""" 应用管理技能 - 打开、关闭、切换应用 """ import re import logging import sys import os from typing import Dict, Any, List # 兼容独立运行和包导入 _agent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if _agent_dir not in sys.path: sys.path.insert(0, _agent_dir) try: from skills.base import BaseSkill except ImportError: from ..base import BaseSkill logger = logging.getLogger(__name__) class AppManagerSkill(BaseSkill): """应用管理技能""" PACKAGE = "" # 通用技能 NAME = "应用管理" # 常用应用包名 APP_PACKAGES = { "微信": "com.tencent.mm", "抖音": "com.ss.android.ugc.aweme", "支付宝": "com.eg.android.AlipayGphone", "淘宝": "com.taobao.taobao", "微博": "com.sina.weibo", "qq": "com.tencent.mobileqq", "设置": "com.android.settings", "相机": "com.android.camera", "浏览器": "com.android.chrome", "豆包": "com.bytedance.doubao", "小红书": "com.xingin.xhs", "bilibili": "tv.danmaku.bili", "知乎": "com.zhihu.android", } def open_app(self, app_name: str) -> Dict[str, Any]: """ 打开应用 Args: app_name: 应用名称(中文或包名) Returns: 执行结果 """ try: # 查找包名 package = self.APP_PACKAGES.get(app_name) if not package: # 尝试直接作为包名 package = app_name # 启动应用 self.d.app_start(package) self.sleep(2) # 验证是否启动成功 current = self.d.app_current() if current.get("package") == package: return { "success": True, "app_name": app_name, "package": package, "message": f"已打开{app_name}" } else: return { "success": False, "error": f"应用启动失败或包名错误: {app_name}", "package": package } except Exception as e: logger.error(f"打开应用失败 {app_name}: {e}") return { "success": False, "error": str(e), "app_name": app_name } def close_app(self, app_name: str = None, package: str = None) -> Dict[str, Any]: """ 关闭应用 Args: app_name: 应用名称 package: 包名(优先) Returns: 执行结果 """ try: if package: target_package = package elif app_name: target_package = self.APP_PACKAGES.get(app_name, app_name) else: # 关闭当前应用 current = self.d.app_current() target_package = current.get("package") if target_package: self.d.app_stop(target_package) return { "success": True, "package": target_package, "message": "应用已关闭" } else: return {"success": False, "error": "未指定应用"} except Exception as e: logger.error(f"关闭应用失败: {e}") return {"success": False, "error": str(e)} def get_running_apps(self) -> Dict[str, Any]: """获取正在运行的应用列表""" try: self.d.press("recent") self.sleep(1) ui_tree = self.d.dump_hierarchy() apps = self._parse_recent_tasks_from_ui(ui_tree) self.home() return {"success": True, "apps": apps} except Exception as e: return {"success": False, "error": str(e), "apps": []} @staticmethod def _parse_recent_tasks_from_ui(xml: str) -> List[Dict[str, Any]]: """从最近任务 UI 解析应用标题占位""" out = [] if not xml: return out skip = {"最近", "清除", "关闭", "全部", "清理"} for i, m in enumerate(re.finditer(r'\b(text|content-desc)="([^"]{1,80})"', xml)): if i >= 50: break text = m.group(2).strip() if text and text not in skip and not text.startswith("com."): out.append({"index": len(out) + 1, "title": text}) return out def get_installed_apps(self, limit: int = 100) -> Dict[str, Any]: """获取已安装的应用列表""" try: # 通过shell命令获取 result = self.d.shell("pm list packages -3") # 第三方应用 packages = [] for line in result.output.split('\n'): if line.startswith('package:'): pkg = line.replace('package:', '').strip() packages.append(pkg) return { "success": True, "packages": packages[:limit], "total": len(packages) } except Exception as e: return {"success": False, "error": str(e), "packages": []} def switch_app(self, app_name: str) -> Dict[str, Any]: """ 切换应用(如果已打开则切换,否则打开) Args: app_name: 应用名称 Returns: 执行结果 """ try: package = self.APP_PACKAGES.get(app_name, app_name) # 检查是否正在运行 current = self.d.app_current() if current.get("package") == package: return { "success": True, "message": f"{app_name}已是当前应用", "package": package } # 打开或切换 self.d.app_start(package) self.sleep(2) return { "success": True, "app_name": app_name, "package": package, "message": f"已切换到{app_name}" } except Exception as e: logger.error(f"切换应用失败 {app_name}: {e}") return { "success": False, "error": str(e), "app_name": app_name }