# -*- coding: utf-8 -*- """共享的 Android 工具函数,可被框架内外复用。""" from __future__ import annotations import logging import re import time from typing import Callable, Optional logger = logging.getLogger(__name__) def get_current_package( adb_shell_func: Callable[[str], str], max_attempts: int = 3, retry_delay: float = 0.5, ) -> Optional[str]: """Read the foreground package via ``dumpsys``, retrying transient failures. Args: adb_shell_func: A callable that accepts a shell command string and returns the stdout text. Example:: lambda cmd: adb_client.shell(cmd) max_attempts: Maximum retry attempts for transient failures. retry_delay: Seconds to wait between retries. Returns: The foreground package name, or ``None`` if it could not be determined. """ for attempt in range(max_attempts): try: focused_app = adb_shell_func("dumpsys window | grep mFocusedApp") if focused_app: matches = re.findall( r"mFocusedApp=ActivityRecord\{[a-f0-9]+\s+\S+\s+([^/]+)/", focused_app, ) if matches: return matches[-1] current_focus = adb_shell_func("dumpsys window | grep mCurrentFocus") if current_focus: matches = re.findall( r"Window\{[a-f0-9]+\s+\S+\s+([^/]+)/", current_focus, ) if matches: return matches[-1] resumed_activity = adb_shell_func("dumpsys activity activities | grep mResumedActivity") if resumed_activity: matches = re.findall( r"\{[a-f0-9]+\s+\S+\s+([^/]+)/", resumed_activity, ) if matches: return matches[-1] if attempt < max_attempts - 1: time.sleep(retry_delay) except Exception as exc: if attempt < max_attempts - 1: time.sleep(retry_delay) continue logger.error("Failed to get current package: %s", exc) return None logger.warning("Failed to get package name after %d attempts", max_attempts) return None