feat: 新增 42 个 Android API 模块
新增模块覆盖: 系统层 (14): system, security, print, opengl, renderscript, transition, test, service_notification, service_controls, service_quicksettings, service_wallpaper, service_autofill, service_dreams, service_vr 应用层 (13): app_admin, app_backup, app_job, app_usage, app_role, app_people, appwidget, companion, credentials, mtp, sip, telecom, speech 硬件媒体层 (15): hardware_display, hardware_fingerprint, hardware_usb, hardware_input, media_audiofx, media_browse, media_session, media_tv, media_midi, media_projection, uwb, se, view_autofill, view_textclassifier, view_translation 总计 94 个模块,75,342 行代码
This commit is contained in:
1 parent
8ad62be068
commit
506f9ac725
43 files changed
+16704
-23
No files matched your search
@@ -0,0 +1,426 @@
|
||||
"""
|
||||
Android view.textclassifier 组件 — TextClassifier, TextClassification, TextLinks, TextSelection 等
|
||||
方法签名完全对齐 Android SDK
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# EntityConfig
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class EntityConfig(Stub):
|
||||
"""EntityConfig — 实体配置"""
|
||||
|
||||
class Builder(Stub):
|
||||
"""EntityConfig.Builder — 实体配置构建器"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._include_types: Optional[Set[str]] = None
|
||||
self._exclude_types: Optional[Set[str]] = None
|
||||
self._include_from_textclassifier = True
|
||||
|
||||
def includeTypesFromTextClassifier(self) -> "EntityConfig.Builder":
|
||||
self._include_from_textclassifier = True
|
||||
return self
|
||||
|
||||
def excludeTypes(self, varargs: List[str]) -> "EntityConfig.Builder":
|
||||
self._exclude_types = set(varargs)
|
||||
return self
|
||||
|
||||
def includeTypes(self, varargs: List[str]) -> "EntityConfig.Builder":
|
||||
self._include_types = set(varargs)
|
||||
return self
|
||||
|
||||
def build(self) -> "EntityConfig":
|
||||
config = EntityConfig()
|
||||
config._include_types = self._include_types
|
||||
config._exclude_types = self._exclude_types
|
||||
config._include_from_textclassifier = self._include_from_textclassifier
|
||||
return config
|
||||
|
||||
def getEntityTypes(self) -> Optional[List[str]]:
|
||||
if self._include_types:
|
||||
return list(self._include_types)
|
||||
return None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._include_types: Optional[Set[str]] = None
|
||||
self._exclude_types: Optional[Set[str]] = None
|
||||
self._include_from_textclassifier = True
|
||||
|
||||
def getEntityTypes(self) -> Optional[List[str]]:
|
||||
if self._include_types:
|
||||
return list(self._include_types)
|
||||
return None
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# TextClassifier
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class TextClassifier(Stub):
|
||||
"""TextClassifier — 文本分类器"""
|
||||
|
||||
TYPE_UNKNOWN = "unknown"
|
||||
TYPE_ADDRESS = "address"
|
||||
TYPE_DATE = "date"
|
||||
TYPE_DATE_TIME = "datetime"
|
||||
TYPE_DURATION = "duration"
|
||||
TYPE_EMAIL = "email"
|
||||
TYPE_FLIGHT_NUMBER = "flight"
|
||||
TYPE_IDENTIFIER = "identifier"
|
||||
TYPE_LINK = "link"
|
||||
TYPE_LIST = "list"
|
||||
TYPE_LOCATION = "location"
|
||||
TYPE_MEASUREMENT = "measurement"
|
||||
TYPE_MONEY = "money"
|
||||
TYPE_OTHER = "other"
|
||||
TYPE_PERIODIC = "periodic"
|
||||
TYPE_PHONE = "phone"
|
||||
TYPE_PRODUCT = "product"
|
||||
TYPE_RECIPE = "recipe"
|
||||
TYPE_TRACK_AIRLINE = "track_airline"
|
||||
TYPE_TRACK_FLIGHT = "track_flight"
|
||||
TYPE_TRACK_FOOD = "track_food"
|
||||
TYPE_TRACK_SPORT = "track_sport"
|
||||
TYPE_TRACK_WEATHER = "track_weather"
|
||||
TYPE_URL = "url"
|
||||
TYPE_VEHICLE = "vehicle"
|
||||
|
||||
WIDGET_TYPE_CLIPBOARD = "clipboard"
|
||||
WIDGET_TYPE_CUT_COPY = "cutcopy"
|
||||
WIDGET_TYPE_EDIT_TEXT = "edittext"
|
||||
WIDGET_TYPE_LINKIFY = "linkify"
|
||||
WIDGET_TYPE_NOTIFICATION = "notification"
|
||||
WIDGET_TYPE_OTHER = "other"
|
||||
WIDGET_TYPE_SELECTION = "selection"
|
||||
WIDGET_TYPE_TEXT = "text"
|
||||
WIDGET_TYPE_UNSELECTED_TEXT = "unselected_text"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Request
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class Request(Stub):
|
||||
"""TextClassifier.Request — 分类请求"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._calling_package_name: Optional[str] = None
|
||||
self._text: str = ""
|
||||
self._start_index: int = 0
|
||||
self._end_index: int = 0
|
||||
self._extras: Any = None
|
||||
self._default_locales: Any = None
|
||||
self._dark_launch_allowed = False
|
||||
|
||||
def getCallingPackageName(self) -> Optional[str]:
|
||||
return self._calling_package_name
|
||||
|
||||
def getText(self) -> str:
|
||||
return self._text
|
||||
|
||||
def getStartIndex(self) -> int:
|
||||
return self._start_index
|
||||
|
||||
def getEndIndex(self) -> int:
|
||||
return self._end_index
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
def getDefaultLocales(self) -> Any:
|
||||
return self._default_locales
|
||||
|
||||
def isDarkLaunchAllowed(self) -> bool:
|
||||
return self._dark_launch_allowed
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def classifyText(self, request: Request) -> "TextClassification":
|
||||
text = request.getText()
|
||||
start = request.getStartIndex()
|
||||
end = request.getEndIndex()
|
||||
if end > len(text):
|
||||
end = len(text)
|
||||
selected = text[start:end] if start < end else text
|
||||
|
||||
entity_type = TextClassifier.TYPE_UNKNOWN
|
||||
confidence = 0.0
|
||||
|
||||
# Basic regex-based classification
|
||||
if re.match(r'^https?://', selected):
|
||||
entity_type = TextClassifier.TYPE_URL
|
||||
confidence = 0.95
|
||||
elif re.match(r'^[\w.+-]+@[\w-]+\.[\w.-]+$', selected):
|
||||
entity_type = TextClassifier.TYPE_EMAIL
|
||||
confidence = 0.95
|
||||
elif re.match(r'^\+?[\d\s\-\(\)]{7,15}$', selected):
|
||||
entity_type = TextClassifier.TYPE_PHONE
|
||||
confidence = 0.85
|
||||
elif re.match(r'^\d{1,4}[-/]\d{1,2}[-/]\d{1,4}$', selected):
|
||||
entity_type = TextClassifier.TYPE_DATE
|
||||
confidence = 0.80
|
||||
elif re.match(r'^\d{1,2}:\d{2}(\s?[AP]M)?$', selected, re.IGNORECASE):
|
||||
entity_type = TextClassifier.TYPE_DATE_TIME
|
||||
confidence = 0.80
|
||||
|
||||
tc = TextClassification()
|
||||
tc._text = selected
|
||||
tc._entity_type = entity_type
|
||||
tc._confidence_score = confidence
|
||||
tc._entity_count = 1
|
||||
return tc
|
||||
|
||||
def suggestConversationActions(self, request: Request) -> List["ConversationAction"]:
|
||||
return []
|
||||
|
||||
def detectLanguage(self, text: str) -> "TextClassification":
|
||||
tc = TextClassification()
|
||||
tc._text = text
|
||||
tc._entity_type = TextClassifier.TYPE_UNKNOWN
|
||||
return tc
|
||||
|
||||
def onSelectionEvent(self, event: Any):
|
||||
pass
|
||||
|
||||
def onTextChanged(self, text: Any):
|
||||
pass
|
||||
|
||||
def onTextSelectionAction(self, action: Any):
|
||||
pass
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# TextClassification
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class TextClassification(Stub):
|
||||
"""TextClassification — 文本分类结果"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._text: str = ""
|
||||
self._entity_type: str = TextClassifier.TYPE_UNKNOWN
|
||||
self._confidence_score: float = 0.0
|
||||
self._entity_count: int = 0
|
||||
self._icon: Any = None
|
||||
self._label: str = ""
|
||||
self._actions: List[Any] = []
|
||||
self._extras: Any = None
|
||||
self._id: Optional[str] = None
|
||||
|
||||
def getText(self) -> str:
|
||||
return self._text
|
||||
|
||||
def getEntityCount(self) -> int:
|
||||
return self._entity_count
|
||||
|
||||
def getEntity(self, index: int) -> Optional[str]:
|
||||
if index == 0:
|
||||
return self._entity_type
|
||||
return None
|
||||
|
||||
def getEntityType(self) -> str:
|
||||
return self._entity_type
|
||||
|
||||
def getConfidenceScore(self, entityType: str) -> float:
|
||||
if entityType == self._entity_type:
|
||||
return self._confidence_score
|
||||
return 0.0
|
||||
|
||||
def getIcon(self) -> Any:
|
||||
return self._icon
|
||||
|
||||
def getLabel(self) -> str:
|
||||
return self._label
|
||||
|
||||
def getActions(self) -> List[Any]:
|
||||
return self._actions
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
def getId(self) -> Optional[str]:
|
||||
return self._id
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"TextClassification(type={self._entity_type}," \
|
||||
f" confidence={self._confidence_score:.2f})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# TextLinks
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class TextLinks(Stub):
|
||||
"""TextLinks — 文本链接"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._links: List[Any] = []
|
||||
self._extras: Any = None
|
||||
|
||||
def getLinks(self) -> List[Any]:
|
||||
return self._links
|
||||
|
||||
def getEntityCount(self) -> int:
|
||||
return len(self._links)
|
||||
|
||||
def getEntity(self, index: int) -> Optional[str]:
|
||||
if 0 <= index < len(self._links):
|
||||
return self._links[index]
|
||||
return None
|
||||
|
||||
def getEntityType(self) -> str:
|
||||
return TextClassifier.TYPE_LINK
|
||||
|
||||
def getConfidenceScore(self, entityType: str) -> float:
|
||||
return 0.0
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# TextSelection
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class TextSelection(Stub):
|
||||
"""TextSelection — 文本选择结果"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._start_index: int = 0
|
||||
self._end_index: int = 0
|
||||
self._entity_type: str = TextClassifier.TYPE_UNKNOWN
|
||||
self._text: str = ""
|
||||
self._entity_count: int = 0
|
||||
self._confidence_score: float = 0.0
|
||||
self._extras: Any = None
|
||||
self._id: Optional[str] = None
|
||||
|
||||
def getSelectionStartIndex(self) -> int:
|
||||
return self._start_index
|
||||
|
||||
def getSelectionEndIndex(self) -> int:
|
||||
return self._end_index
|
||||
|
||||
def getEntityType(self) -> str:
|
||||
return self._entity_type
|
||||
|
||||
def getText(self) -> str:
|
||||
return self._text
|
||||
|
||||
def getEntityCount(self) -> int:
|
||||
return self._entity_count
|
||||
|
||||
def getEntity(self, index: int) -> Optional[str]:
|
||||
if index == 0:
|
||||
return self._entity_type
|
||||
return None
|
||||
|
||||
def getConfidenceScore(self, entityType: str) -> float:
|
||||
if entityType == self._entity_type:
|
||||
return self._confidence_score
|
||||
return 0.0
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
def getId(self) -> Optional[str]:
|
||||
return self._id
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# ConversationAction
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class ConversationAction(Stub):
|
||||
"""ConversationAction — 对话操作"""
|
||||
|
||||
TYPE_CALL = "call"
|
||||
TYPE_CREATE_REMINDER = "create_reminder"
|
||||
TYPE_OPEN_URL = "open_url"
|
||||
TYPE_SEND_EMAIL = "send_email"
|
||||
TYPE_SEND_SMS = "send_sms"
|
||||
TYPE_SHARE_LOCATION = "share_location"
|
||||
TYPE_TEXT_REPLY = "text_reply"
|
||||
TYPE_VIEW_CALENDAR = "view_calendar"
|
||||
TYPE_VIEW_MAP = "view_map"
|
||||
|
||||
def __init__(self, text: str = "", confidenceScore: float = 0.0,
|
||||
action: str = "", extras: Any = None,
|
||||
icon: Any = None, label: str = ""):
|
||||
super().__init__()
|
||||
self._text = text
|
||||
self._confidence_score = confidenceScore
|
||||
self._action = action
|
||||
self._extras = extras
|
||||
self._icon = icon
|
||||
self._label = label
|
||||
|
||||
def getText(self) -> str:
|
||||
return self._text
|
||||
|
||||
def getConfidenceScore(self) -> float:
|
||||
return self._confidence_score
|
||||
|
||||
def getAction(self) -> str:
|
||||
return self._action
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
def getIcon(self) -> Any:
|
||||
return self._icon
|
||||
|
||||
def getLabel(self) -> str:
|
||||
return self._label
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# TextClassificationContext
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class TextClassificationContext(Stub):
|
||||
"""TextClassificationContext — 文本分类上下文"""
|
||||
|
||||
def __init__(self, packageName: str = "", widgetType: str = "",
|
||||
widgetVersion: str = ""):
|
||||
super().__init__()
|
||||
self._package_name = packageName
|
||||
self._widget_type = widgetType
|
||||
self._widget_version = widgetVersion
|
||||
|
||||
def getPackageName(self) -> str:
|
||||
return self._package_name
|
||||
|
||||
def getWidgetType(self) -> str:
|
||||
return self._widget_type
|
||||
|
||||
def getWidgetVersion(self) -> str:
|
||||
return self._widget_version
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# __all__
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
__all__ = [
|
||||
"TextClassifier",
|
||||
"TextClassification",
|
||||
"TextLinks",
|
||||
"TextSelection",
|
||||
"ConversationAction",
|
||||
"TextClassificationContext",
|
||||
"EntityConfig",
|
||||
]
|
||||
Reference in new issue
Block a user