Android应用固定/取消固定状态变更检测及回调触发问题
核心问题说明
onLockTaskModeEntering()和onLockTaskModeExiting()这两个回调必须要求你的应用成为设备所有者或配置文件所有者(属于设备策略管理器DPM范畴)才能触发。哪怕只是接收状态变更通知,系统也只会将这类事件发送给具备设备管理权限的应用——这是Android系统对锁定任务模式这类安全管控功能的权限限制,官方文档虽未单独明确标注这两个回调的权限要求,但它们属于DeviceAdminReceiver的设备管理相关回调,默认依赖设备所有者/配置文件所有者权限。
方案一:通过DeviceAdminReceiver实现(需设备/配置文件所有者权限)
1. 配置DeviceAdminReceiver组件
在清单文件中正确声明Receiver,添加对应的intent-filter和权限:
<receiver android:name=".MyDeviceAdminReceiver" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> <action android:name="android.app.action.LOCK_TASK_MODE_ENTERING" /> <action android:name="android.app.action.LOCK_TASK_MODE_EXITING" /> </intent-filter> </receiver>
2. 配置设备管理权限策略
在res/xml/device_admin.xml中声明需使用的设备管理策略,必须包含lock-task:
<device-admin xmlns:android="http://schemas.android.com/apk/res/android"> <uses-policies> <lock-task /> </uses-policies> </device-admin>
3. 将应用设置为设备所有者/配置文件所有者
通过adb命令完成权限授予:
- 设置为设备所有者:
adb shell dpm set-device-owner com.your.package/.MyDeviceAdminReceiver
- 设置为工作配置文件所有者(适用于多用户场景):
adb shell dpm set-profile-owner com.your.package/.MyDeviceAdminReceiver [user-id]
注意:设备所有者只能设置一个,若已有其他应用占用,需先通过
adb shell dpm remove-active-admin com.other.package/.OtherAdminReceiver移除。
4. 实现回调逻辑
在自定义的MyDeviceAdminReceiver中重写回调:
public class MyDeviceAdminReceiver extends DeviceAdminReceiver { @Override public void onLockTaskModeEntering(Context context, Intent intent, String pkg) { super.onLockTaskModeEntering(context, intent, pkg); // 处理进入锁定任务模式的逻辑 } @Override public void onLockTaskModeExiting(Context context, Intent intent) { super.onLockTaskModeExiting(context, intent); // 处理退出锁定任务模式的逻辑 } }
方案二:通过辅助服务(AccessibilityService)实现(无需设备所有者权限)
如果不想让应用成为设备所有者,可借助辅助服务监听窗口状态变化,间接判断锁定任务模式的状态变更:
1. 配置辅助服务组件
在清单文件中声明辅助服务:
<service android:name=".MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
2. 配置辅助服务参数
在res/xml/accessibility_service_config.xml中设置监听的事件类型:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" />
3. 实现状态监听逻辑
在辅助服务中对比前后的锁定任务模式状态:
public class MyAccessibilityService extends AccessibilityService { private int lastLockTaskState = ActivityManager.LOCK_TASK_MODE_NONE; @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); int currentState = am.getLockTaskModeState(); if (currentState != lastLockTaskState) { if (currentState != ActivityManager.LOCK_TASK_MODE_NONE) { // 进入锁定任务模式 } else { // 退出锁定任务模式 } lastLockTaskState = currentState; } } } @Override public void onInterrupt() { // 服务中断时的处理逻辑 } }
注意:辅助服务需要用户手动在系统设置的「无障碍」选项中开启,这是该方案的局限性。
内容的提问来源于stack exchange,提问作者Flyview

