- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
1554 lines
48 KiB
Python
1554 lines
48 KiB
Python
"""
|
|
Android WebKit 扩展组件 — WebView, WebSettings, WebViewClient, WebChromeClient 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import json
|
|
import threading
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from ..java.lang import RuntimeException
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebView 常量
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
LOAD_DEFAULT = 0
|
|
LOAD_CACHE_ONLY = 1
|
|
LOAD_CACHE_ELSE_NETWORK = 2
|
|
LOAD_NO_CACHE = 3
|
|
LOAD_NORMAL = 0
|
|
|
|
ERROR_UNKNOWN = -1
|
|
ERROR_HOST_LOOKUP = -2
|
|
ERROR_UNSUPPORTED_AUTH_SCHEME = -3
|
|
ERROR_AUTHENTICATION = -4
|
|
ERROR_PROXY_AUTHENTICATION = -5
|
|
ERROR_CONNECT = -6
|
|
ERROR_IO = -7
|
|
ERROR_TIMEOUT = -8
|
|
ERROR_REDIRECT_LOOP = -9
|
|
ERROR_UNSUPPORTED_SCHEME = -10
|
|
ERROR_FAILED_SSL_HANDSHAKE = -11
|
|
ERROR_BAD_URL = -12
|
|
ERROR_FILE = -13
|
|
ERROR_FILE_NOT_FOUND = -14
|
|
ERROR_TOO_MANY_REQUESTS = -15
|
|
|
|
NAVIGATION_TYPE_LINK_CLICKED = 0
|
|
NAVIGATION_TYPE_FORM_SUBMITTED = 1
|
|
NAVIGATION_TYPE_BACK_FORWARD = 2
|
|
NAVIGATION_TYPE_RELOAD = 3
|
|
NAVIGATION_TYPE_FORM_RESUBMITTED = 4
|
|
NAVIGATION_TYPE_OTHER = -1
|
|
|
|
OVER_SCROLL_NEVER = 2
|
|
OVER_SCROLL_ALWAYS = 0
|
|
OVER_SCROLL_IF_CONTENT_SCROLLS = 1
|
|
|
|
RENDERER_PRIORITY_WAIVED = 0
|
|
RENDERER_PRIORITY_BOUND = 1
|
|
RENDERER_PRIORITY_IMPORTANT = 2
|
|
|
|
SCHEME_HTTP = "http"
|
|
SCHEME_HTTPS = "https"
|
|
SCHEME_FILE = "file"
|
|
SCHEME_ABOUT = "about"
|
|
SCHEME_DATA = "data"
|
|
SCHEME_JAVASCRIPT = "javascript"
|
|
|
|
WEB_CHROME_CLIENT_GET_DEFAULT_VIDEO_POSTER = 1
|
|
WEB_CHROME_CLIENT_GET_VISITED_HISTORY = 2
|
|
|
|
WEB_RESOURCE_ERROR_STYLE_BOX = 0
|
|
WEB_RESOURCE_ERROR_STYLE_GENERIC = 1
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebResourceRequest / WebResourceResponse / WebResourceError
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebResourceRequest(Stub):
|
|
"""WebResourceRequest — 资源请求"""
|
|
|
|
def __init__(self, url: str = "", is_for_main_frame: bool = False,
|
|
is_redirect: bool = False, method: str = "GET",
|
|
request_headers: Optional[Dict[str, str]] = None,
|
|
has_user_gesture: bool = False,
|
|
is_main_frame: bool = False):
|
|
super().__init__()
|
|
self._url = url
|
|
self._is_for_main_frame = is_for_main_frame
|
|
self._is_redirect = is_redirect
|
|
self._method = method
|
|
self._request_headers = request_headers or {}
|
|
self._has_user_gesture = has_user_gesture
|
|
self._is_main_frame = is_main_frame
|
|
|
|
def getUrl(self) -> str:
|
|
return self._url
|
|
|
|
def isForMainFrame(self) -> bool:
|
|
return self._is_for_main_frame
|
|
|
|
def isRedirect(self) -> bool:
|
|
return self._is_redirect
|
|
|
|
def getMethod(self) -> str:
|
|
return self._method
|
|
|
|
def getRequestHeaders(self) -> Dict[str, str]:
|
|
return dict(self._request_headers)
|
|
|
|
def hasUserGesture(self) -> bool:
|
|
return self._has_user_gesture
|
|
|
|
def isMainFrame(self) -> bool:
|
|
return self._is_main_frame
|
|
|
|
def toString(self) -> str:
|
|
return f"WebResourceRequest(url={self._url}, method={self._method})"
|
|
|
|
|
|
class WebResourceResponse(Stub):
|
|
"""WebResourceResponse — 资源响应"""
|
|
|
|
def __init__(self, mime_type: str = "", encoding: str = "",
|
|
data: Any = None, status_code: int = 200,
|
|
reason_phrase: str = "OK",
|
|
response_headers: Optional[Dict[str, str]] = None):
|
|
super().__init__()
|
|
self._mime_type = mime_type
|
|
self._encoding = encoding
|
|
self._data = data
|
|
self._status_code = status_code
|
|
self._reason_phrase = reason_phrase
|
|
self._response_headers = response_headers or {}
|
|
|
|
def getMimeType(self) -> str:
|
|
return self._mime_type
|
|
|
|
def getEncoding(self) -> str:
|
|
return self._encoding
|
|
|
|
def getData(self) -> Any:
|
|
return self._data
|
|
|
|
def getStatusCode(self) -> int:
|
|
return self._status_code
|
|
|
|
def getReasonPhrase(self) -> str:
|
|
return self._reason_phrase
|
|
|
|
def getResponseHeaders(self) -> Dict[str, str]:
|
|
return dict(self._response_headers)
|
|
|
|
def setMimeType(self, mime_type: str) -> None:
|
|
self._mime_type = mime_type
|
|
|
|
def setEncoding(self, encoding: str) -> None:
|
|
self._encoding = encoding
|
|
|
|
def setData(self, data: Any) -> None:
|
|
self._data = data
|
|
|
|
def setStatusCodeAndReasonPhrase(self, status_code: int, reason: str) -> None:
|
|
self._status_code = status_code
|
|
self._reason_phrase = reason
|
|
|
|
def setResponseHeaders(self, headers: Dict[str, str]) -> None:
|
|
self._response_headers = dict(headers)
|
|
|
|
def toString(self) -> str:
|
|
return (f"WebResourceResponse(status={self._status_code}, "
|
|
f"mime={self._mime_type})")
|
|
|
|
|
|
class WebResourceError(Stub):
|
|
"""WebResourceError — 资源错误"""
|
|
|
|
ERROR_UNKNOWN = ERROR_UNKNOWN
|
|
ERROR_HOST_LOOKUP = ERROR_HOST_LOOKUP
|
|
ERROR_UNSUPPORTED_AUTH_SCHEME = ERROR_UNSUPPORTED_AUTH_SCHEME
|
|
ERROR_AUTHENTICATION = ERROR_AUTHENTICATION
|
|
ERROR_PROXY_AUTHENTICATION = ERROR_PROXY_AUTHENTICATION
|
|
ERROR_CONNECT = ERROR_CONNECT
|
|
ERROR_IO = ERROR_IO
|
|
ERROR_TIMEOUT = ERROR_TIMEOUT
|
|
ERROR_REDIRECT_LOOP = ERROR_REDIRECT_LOOP
|
|
ERROR_UNSUPPORTED_SCHEME = ERROR_UNSUPPORTED_SCHEME
|
|
ERROR_FAILED_SSL_HANDSHAKE = ERROR_FAILED_SSL_HANDSHAKE
|
|
ERROR_BAD_URL = ERROR_BAD_URL
|
|
ERROR_FILE = ERROR_FILE
|
|
ERROR_FILE_NOT_FOUND = ERROR_FILE_NOT_FOUND
|
|
ERROR_TOO_MANY_REQUESTS = ERROR_TOO_MANY_REQUESTS
|
|
|
|
def __init__(self, error_code: int = ERROR_UNKNOWN, description: str = ""):
|
|
super().__init__()
|
|
self._error_code = error_code
|
|
self._description = description
|
|
|
|
def getErrorCode(self) -> int:
|
|
return self._error_code
|
|
|
|
def getDescription(self) -> str:
|
|
return self._description
|
|
|
|
def toString(self) -> str:
|
|
return f"WebResourceError(code={self._error_code}, desc={self._description})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebMessage / WebMessagePort / WebMessageListener
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebMessage(Stub):
|
|
"""WebMessage — Web消息"""
|
|
|
|
def __init__(self, data: str = "", ports: Optional[List["WebMessagePort"]] = None):
|
|
super().__init__()
|
|
self._data = data
|
|
self._ports = list(ports) if ports else []
|
|
|
|
def getData(self) -> str:
|
|
return self._data
|
|
|
|
def getPorts(self) -> List["WebMessagePort"]:
|
|
return list(self._ports)
|
|
|
|
def toString(self) -> str:
|
|
return f"WebMessage(data={self._data[:50]})"
|
|
|
|
|
|
class WebMessagePort(Stub):
|
|
"""WebMessagePort — Web消息端口"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._callback: Optional[Callable] = None
|
|
self._closed = False
|
|
|
|
def postMessage(self, message: WebMessage) -> None:
|
|
if self._closed:
|
|
raise RuntimeException("WebMessagePort 已关闭")
|
|
if self._callback:
|
|
self._callback(message)
|
|
|
|
def close(self) -> None:
|
|
self._closed = True
|
|
self._callback = None
|
|
|
|
def setWebMessageCallback(self, callback: Optional[Callable]) -> None:
|
|
self._callback = callback
|
|
|
|
def isClosed(self) -> bool:
|
|
return self._closed
|
|
|
|
def toString(self) -> str:
|
|
return f"WebMessagePort(closed={self._closed})"
|
|
|
|
|
|
class WebMessageListener(Stub):
|
|
"""WebMessageListener — Web消息监听器"""
|
|
|
|
def onPostMessage(self, view: Any, message: WebMessage,
|
|
source_origin: str, is_main_frame: bool,
|
|
js_ports: List[WebMessagePort]) -> None:
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebStorage
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebStorage(Stub):
|
|
"""WebStorage — Web存储"""
|
|
|
|
class UsageInfo(Stub):
|
|
"""WebStorage.UsageInfo — 使用信息"""
|
|
def __init__(self, origin: str = "", usage: int = 0, quota: int = 0):
|
|
super().__init__()
|
|
self._origin = origin
|
|
self._usage = usage
|
|
self._quota = quota
|
|
|
|
def getOrigin(self) -> str:
|
|
return self._origin
|
|
|
|
def getUsage(self) -> int:
|
|
return self._usage
|
|
|
|
def getQuota(self) -> int:
|
|
return self._quota
|
|
|
|
def toString(self) -> str:
|
|
return f"UsageInfo(origin={self._origin}, usage={self._usage})"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._storage: Dict[str, int] = {}
|
|
self._lock = threading.Lock()
|
|
|
|
def getOrigins(self, callback: Callable) -> None:
|
|
with self._lock:
|
|
callback(list(self._storage.keys()))
|
|
|
|
def getUsageForOrigin(self, origin: str, callback: Callable) -> None:
|
|
with self._lock:
|
|
callback(self._storage.get(origin, 0))
|
|
|
|
def getQuotaForOrigin(self, origin: str, callback: Callable) -> None:
|
|
with self._lock:
|
|
callback(self._storage.get(origin, 5 * 1024 * 1024))
|
|
|
|
def setQuotaForOrigin(self, origin: str, quota: int) -> None:
|
|
with self._lock:
|
|
self._storage[origin] = quota
|
|
|
|
def deleteOrigin(self, origin: str) -> None:
|
|
with self._lock:
|
|
self._storage.pop(origin, None)
|
|
|
|
def deleteAllData(self) -> None:
|
|
with self._lock:
|
|
self._storage.clear()
|
|
|
|
def toString(self) -> str:
|
|
return f"WebStorage(origins={len(self._storage)})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebView 扩展
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebView(Stub):
|
|
"""WebView — Web视图扩展"""
|
|
|
|
RENDERER_PRIORITY_WAIVED = RENDERER_PRIORITY_WAIVED
|
|
RENDERER_PRIORITY_BOUND = RENDERER_PRIORITY_BOUND
|
|
RENDERER_PRIORITY_IMPORTANT = RENDERER_PRIORITY_IMPORTANT
|
|
|
|
SCHEME_HTTP = SCHEME_HTTP
|
|
SCHEME_HTTPS = SCHEME_HTTPS
|
|
SCHEME_FILE = SCHEME_FILE
|
|
SCHEME_ABOUT = SCHEME_ABOUT
|
|
SCHEME_DATA = SCHEME_DATA
|
|
SCHEME_JAVASCRIPT = SCHEME_JAVASCRIPT
|
|
|
|
LOAD_DEFAULT = LOAD_DEFAULT
|
|
LOAD_CACHE_ONLY = LOAD_CACHE_ONLY
|
|
LOAD_CACHE_ELSE_NETWORK = LOAD_CACHE_ELSE_NETWORK
|
|
LOAD_NO_CACHE = LOAD_NO_CACHE
|
|
LOAD_NORMAL = LOAD_NORMAL
|
|
|
|
OVER_SCROLL_NEVER = OVER_SCROLL_NEVER
|
|
OVER_SCROLL_ALWAYS = OVER_SCROLL_ALWAYS
|
|
OVER_SCROLL_IF_CONTENT_SCROLLS = OVER_SCROLL_IF_CONTENT_SCROLLS
|
|
|
|
class WebViewTransport(Stub):
|
|
"""WebView.WebViewTransport — WebView传输"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._webview: Optional[WebView] = None
|
|
|
|
def setWebView(self, webview: "WebView") -> None:
|
|
self._webview = webview
|
|
|
|
def getWebView(self) -> Optional["WebView"]:
|
|
return self._webview
|
|
|
|
def __init__(self, context: Any = None):
|
|
super().__init__()
|
|
self._url: Optional[str] = None
|
|
self._content: Optional[str] = None
|
|
self._settings: Optional["WebSettings"] = None
|
|
self._client: Optional["WebViewClient"] = None
|
|
self._chrome_client: Optional["WebChromeClient"] = None
|
|
self._web_message_listeners: Dict[str, WebMessageListener] = {}
|
|
self._renderer_priority: int = self.RENDERER_PRIORITY_BOUND
|
|
self._renderer_priority_overridden = False
|
|
self._lock = threading.Lock()
|
|
|
|
def loadUrl(self, url: str, additional_headers: Optional[Dict[str, str]] = None) -> None:
|
|
self._url = url
|
|
self._content = None
|
|
if self._client:
|
|
self._client.onPageStarted(self, url, None)
|
|
|
|
def loadData(self, data: str, mime_type: str = "text/html",
|
|
encoding: str = "utf-8") -> None:
|
|
self._content = data
|
|
self._url = "data:text/html;charset=utf-8," + data[:100]
|
|
|
|
def loadDataWithBaseURL(self, base_url: str, data: str,
|
|
mime_type: str, encoding: str,
|
|
history_url: Optional[str]) -> None:
|
|
self._content = data
|
|
self._url = base_url
|
|
|
|
def postUrl(self, url: str, post_data: bytes) -> None:
|
|
self._url = url
|
|
|
|
def getUrl(self) -> Optional[str]:
|
|
return self._url
|
|
|
|
def getTitle(self) -> str:
|
|
return ""
|
|
|
|
def getSettings(self) -> "WebSettings":
|
|
if self._settings is None:
|
|
self._settings = WebSettings(self)
|
|
return self._settings
|
|
|
|
def setWebViewClient(self, client: "WebViewClient") -> None:
|
|
self._client = client
|
|
|
|
def getWebViewClient(self) -> Optional["WebViewClient"]:
|
|
return self._client
|
|
|
|
def setWebChromeClient(self, client: "WebChromeClient") -> None:
|
|
self._chrome_client = client
|
|
|
|
def getWebChromeClient(self) -> Optional["WebChromeClient"]:
|
|
return self._chrome_client
|
|
|
|
def setWebMessageListener(self, js_object_name: str,
|
|
listener: WebMessageListener) -> None:
|
|
with self._lock:
|
|
self._web_message_listeners[js_object_name] = listener
|
|
|
|
def addJavascriptInterface(self, obj: Any, name: str) -> None:
|
|
pass
|
|
|
|
def removeJavascriptInterface(self, name: str) -> None:
|
|
pass
|
|
|
|
def evaluateJavascript(self, script: str, callback: Optional[Callable] = None) -> None:
|
|
pass
|
|
|
|
def evaluateJavascriptForTests(self, script: str, callback: Optional[Callable] = None) -> None:
|
|
pass
|
|
|
|
def canGoBack(self) -> bool:
|
|
return False
|
|
|
|
def canGoForward(self) -> bool:
|
|
return False
|
|
|
|
def goBack(self) -> None:
|
|
pass
|
|
|
|
def goForward(self) -> None:
|
|
pass
|
|
|
|
def reload(self) -> None:
|
|
if self._url:
|
|
self.loadUrl(self._url)
|
|
|
|
def stopLoading(self) -> None:
|
|
pass
|
|
|
|
def clearHistory(self) -> None:
|
|
pass
|
|
|
|
def clearCache(self, include_disk: bool) -> None:
|
|
pass
|
|
|
|
def clearFormData(self) -> None:
|
|
pass
|
|
|
|
def destroy(self) -> None:
|
|
pass
|
|
|
|
def onPause(self) -> None:
|
|
pass
|
|
|
|
def onResume(self) -> None:
|
|
pass
|
|
|
|
def isPaused(self) -> bool:
|
|
return False
|
|
|
|
def pageUp(self, top: bool) -> bool:
|
|
return True
|
|
|
|
def pageDown(self, bottom: bool) -> bool:
|
|
return True
|
|
|
|
def setInitialScale(self, scale: int) -> None:
|
|
pass
|
|
|
|
def getScale(self) -> float:
|
|
return 1.0
|
|
|
|
def setRendererPriorityPolicy(self, priority: int, overridden: bool) -> None:
|
|
self._renderer_priority = priority
|
|
self._renderer_priority_overridden = overridden
|
|
|
|
def getRendererRequestedPriority(self) -> int:
|
|
return self._renderer_priority
|
|
|
|
def getRendererPriorityWaivedWhenNotVisible(self) -> bool:
|
|
return self._renderer_priority_overridden
|
|
|
|
def setNetworkAvailable(self, available: bool) -> None:
|
|
pass
|
|
|
|
def setLayoutParams(self, params: Any) -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"WebView(url={self._url})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebSettings 扩展
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebSettings(Stub):
|
|
"""WebSettings — Web设置扩展"""
|
|
|
|
LOAD_DEFAULT = LOAD_DEFAULT
|
|
LOAD_CACHE_ONLY = LOAD_CACHE_ONLY
|
|
LOAD_CACHE_ELSE_NETWORK = LOAD_CACHE_ELSE_NETWORK
|
|
LOAD_NO_CACHE = LOAD_NO_CACHE
|
|
LOAD_NORMAL = LOAD_NORMAL
|
|
|
|
MIXED_CONTENT_ALWAYS_ALLOW = 0
|
|
MIXED_CONTENT_NEVER_ALLOW = 1
|
|
MIXED_CONTENT_COMPATIBILITY_MODE = 2
|
|
|
|
LAYOUT_ALGORITHM_NORMAL = 0
|
|
LAYOUT_ALGORITHM_SINGLE_COLUMN = 1
|
|
LAYOUT_ALGORITHM_NARROW_COLUMNS = 2
|
|
LAYOUT_ALGORITHM_TEXT_AUTOSIZING = 3
|
|
|
|
PLUGIN_STATE_ON = 0
|
|
PLUGIN_STATE_ON_DEMAND = 1
|
|
PLUGIN_STATE_OFF = 2
|
|
|
|
RENDER_GOOGLE_SUIT = 0
|
|
RENDER_PRIORITY_NORMAL = 0
|
|
RENDER_PRIORITY_HIGH = 1
|
|
RENDER_PRIORITY_LOW = 2
|
|
|
|
TEXT_AUTOSIZING_TEXT_SIZE_INCREMENT = 0
|
|
|
|
USER_AGENT_DESKTOP = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
|
USER_AGENT_MOBILE = "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
|
|
|
|
def __init__(self, webview: Optional[WebView] = None):
|
|
super().__init__()
|
|
self._webview = webview
|
|
self._java_script_enabled = False
|
|
self._java_script_can_open_windows = False
|
|
self._allow_file_access = True
|
|
self._allow_file_access_from_file_urls = True
|
|
self._allow_universal_access_from_file_urls = False
|
|
self._built_in_zoom_controls = True
|
|
self._display_zoom_controls = True
|
|
self._support_zoom = True
|
|
self._load_with_overview_mode = False
|
|
self._use_wide_viewport = True
|
|
self._dom_storage_enabled = True
|
|
self._database_enabled = True
|
|
self._app_cache_enabled = True
|
|
self._cache_mode = LOAD_DEFAULT
|
|
self._user_agent_string: Optional[str] = None
|
|
self._default_font_size: int = 16
|
|
self._default_fixed_font_size: int = 13
|
|
self._minimum_font_size: int = 8
|
|
self._minimum_logical_font_size: int = 8
|
|
self._text_zoom: int = 100
|
|
self._standard_font_family: str = "sans-serif"
|
|
self._serif_font_family: str = "serif"
|
|
self._sans_serif_font_family: str = "sans-serif"
|
|
self._fixed_font_family: str = "monospace"
|
|
self._cursive_font_family: str = "cursive"
|
|
self._fantasy_font_family: str = "fantasy"
|
|
self._default_text_encoding: str = "UTF-8"
|
|
self._layout_algorithm = self.LAYOUT_ALGORITHM_NORMAL
|
|
self._block_network_image = False
|
|
self._block_network_loads = False
|
|
self._accept_cookies = True
|
|
self._mixed_content_mode = self.MIXED_CONTENT_NEVER_ALLOW
|
|
self._offscreen_prefetch_rss = False
|
|
self._safe_browsing_enabled = True
|
|
self._save_form_data = True
|
|
self._save_password = False
|
|
self._need_initial_focus = True
|
|
self._support_multiple_windows = False
|
|
self._allow_content_access = True
|
|
self._loads_images_automatically = True
|
|
self._javascript_enabled = False
|
|
self._media_playback_requires_user_gesture = True
|
|
|
|
def setJavaScriptEnabled(self, enabled: bool) -> None:
|
|
self._javascript_enabled = enabled
|
|
|
|
def getJavaScriptEnabled(self) -> bool:
|
|
return self._javascript_enabled
|
|
|
|
def setJavaScriptCanOpenWindowsAutomatically(self, can: bool) -> None:
|
|
self._java_script_can_open_windows = can
|
|
|
|
def getJavaScriptCanOpenWindowsAutomatically(self) -> bool:
|
|
return self._java_script_can_open_windows
|
|
|
|
def setAllowFileAccess(self, allow: bool) -> None:
|
|
self._allow_file_access = allow
|
|
|
|
def getAllowFileAccess(self) -> bool:
|
|
return self._allow_file_access
|
|
|
|
def setAllowFileAccessFromFileURLs(self, allow: bool) -> None:
|
|
self._allow_file_access_from_file_urls = allow
|
|
|
|
def getAllowFileAccessFromFileURLs(self) -> bool:
|
|
return self._allow_file_access_from_file_urls
|
|
|
|
def setAllowUniversalAccessFromFileURLs(self, allow: bool) -> None:
|
|
self._allow_universal_access_from_file_urls = allow
|
|
|
|
def getAllowUniversalAccessFromFileURLs(self) -> bool:
|
|
return self._allow_universal_access_from_file_urls
|
|
|
|
def setBuiltInZoomControls(self, enabled: bool) -> None:
|
|
self._built_in_zoom_controls = enabled
|
|
|
|
def getBuiltInZoomControls(self) -> bool:
|
|
return self._built_in_zoom_controls
|
|
|
|
def setDisplayZoomControls(self, enabled: bool) -> None:
|
|
self._display_zoom_controls = enabled
|
|
|
|
def getDisplayZoomControls(self) -> bool:
|
|
return self._display_zoom_controls
|
|
|
|
def setSupportZoom(self, support: bool) -> None:
|
|
self._support_zoom = support
|
|
|
|
def supportZoom(self) -> bool:
|
|
return self._support_zoom
|
|
|
|
def setLoadWithOverviewMode(self, overview: bool) -> None:
|
|
self._load_with_overview_mode = overview
|
|
|
|
def getLoadWithOverviewMode(self) -> bool:
|
|
return self._load_with_overview_mode
|
|
|
|
def setUseWideViewPort(self, use: bool) -> None:
|
|
self._use_wide_viewport = use
|
|
|
|
def getUseWideViewPort(self) -> bool:
|
|
return self._use_wide_viewport
|
|
|
|
def setDomStorageEnabled(self, enabled: bool) -> None:
|
|
self._dom_storage_enabled = enabled
|
|
|
|
def getDomStorageEnabled(self) -> bool:
|
|
return self._dom_storage_enabled
|
|
|
|
def setDatabaseEnabled(self, enabled: bool) -> None:
|
|
self._database_enabled = enabled
|
|
|
|
def getDatabaseEnabled(self) -> bool:
|
|
return self._database_enabled
|
|
|
|
def setAppCacheEnabled(self, enabled: bool) -> None:
|
|
self._app_cache_enabled = enabled
|
|
|
|
def getAppCacheEnabled(self) -> bool:
|
|
return self._app_cache_enabled
|
|
|
|
def setCacheMode(self, mode: int) -> None:
|
|
self._cache_mode = mode
|
|
|
|
def getCacheMode(self) -> int:
|
|
return self._cache_mode
|
|
|
|
def setUserAgentString(self, ua: Optional[str]) -> None:
|
|
self._user_agent_string = ua
|
|
|
|
def getUserAgentString(self) -> str:
|
|
return self._user_agent_string or self.USER_AGENT_MOBILE
|
|
|
|
def setDefaultFontSize(self, size: int) -> None:
|
|
self._default_font_size = max(1, size)
|
|
|
|
def getDefaultFontSize(self) -> int:
|
|
return self._default_font_size
|
|
|
|
def setDefaultFixedFontSize(self, size: int) -> None:
|
|
self._default_fixed_font_size = max(1, size)
|
|
|
|
def getDefaultFixedFontSize(self) -> int:
|
|
return self._default_fixed_font_size
|
|
|
|
def setMinimumFontSize(self, size: int) -> None:
|
|
self._minimum_font_size = max(1, size)
|
|
|
|
def getMinimumFontSize(self) -> int:
|
|
return self._minimum_font_size
|
|
|
|
def setTextZoom(self, text_zoom: int) -> None:
|
|
self._text_zoom = max(50, min(200, text_zoom))
|
|
|
|
def getTextZoom(self) -> int:
|
|
return self._text_zoom
|
|
|
|
def setStandardFontFamily(self, font: str) -> None:
|
|
self._standard_font_family = font
|
|
|
|
def getStandardFontFamily(self) -> str:
|
|
return self._standard_font_family
|
|
|
|
def setSerifFontFamily(self, font: str) -> None:
|
|
self._serif_font_family = font
|
|
|
|
def getSerifFontFamily(self) -> str:
|
|
return self._serif_font_family
|
|
|
|
def setSansSerifFontFamily(self, font: str) -> None:
|
|
self._sans_serif_font_family = font
|
|
|
|
def getSansSerifFontFamily(self) -> str:
|
|
return self._sans_serif_font_family
|
|
|
|
def setFixedFontFamily(self, font: str) -> None:
|
|
self._fixed_font_family = font
|
|
|
|
def getFixedFontFamily(self) -> str:
|
|
return self._fixed_font_family
|
|
|
|
def setCursiveFontFamily(self, font: str) -> None:
|
|
self._cursive_font_family = font
|
|
|
|
def getCursiveFontFamily(self) -> str:
|
|
return self._cursive_font_family
|
|
|
|
def setFantasyFontFamily(self, font: str) -> None:
|
|
self._fantasy_font_family = font
|
|
|
|
def getFantasyFontFamily(self) -> str:
|
|
return self._fantasy_font_family
|
|
|
|
def setDefaultTextEncodingName(self, encoding: str) -> None:
|
|
self._default_text_encoding = encoding
|
|
|
|
def getDefaultTextEncodingName(self) -> str:
|
|
return self._default_text_encoding
|
|
|
|
def setLayoutAlgorithm(self, algorithm: int) -> None:
|
|
self._layout_algorithm = algorithm
|
|
|
|
def getLayoutAlgorithm(self) -> int:
|
|
return self._layout_algorithm
|
|
|
|
def setBlockNetworkImage(self, block: bool) -> None:
|
|
self._block_network_image = block
|
|
|
|
def getBlockNetworkImage(self) -> bool:
|
|
return self._block_network_image
|
|
|
|
def setBlockNetworkLoads(self, block: bool) -> None:
|
|
self._block_network_loads = block
|
|
|
|
def getBlockNetworkLoads(self) -> bool:
|
|
return self._block_network_loads
|
|
|
|
def setMixedContentMode(self, mode: int) -> None:
|
|
self._mixed_content_mode = mode
|
|
|
|
def getMixedContentMode(self) -> int:
|
|
return self._mixed_content_mode
|
|
|
|
def setLoadsImagesAutomatically(self, enabled: bool) -> None:
|
|
self._loads_images_automatically = enabled
|
|
|
|
def getLoadsImagesAutomatically(self) -> bool:
|
|
return self._loads_images_automatically
|
|
|
|
def setMediaPlaybackRequiresUserGesture(self, requires: bool) -> None:
|
|
self._media_playback_requires_user_gesture = requires
|
|
|
|
def getMediaPlaybackRequiresUserGesture(self) -> bool:
|
|
return self._media_playback_requires_user_gesture
|
|
|
|
def setSupportMultipleWindows(self, support: bool) -> None:
|
|
self._support_multiple_windows = support
|
|
|
|
def supportMultipleWindows(self) -> bool:
|
|
return self._support_multiple_windows
|
|
|
|
def setSaveFormData(self, save: bool) -> None:
|
|
self._save_form_data = save
|
|
|
|
def getSaveFormData(self) -> bool:
|
|
return self._save_form_data
|
|
|
|
def setSavePassword(self, save: bool) -> None:
|
|
self._save_password = save
|
|
|
|
def getSavePassword(self) -> bool:
|
|
return self._save_password
|
|
|
|
def setNeedInitialFocus(self, need: bool) -> None:
|
|
self._need_initial_focus = need
|
|
|
|
def getNeedInitialFocus(self) -> bool:
|
|
return self._need_initial_focus
|
|
|
|
def setSafeBrowsingEnabled(self, enabled: bool) -> None:
|
|
self._safe_browsing_enabled = enabled
|
|
|
|
def getSafeBrowsingEnabled(self) -> bool:
|
|
return self._safe_browsing_enabled
|
|
|
|
def toString(self) -> str:
|
|
return (f"WebSettings(js={self._javascript_enabled}, "
|
|
f"zoom={self._support_zoom})")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebViewClient 扩展
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebViewClient(Stub):
|
|
"""WebViewClient — Web视图客户端扩展"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def shouldOverrideUrlLoading(self, view: WebView, request: WebResourceRequest) -> bool:
|
|
return False
|
|
|
|
def shouldOverrideKeyEvent(self, view: WebView, event: Any) -> bool:
|
|
return False
|
|
|
|
def onPageStarted(self, view: WebView, url: str, favicon: Any) -> None:
|
|
pass
|
|
|
|
def onPageFinished(self, view: WebView, url: str) -> None:
|
|
pass
|
|
|
|
def onLoadResource(self, view: WebView, url: str) -> None:
|
|
pass
|
|
|
|
def onPageCommitVisible(self, view: WebView, url: str) -> None:
|
|
pass
|
|
|
|
def shouldInterceptRequest(self, view: WebView, request: WebResourceRequest) -> Optional[WebResourceResponse]:
|
|
return None
|
|
|
|
def onReceivedError(self, view: WebView, request: WebResourceRequest,
|
|
error: WebResourceError) -> None:
|
|
pass
|
|
|
|
def onReceivedHttpError(self, view: WebView, request: WebResourceRequest,
|
|
error_response: WebResourceResponse) -> None:
|
|
pass
|
|
|
|
def onReceivedHttpAuthRequest(self, view: WebView, handler: Any,
|
|
host: str, realm: str) -> None:
|
|
pass
|
|
|
|
def onReceivedLoginRequest(self, view: WebView, realm: str,
|
|
account: str, args: str) -> None:
|
|
pass
|
|
|
|
def onReceivedSslError(self, view: WebView, handler: Any,
|
|
error: Any) -> None:
|
|
pass
|
|
|
|
def onReceivedClientCertRequest(self, view: WebView,
|
|
request: Any) -> None:
|
|
pass
|
|
|
|
def onFormResubmission(self, view: WebView, dont_resend: Any,
|
|
resend: Any) -> None:
|
|
pass
|
|
|
|
def doUpdateVisitedHistory(self, view: WebView, url: str,
|
|
is_reloa: bool) -> None:
|
|
pass
|
|
|
|
def onUnhandledKeyEvent(self, view: WebView, event: Any) -> None:
|
|
pass
|
|
|
|
def onScaleChanged(self, view: WebView, old_scale: float, new_scale: float) -> None:
|
|
pass
|
|
|
|
def onRenderProcessGone(self, view: WebView, detail: Any) -> bool:
|
|
return True
|
|
|
|
def onUnhandledInputEvent(self, view: WebView, event: Any) -> None:
|
|
pass
|
|
|
|
def safebrowsingOnBackForwardTransitioned(self, view: WebView,
|
|
safe: bool) -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return "WebViewClient()"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebChromeClient 扩展
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebChromeClient(Stub):
|
|
"""WebChromeClient — Web Chrome客户端扩展"""
|
|
|
|
GET_DEFAULT_VIDEO_POSTER = WEB_CHROME_CLIENT_GET_DEFAULT_VIDEO_POSTER
|
|
GET_VISITED_HISTORY = WEB_CHROME_CLIENT_GET_VISITED_HISTORY
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def onProgressChanged(self, view: WebView, new_progress: int) -> None:
|
|
pass
|
|
|
|
def onReceivedTitle(self, view: WebView, title: str) -> None:
|
|
pass
|
|
|
|
def onReceivedIcon(self, view: WebView, icon: Any) -> None:
|
|
pass
|
|
|
|
def onReceivedTouchIconUrl(self, view: WebView, url: str,
|
|
precomposed: bool) -> None:
|
|
pass
|
|
|
|
def onShowCustomView(self, view: Any, callback: Any) -> None:
|
|
pass
|
|
|
|
def onHideCustomView(self) -> None:
|
|
pass
|
|
|
|
def onCreateWindow(self, view: WebView, is_dialog: bool,
|
|
is_user_gesture: bool,
|
|
result_msg: Any) -> bool:
|
|
return False
|
|
|
|
def onRequestFocus(self, view: WebView) -> None:
|
|
pass
|
|
|
|
def onCloseWindow(self, window: WebView) -> None:
|
|
pass
|
|
|
|
def onJsAlert(self, view: WebView, url: str, message: str,
|
|
result: Any) -> bool:
|
|
return False
|
|
|
|
def onJsConfirm(self, view: WebView, url: str, message: str,
|
|
result: Any) -> bool:
|
|
return False
|
|
|
|
def onJsPrompt(self, view: WebView, url: str, message: str,
|
|
default_value: str, result: Any) -> bool:
|
|
return False
|
|
|
|
def onJsBeforeUnload(self, view: WebView, url: str, message: str,
|
|
result: Any) -> bool:
|
|
return False
|
|
|
|
def onConsoleMessage(self, console_message: Any) -> bool:
|
|
return True
|
|
|
|
def getVideoLoadingProgressView(self) -> Optional[Any]:
|
|
return None
|
|
|
|
def getDefaultVideoPoster(self) -> Optional[Any]:
|
|
return None
|
|
|
|
def onShowFileChooser(self, view: WebView, callback: Any,
|
|
params: Any) -> bool:
|
|
return False
|
|
|
|
def onPermissionRequest(self, request: Any) -> None:
|
|
pass
|
|
|
|
def onPermissionRequestCanceled(self, request: Any) -> None:
|
|
pass
|
|
|
|
def onGeolocationPermissionsShowPrompt(self, origin: str,
|
|
callback: Any) -> None:
|
|
pass
|
|
|
|
def onGeolocationPermissionsHidePrompt(self) -> None:
|
|
pass
|
|
|
|
def onJsTimeout(self) -> bool:
|
|
return True
|
|
|
|
def onExceededDatabaseQuota(self, url: str, database_id: str,
|
|
quota: int, estimated: int,
|
|
quota_updater: Any) -> None:
|
|
pass
|
|
|
|
def onReachedMaxAppCacheSize(self, space_needed: int, total: int,
|
|
quota_updater: Any) -> None:
|
|
pass
|
|
|
|
def onConsoleMessage(self, source_id: str, message: str,
|
|
line_number: int, msg_type: int) -> bool:
|
|
return True
|
|
|
|
def toString(self) -> str:
|
|
return "WebChromeClient()"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CookieManager 扩展
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CookieManager(Stub):
|
|
"""CookieManager — Cookie管理器扩展"""
|
|
|
|
_instance: Optional["CookieManager"] = None
|
|
_lock = threading.Lock()
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._cookies: Dict[str, Dict[str, str]] = {}
|
|
self._accept_cookie = True
|
|
|
|
@staticmethod
|
|
def getInstance() -> "CookieManager":
|
|
with CookieManager._lock:
|
|
if CookieManager._instance is None:
|
|
CookieManager._instance = CookieManager()
|
|
return CookieManager._instance
|
|
|
|
def setAcceptCookie(self, accept: bool) -> None:
|
|
self._accept_cookie = accept
|
|
|
|
def acceptCookie(self) -> bool:
|
|
return self._accept_cookie
|
|
|
|
def setAcceptThirdPartyCookies(self, webview: WebView, accept: bool) -> None:
|
|
pass
|
|
|
|
def acceptThirdPartyCookies(self, webview: WebView) -> bool:
|
|
return False
|
|
|
|
def setCookie(self, url: str, value: str) -> None:
|
|
domain = self._extract_domain(url)
|
|
if domain not in self._cookies:
|
|
self._cookies[domain] = {}
|
|
if "=" in value:
|
|
key, val = value.split("=", 1)
|
|
self._cookies[domain][key.strip()] = val.strip()
|
|
|
|
def getCookie(self, url: str) -> Optional[str]:
|
|
domain = self._extract_domain(url)
|
|
if domain in self._cookies:
|
|
parts = [f"{k}={v}" for k, v in self._cookies[domain].items()]
|
|
return "; ".join(parts)
|
|
return None
|
|
|
|
def removeSessionCookies(self) -> None:
|
|
self._cookies.clear()
|
|
|
|
def removeAllCookies(self) -> None:
|
|
self._cookies.clear()
|
|
|
|
def removeExpiredCookie(self) -> None:
|
|
pass
|
|
|
|
def hasCookies(self) -> bool:
|
|
return bool(self._cookies)
|
|
|
|
def _extract_domain(self, url: str) -> str:
|
|
if "://" in url:
|
|
url = url.split("://", 1)[1]
|
|
return url.split("/")[0].split(":")[0]
|
|
|
|
def flush(self) -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"CookieManager(domains={len(self._cookies)})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# GeolocationPermissions / JsResult / JsPromptResult
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class GeolocationPermissions(Stub):
|
|
"""GeolocationPermissions — 地理位置权限"""
|
|
|
|
_origins: Dict[str, bool] = {}
|
|
_lock = threading.Lock()
|
|
|
|
@classmethod
|
|
def getInstance(cls) -> "GeolocationPermissions":
|
|
return cls()
|
|
|
|
def getOrigins(self, callback: Callable) -> None:
|
|
with self._lock:
|
|
callback(list(self._origins.keys()))
|
|
|
|
def getAllowed(self, origin: str, callback: Callable) -> None:
|
|
with self._lock:
|
|
callback(origin, self._origins.get(origin, False), False)
|
|
|
|
def clear(self, origin: str) -> None:
|
|
with self._lock:
|
|
self._origins.pop(origin, None)
|
|
|
|
def clearAll(self) -> None:
|
|
with self._lock:
|
|
self._origins.clear()
|
|
|
|
def allow(self, origin: str, allow: bool) -> None:
|
|
with self._lock:
|
|
self._origins[origin] = allow
|
|
|
|
|
|
class JsResult(Stub):
|
|
"""JsResult — JavaScript 对话框结果"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._result: Optional[bool] = None
|
|
|
|
def confirm(self) -> None:
|
|
self._result = True
|
|
|
|
def cancel(self) -> None:
|
|
self._result = False
|
|
|
|
def getResult(self) -> Optional[bool]:
|
|
return self._result
|
|
|
|
def toString(self) -> str:
|
|
return f"JsResult(result={self._result})"
|
|
|
|
|
|
class JsPromptResult(JsResult):
|
|
"""JsPromptResult — JavaScript 提示框结果"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._string_result: str = ""
|
|
|
|
def confirm(self, result: str) -> None:
|
|
super().confirm()
|
|
self._string_result = result
|
|
|
|
def getStringResult(self) -> str:
|
|
return self._string_result
|
|
|
|
def toString(self) -> str:
|
|
return f"JsPromptResult(result={self._result}, string={self._string_result})"
|
|
|
|
|
|
class HttpAuthHandler(Stub):
|
|
"""HttpAuthHandler — HTTP 认证处理器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._handled = False
|
|
|
|
def proceed(self, username: str, password: str) -> None:
|
|
self._handled = True
|
|
|
|
def cancel(self) -> None:
|
|
self._handled = True
|
|
|
|
def useHttpAuthUsernamePassword(self, use: bool) -> None:
|
|
pass
|
|
|
|
def isHandled(self) -> bool:
|
|
return self._handled
|
|
|
|
def toString(self) -> str:
|
|
return f"HttpAuthHandler(handled={self._handled})"
|
|
|
|
|
|
class SslErrorHandler(Stub):
|
|
"""SslErrorHandler — SSL 错误处理器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._handled = False
|
|
|
|
def proceed(self) -> None:
|
|
self._handled = True
|
|
|
|
def cancel(self) -> None:
|
|
self._handled = True
|
|
|
|
def isHandled(self) -> bool:
|
|
return self._handled
|
|
|
|
def toString(self) -> str:
|
|
return f"SslErrorHandler(handled={self._handled})"
|
|
|
|
|
|
class ClientCertRequest(Stub):
|
|
"""ClientCertRequest — 客户端证书请求"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._handled = False
|
|
|
|
def getHost(self) -> str:
|
|
return ""
|
|
|
|
def getPort(self) -> int:
|
|
return 443
|
|
|
|
def getKeyTypes(self) -> List[str]:
|
|
return ["RSA"]
|
|
|
|
def getPrincipals(self) -> List[str]:
|
|
return []
|
|
|
|
def cancel(self) -> None:
|
|
self._handled = True
|
|
|
|
def proceed(self, private_key: Any, chain: List[Any]) -> None:
|
|
self._handled = True
|
|
|
|
def ignore(self) -> None:
|
|
self._handled = True
|
|
|
|
def isHandled(self) -> bool:
|
|
return self._handled
|
|
|
|
|
|
class PermissionRequest(Stub):
|
|
"""PermissionRequest — 权限请求"""
|
|
|
|
RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE"
|
|
RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE"
|
|
RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID"
|
|
RESOURCE_MIDI_SYSEX = "android.webkit.resource.MIDI_SYSEX"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._origin: Optional[str] = None
|
|
self._resources: List[str] = []
|
|
self._granted = False
|
|
|
|
def getOrigin(self) -> str:
|
|
return self._origin or ""
|
|
|
|
def getResources(self) -> List[str]:
|
|
return list(self._resources)
|
|
|
|
def grant(self, resources: List[str]) -> None:
|
|
self._granted = True
|
|
|
|
def deny(self) -> None:
|
|
self._granted = False
|
|
|
|
def isGranted(self) -> bool:
|
|
return self._granted
|
|
|
|
def toString(self) -> str:
|
|
return f"PermissionRequest(origin={self._origin}, granted={self._granted})"
|
|
|
|
|
|
class ConsoleMessage(Stub):
|
|
"""ConsoleMessage — 控制台消息"""
|
|
|
|
MessageLevel = type("MessageLevel", (), {
|
|
"TIP": 0, "LOG": 1, "WARNING": 2, "ERROR": 3, "DEBUG": 4
|
|
})
|
|
|
|
def __init__(self, message: str = "", source_id: str = "",
|
|
line_number: int = 0, msg_level: int = MessageLevel.LOG):
|
|
super().__init__()
|
|
self._message = message
|
|
self._source_id = source_id
|
|
self._line_number = line_number
|
|
self._msg_level = msg_level
|
|
|
|
def message(self) -> str:
|
|
return self._message
|
|
|
|
def sourceId(self) -> str:
|
|
return self._source_id
|
|
|
|
def lineNumber(self) -> int:
|
|
return self._line_number
|
|
|
|
def messageLevel(self) -> int:
|
|
return self._msg_level
|
|
|
|
def toString(self) -> str:
|
|
return f"ConsoleMessage({self._message[:50]})"
|
|
|
|
|
|
class ValueCallback(Stub):
|
|
"""ValueCallback — 值回调接口"""
|
|
|
|
def onReceiveValue(self, value: Any) -> None:
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebBackForwardList / WebHistoryItem / WebIconDatabase / etc.
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebBackForwardList(Stub):
|
|
"""WebBackForwardList — 后退/前进列表"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._items: List["WebHistoryItem"] = []
|
|
self._current_index: int = -1
|
|
|
|
def getCurrentItem(self) -> Optional["WebHistoryItem"]:
|
|
if 0 <= self._current_index < len(self._items):
|
|
return self._items[self._current_index]
|
|
return None
|
|
|
|
def getCurrentIndex(self) -> int:
|
|
return self._current_index
|
|
|
|
def getItemAtIndex(self, index: int) -> Optional["WebHistoryItem"]:
|
|
if 0 <= index < len(self._items):
|
|
return self._items[index]
|
|
return None
|
|
|
|
def getSize(self) -> int:
|
|
return len(self._items)
|
|
|
|
def toString(self) -> str:
|
|
return f"WebBackForwardList(size={len(self._items)}, current={self._current_index})"
|
|
|
|
|
|
class WebHistoryItem(Stub):
|
|
"""WebHistoryItem — Web历史条目"""
|
|
|
|
def __init__(self, url: str = "", title: str = "",
|
|
favicon: Any = None):
|
|
super().__init__()
|
|
self._url = url
|
|
self._title = title
|
|
self._favicon = favicon
|
|
|
|
def getUrl(self) -> str:
|
|
return self._url
|
|
|
|
def getTitle(self) -> str:
|
|
return self._title
|
|
|
|
def getFavicon(self) -> Optional[Any]:
|
|
return self._favicon
|
|
|
|
def setUrl(self, url: str) -> None:
|
|
self._url = url
|
|
|
|
def setTitle(self, title: str) -> None:
|
|
self._title = title
|
|
|
|
def setFavicon(self, favicon: Any) -> None:
|
|
self._favicon = favicon
|
|
|
|
def toString(self) -> str:
|
|
return f"WebHistoryItem(url={self._url}, title={self._title})"
|
|
|
|
|
|
class WebIconDatabase(Stub):
|
|
"""WebIconDatabase — Web图标数据库"""
|
|
|
|
_instance: Optional["WebIconDatabase"] = None
|
|
|
|
@staticmethod
|
|
def getInstance() -> "WebIconDatabase":
|
|
if WebIconDatabase._instance is None:
|
|
WebIconDatabase._instance = WebIconDatabase()
|
|
return WebIconDatabase._instance
|
|
|
|
def open(self, path: str) -> None:
|
|
pass
|
|
|
|
def close(self) -> None:
|
|
pass
|
|
|
|
def removeAllIcons(self) -> None:
|
|
pass
|
|
|
|
def requestIconForPageUrl(self, url: str, callback: Callable) -> None:
|
|
callback(url, None)
|
|
|
|
def retainIconForPageUrl(self, url: str) -> None:
|
|
pass
|
|
|
|
def releaseIconForPageUrl(self, url: str) -> None:
|
|
pass
|
|
|
|
def getIconForPageUrl(self, url: str) -> Optional[Any]:
|
|
return None
|
|
|
|
def toString(self) -> str:
|
|
return "WebIconDatabase()"
|
|
|
|
|
|
class WebViewDatabase(Stub):
|
|
"""WebViewDatabase — WebView数据库"""
|
|
|
|
_instance: Optional["WebViewDatabase"] = None
|
|
|
|
@staticmethod
|
|
def getInstance(context: Any) -> "WebViewDatabase":
|
|
if WebViewDatabase._instance is None:
|
|
WebViewDatabase._instance = WebViewDatabase()
|
|
return WebViewDatabase._instance
|
|
|
|
def hasFormData(self) -> bool:
|
|
return False
|
|
|
|
def clearFormData(self) -> None:
|
|
pass
|
|
|
|
def hasUsernamePassword(self) -> bool:
|
|
return False
|
|
|
|
def clearUsernamePassword(self) -> None:
|
|
pass
|
|
|
|
def hasHttpAuthUsernamePassword(self) -> bool:
|
|
return False
|
|
|
|
def clearHttpAuthUsernamePassword(self) -> None:
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return "WebViewDatabase()"
|
|
|
|
|
|
class WebViewFragment(Stub):
|
|
"""WebViewFragment — WebView片段"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._webview: Optional[WebView] = None
|
|
|
|
def onCreateView(self, inflater: Any, container: Any,
|
|
savedInstanceState: Any) -> Optional[WebView]:
|
|
self._webview = WebView()
|
|
return self._webview
|
|
|
|
def onPause(self) -> None:
|
|
if self._webview:
|
|
self._webview.onPause()
|
|
|
|
def onResume(self) -> None:
|
|
if self._webview:
|
|
self._webview.onResume()
|
|
|
|
def onDestroyView(self) -> None:
|
|
if self._webview:
|
|
self._webview.destroy()
|
|
|
|
def getWebView(self) -> Optional[WebView]:
|
|
return self._webview
|
|
|
|
def toString(self) -> str:
|
|
return f"WebViewFragment(webview={'yes' if self._webview else 'no'})"
|
|
|
|
|
|
class DateSorter(Stub):
|
|
"""DateSorter — 日期排序器"""
|
|
|
|
DAY_COUNT = 5
|
|
|
|
def __init__(self, context: Any):
|
|
super().__init__()
|
|
self._bounds: List[int] = [0, 0, 0, 0, 0]
|
|
self._labels: List[str] = ["Today", "Yesterday", "Earlier"]
|
|
|
|
def getBounds(self) -> List[int]:
|
|
return list(self._bounds)
|
|
|
|
def getLabel(self, index: int) -> str:
|
|
if 0 <= index < len(self._labels):
|
|
return self._labels[index]
|
|
return ""
|
|
|
|
def toString(self) -> str:
|
|
return "DateSorter()"
|
|
|
|
|
|
class FindActionModeCallback(Stub):
|
|
"""FindActionModeCallback — 查找操作模式回调"""
|
|
|
|
def __init__(self, context: Any = None):
|
|
super().__init__()
|
|
self._search_text: str = ""
|
|
self._global_search_count: int = 0
|
|
self._match_count: int = 0
|
|
|
|
def finishActionMode(self) -> None:
|
|
pass
|
|
|
|
def setText(self, text: str) -> None:
|
|
self._search_text = text
|
|
|
|
def getText(self) -> str:
|
|
return self._search_text
|
|
|
|
def setGlobalSearchCount(self, count: int) -> None:
|
|
self._global_search_count = count
|
|
|
|
def getGlobalSearchCount(self) -> int:
|
|
return self._global_search_count
|
|
|
|
def setMatchCount(self, count: int) -> None:
|
|
self._match_count = count
|
|
|
|
def getMatchCount(self) -> int:
|
|
return self._match_count
|
|
|
|
def toString(self) -> str:
|
|
return (f"FindActionModeCallback(search={self._search_text}, "
|
|
f"matches={self._match_count})")
|
|
|
|
|
|
class JsDialogHelper(Stub):
|
|
"""JsDialogHelper — JavaScript 对话框助手"""
|
|
|
|
ALERT = 1
|
|
CONFIRM = 2
|
|
PROMPT = 3
|
|
UNLOAD = 4
|
|
|
|
def __init__(self, result: JsResult, default_value: str = "",
|
|
dialog_type: int = ALERT, message: str = ""):
|
|
super().__init__()
|
|
self._result = result
|
|
self._default_value = default_value
|
|
self._dialog_type = dialog_type
|
|
self._message = message
|
|
|
|
def getDialogType(self) -> int:
|
|
return self._dialog_type
|
|
|
|
def getMessage(self) -> str:
|
|
return self._message
|
|
|
|
def getDefaultValue(self) -> str:
|
|
return self._default_value
|
|
|
|
def invokeCallback(self, result: Any) -> None:
|
|
if self._result:
|
|
self._result.confirm()
|
|
|
|
def cancelDialog(self) -> None:
|
|
if self._result:
|
|
self._result.cancel()
|
|
|
|
def toString(self) -> str:
|
|
types = {1: "ALERT", 2: "CONFIRM", 3: "PROMPT", 4: "UNLOAD"}
|
|
return f"JsDialogHelper(type={types.get(self._dialog_type, 'UNKNOWN')})" |