新增模块覆盖: 系统层 (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 行代码
426 lines
15 KiB
Python
426 lines
15 KiB
Python
"""
|
|
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",
|
|
] |