Android 如何监控当前Foreground Activity,如何获知应用程序的启动
2016-01-21 13:04
676 查看
目前主流的监控Foreground Activity的方法,主要有以下三种,各有利弊,还没有找到一个彻底的完美解决方案!
一、使用
通过 AccessibilityService可以监控当前Active
Window
通过回调函数 onAccessibilityEven 检查事件类型 TYPE_WINDOW_STATE_CHANGED 获知当前 window
改变了
通过调用 PackageManager.getActivityInfo() 检查当前的window
是不是一个Activity
不需要轮询机制,非常省电
不需要申明 GET_TASKS 权限
settings 才能收到 AccessibilityEvent事件
当用户手动在手机设置页面关闭 Accessibility setting后,AccessibilityService就会停止运行。你也可以在service 里面用代码 stop itself,但是一旦在代码里面停止service之后,目前还没有找到什么办法能够再次开启。
当用户在设置页面开启 AccessibilityService的时候,有些第三方应用会弹出一个悬浮窗盖住屏幕,导致用户无法点击确认按钮。例如
Velis Auto Brightness 和 Lux 这些App就会干这种事。 目前还不知道如果规避这些第三方应用的恶心行为。
AccessibilityService 是被动触发的,无法主动获知当前Activity
的信息,除非当前Activity有所改变
不要忘记添加permission 到Manifest 文件:
一、使用 AccessibilityService
通过 AccessibilityService可以监控当前ActiveWindow
通过回调函数 onAccessibilityEven 检查事件类型 TYPE_WINDOW_STATE_CHANGED 获知当前 window
改变了
通过调用 PackageManager.getActivityInfo() 检查当前的window
是不是一个Activity
1. 优点:
经过测试Android 2.2 (API 8) ~ Android 5.1.0(API 22) 都可以正常工作,更高版本的还没有测试过不需要轮询机制,非常省电
不需要申明 GET_TASKS 权限
2. 缺点:
用户必须手动在手机的设置页面开启 Android's accessibilitysettings 才能收到 AccessibilityEvent事件
当用户手动在手机设置页面关闭 Accessibility setting后,AccessibilityService就会停止运行。你也可以在service 里面用代码 stop itself,但是一旦在代码里面停止service之后,目前还没有找到什么办法能够再次开启。
当用户在设置页面开启 AccessibilityService的时候,有些第三方应用会弹出一个悬浮窗盖住屏幕,导致用户无法点击确认按钮。例如
Velis Auto Brightness 和 Lux 这些App就会干这种事。 目前还不知道如果规避这些第三方应用的恶心行为。
AccessibilityService 是被动触发的,无法主动获知当前Activity
的信息,除非当前Activity有所改变
3. 代码示例
public class WindowChangeDetectingService extends AccessibilityService { @Override protected void onServiceConnected() { super.onServiceConnected(); //Configure these here for compatibility with API 13 and below. AccessibilityServiceInfo config = new AccessibilityServiceInfo(); config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; if (Build.VERSION.SDK_INT >= 16) //Just in case this helps config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; setServiceInfo(config); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { ComponentName componentName = new ComponentName( event.getPackageName().toString(), event.getClassName().toString() ); ActivityInfo activityInfo = tryGetActivity(componentName); boolean isActivity = activityInfo != null; if (isActivity) Log.i("CurrentActivity", componentName.flattenToShortString()); } } private ActivityInfo tryGetActivity(ComponentName componentName) { try { return getPackageManager().getActivityInfo(componentName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } } @Override public void onInterrupt() {} }
6. Enabling the Service每个用户必须手动到手机设置页面开启 AccessibilityService 这个service才会被调用到。查看具体实现:thisStackOverflow answer 二、使用 ActivityManager使用 ActivityManager有一定版本限制。官方文档有详细的说明:onAPI-21 as of LOLLIPOP, ActivityManager.getRunningTasks() is no longer available to third party applications: the introduction of document-centric recents means it can leak person information to the caller. For backwards compatibility, it will still return a small subset of its data: at least the caller's own tasks, and possibly some other tasks such as home that are known to not be sensitive. 网上有人说可以用下面的方法分别调用不同的API,兼容不同的版本: Pre-Lollipop: ActivityManager.getRunningTasks Lollipop: ActivityManager.getRunningAppProcesses 在 Android5.0 (API-21)及以上,getRunningTasks将只返回自己和 launcher,getRunningTasks 无法正确判断当前应用是否为front, 不同版本测试的结果也不一样: 在 Android 5.0版本: 1. 当用户在当前App页面时,runningTasksInfos.get(0) = 当前App 2. 当用户回到launch页面时,runningTasksInfos.get(0) = launcher 3. 当用户在其它App页面时,runningTasksInfos.get(0) = launcher 在 Android 5.1, 6.0 以上版本: 1. 当用户在钱盾页面时,runningTasksInfos.get(0) = 当前App 2. 当用户回到launch页面时,runningTasksInfos.get(0) = launcher 3. 当用户在其它App页面时,runningTasksInfos.get(0) = 当前App 对于getRunningAppProcesses,经过我自己的测试: 在Android 5.0(API-21) 版本getRunningAppProcesses可以获取所有应用的process,可以通过其来判断top package; 但是在 Android 5.1.0 (API-22)及其以上Android 6.0 (API-23)上永远只返回应用自身的process,不能用来判断任意top package,但是可以用来判断当前App应用是否在前台: 官方文档申明 getRunningAppProcesses() 只是用于debugging and management user interfaces,有一定的局限性,说不定哪天就不支持了 依赖反射调用: ActivityManager.RunningAppProcessInfo.processState 无法监控 App switcher activity.
|
<uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
相关文章推荐
- jenkins+git+android studio自动化构建(持续集成)
- 自定义View实现米老鼠时钟
- 第一节 简单的一个扫盲
- Android service后台保活原理相关和测试结果
- Android 布局3.绝对布局和表格布局
- 解决 Android studio 从github导入PagerSlidingTabStrip 工程问题
- Android ORM系列之GreenDao关联关系映射
- 笔记:Android ListView 的Item点击不变色
- Android -下拉刷新,ViewPager和ScrollView嵌套滚动问题解决方案
- 阿冰教你一步一步做Android新闻客户端(二)两种异步线程加载图片的方法
- android安卓屏蔽禁用系统输入法,自定义软键盘,解决EditText光标问题demo
- Android Parcelable和Serializable的区别
- android 通过字符串来获取R下面资源的ID 值
- 【Android 基础】Animation 动画介绍和实现
- Android基础Activity初步了解
- Android拨打电话(Intent.ACTION.CALL)
- Android Studio中JNI -- 2 -- 编写c文件
- 深入android6.0 设备 idle状态
- Android6.0 设备Idle状态(二)AlarmManagerService setIdleUntil接口
- [Androd初级]解决Listview的子项Item的高度无法设置的情节