Android 15 Lock Task 模式深度分析 (第二部分)
6. 企业管理配置
6.1 DeviceOwner/ProfileOwner配置
Lock Task的完全锁定模式(LOCKED)需要通过DevicePolicyManager(DPM)进行配置。只有DeviceOwner或ProfileOwner才能使用完整的Lock Task功能。
6.1.1 设置白名单
java
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
public class DeviceAdminHelper {
private DevicePolicyManager mDpm;
private ComponentName mAdminComponent;
public DeviceAdminHelper(Context context, ComponentName adminComponent) {
mDpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
mAdminComponent = adminComponent;
}
/**
* 设置Lock Task白名单包
* 只有DeviceOwner或ProfileOwner可以调用
*/
public void setLockTaskPackages(String[] packages) {
if (!mDpm.isDeviceOwnerApp(mAdminComponent.getPackageName()) &&
!mDpm.isProfileOwnerApp(mAdminComponent.getPackageName())) {
throw new SecurityException("Not a device owner or profile owner");
}
try {
mDpm.setLockTaskPackages(mAdminComponent, packages);
Log.i(TAG, "Lock task packages set: " + Arrays.toString(packages));
} catch (SecurityException e) {
Log.e(TAG, "Failed to set lock task packages", e);
}
}
/**
* 获取当前白名单
*/
public String[] getLockTaskPackages() {
return mDpm.getLockTaskPackages(mAdminComponent);
}
/**
* 检查包是否在白名单中
*/
public boolean isLockTaskPermitted(String packageName) {
return mDpm.isLockTaskPermitted(packageName);
}
}
使用示例:
java
// 在DeviceOwner应用中
DeviceAdminHelper adminHelper = new DeviceAdminHelper(
context,
new ComponentName(context, MyDeviceAdminReceiver.class)
);
// 设置多个应用进入白名单
String[] allowedPackages = {
"com.example.kiosk.launcher", // Kiosk启动器
"com.example.kiosk.app1", // 业务应用1
"com.example.kiosk.app2", // 业务应用2
"com.android.settings" // 设置应用(可选)
};
adminHelper.setLockTaskPackages(allowedPackages);
6.1.2 配置Lock Task功能
源码 : DevicePolicyManager.java: Line 3018-3091
java
public class LockTaskFeatureConfig {
private DevicePolicyManager mDpm;
private ComponentName mAdminComponent;
/**
* 设置Lock Task模式下允许的功能
* @param features 功能标志位的组合
*/
public void setLockTaskFeatures(int features) {
mDpm.setLockTaskFeatures(mAdminComponent, features);
}
/**
* 示例: 配置Kiosk模式 - 最小功能
*/
public void configureKioskMode() {
int features = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
// 禁用所有系统功能
setLockTaskFeatures(features);
}
/**
* 示例: 配置受限模式 - 允许基本功能
*/
public void configureRestrictedMode() {
int features = DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO
| DevicePolicyManager.LOCK_TASK_FEATURE_HOME
| DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
setLockTaskFeatures(features);
}
/**
* 示例: 配置考试模式 - 允许通知但禁止导航
*/
public void configureExamMode() {
int features = DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO
| DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
| DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
setLockTaskFeatures(features);
}
/**
* 示例: 配置展示模式 - 允许大部分功能
*/
public void configurePresentationMode() {
int features = DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO
| DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
| DevicePolicyManager.LOCK_TASK_FEATURE_HOME
| DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW
| DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
setLockTaskFeatures(features);
}
/**
* 获取当前配置的功能
*/
public int getLockTaskFeatures() {
return mDpm.getLockTaskFeatures(mAdminComponent);
}
}
6.1.3 功能标志详解
| 功能标志 | 值 | 说明 | 允许的操作 |
|---|---|---|---|
LOCK_TASK_FEATURE_NONE |
0 | 无功能 | 完全限制,仅锁定应用可用 |
LOCK_TASK_FEATURE_SYSTEM_INFO |
1 | 系统信息 | 显示状态栏时钟、电池等系统图标 |
LOCK_TASK_FEATURE_NOTIFICATIONS |
2 | 通知 | 显示通知图标和下拉通知面板 |
LOCK_TASK_FEATURE_HOME |
4 | Home按钮 | 允许使用Home按钮切换白名单应用 |
LOCK_TASK_FEATURE_OVERVIEW |
8 | 最近任务 | 允许使用最近任务按钮(需配合HOME) |
LOCK_TASK_FEATURE_GLOBAL_ACTIONS |
16 | 全局操作 | 允许电源菜单(关机/重启) |
LOCK_TASK_FEATURE_KEYGUARD |
32 | 锁屏 | 允许锁屏功能 |
LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK |
64 | 阻止启动Activity | 阻止任务内启动非白名单Activity |
注意:
LOCK_TASK_FEATURE_OVERVIEW必须与LOCK_TASK_FEATURE_HOME一起使用- 默认情况下(PINNED模式),
LOCK_TASK_FEATURE_GLOBAL_ACTIONS是启用的
6.1.4 完整的DeviceOwner配置示例
java
public class KioskDeviceAdmin extends DeviceAdminReceiver {
private static final String TAG = "KioskDeviceAdmin";
@Override
public void onEnabled(Context context, Intent intent) {
super.onEnabled(context, intent);
Log.i(TAG, "Device admin enabled");
// 配置Kiosk模式
setupKioskMode(context);
}
private void setupKioskMode(Context context) {
DevicePolicyManager dpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminComponent =
new ComponentName(context, KioskDeviceAdmin.class);
// 1. 设置白名单应用
String[] lockTaskPackages = {
context.getPackageName(), // Kiosk应用自身
"com.example.kiosk.content"
};
dpm.setLockTaskPackages(adminComponent, lockTaskPackages);
// 2. 配置允许的功能(最小化)
int features = DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO
| DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
dpm.setLockTaskFeatures(adminComponent, features);
// 3. 设置其他策略
// 禁用状态栏
dpm.setStatusBarDisabled(adminComponent, true);
// 禁用安全键盘
dpm.setKeyguardDisabled(adminComponent, true);
// 设置用户限制
dpm.addUserRestriction(adminComponent,
UserManager.DISALLOW_SAFE_BOOT);
dpm.addUserRestriction(adminComponent,
UserManager.DISALLOW_FACTORY_RESET);
dpm.addUserRestriction(adminComponent,
UserManager.DISALLOW_ADD_USER);
dpm.addUserRestriction(adminComponent,
UserManager.DISALLOW_INSTALL_APPS);
dpm.addUserRestriction(adminComponent,
UserManager.DISALLOW_UNINSTALL_APPS);
Log.i(TAG, "Kiosk mode configured");
}
/**
* 启动Kiosk应用并进入Lock Task
*/
public static void startKioskApp(Context context) {
Intent intent = new Intent(context, KioskMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
KioskMainActivity实现:
java
public class KioskMainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_kiosk);
// 隐藏系统UI
hideSystemUI();
}
@Override
protected void onStart() {
super.onStart();
// 自动启动Lock Task
startLockTask();
}
private void hideSystemUI() {
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
@Override
public void onBackPressed() {
// 在Kiosk模式中禁用返回键
// 不调用super.onBackPressed()
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 拦截某些按键
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
keyCode == KeyEvent.KEYCODE_POWER) {
// 可以选择性处理或忽略
return true;
}
return super.onKeyDown(keyCode, event);
}
}
6.2 ADB命令配置
对于开发和测试,可以使用ADB命令配置Lock Task。
6.2.1 设置DeviceOwner(仅限未激活设备)
bash
# 安装设备管理员应用
adb install KioskApp.apk
# 设置为DeviceOwner
adb shell dpm set-device-owner com.example.kiosk/.KioskDeviceAdmin
# 验证
adb shell dpm list-owners
6.2.2 配置Lock Task白名单
bash
# 设置白名单(多个包用空格分隔)
adb shell dpm set-lock-task-packages com.example.kiosk \
com.example.kiosk com.example.kiosk.content
# 查看当前白名单
adb shell dpm get-lock-task-packages
6.2.3 配置Lock Task功能
bash
# 设置功能标志(使用十进制值)
# SYSTEM_INFO(1) + HOME(4) = 5
adb shell settings put global lock_task_features 5
# 或使用dpm命令
adb shell dpm set-lock-task-features com.example.kiosk/.KioskDeviceAdmin 5
功能标志计算:
NONE = 0
SYSTEM_INFO = 1
NOTIFICATIONS = 2
HOME = 4
OVERVIEW = 8
GLOBAL_ACTIONS = 16
KEYGUARD = 32
BLOCK_ACTIVITY_START = 64
示例组合:
- 基本Kiosk: SYSTEM_INFO + HOME = 1 + 4 = 5
- 带通知: SYSTEM_INFO + NOTIFICATIONS + HOME = 1 + 2 + 4 = 7
- 完全受限: NONE = 0
- 全功能: 1+2+4+8+16+32 = 63
6.2.4 启动和停止Lock Task
bash
# 启动指定包的Lock Task
adb shell am start-lock-task-mode com.example.kiosk/.MainActivity
# 停止Lock Task
adb shell am stop-lock-task-mode
# 查看当前Lock Task状态
adb shell dumpsys activity | grep "mLockTaskMode"
6.2.5 清除DeviceOwner
bash
# 移除DeviceOwner(会清除所有策略)
adb shell dpm remove-active-admin com.example.kiosk/.KioskDeviceAdmin
# 恢复出厂设置
adb shell am broadcast -a android.intent.action.FACTORY_RESET \
-p android --ez EXTRA_WIPE_EXTERNAL_STORAGE true
6.3 Screen Pinning用户设置
Screen Pinning(屏幕固定)可以通过系统设置启用。
6.3.1 启用Screen Pinning
通过设置界面:
- 打开设置 → 安全 → 屏幕固定
- 开启"屏幕固定"开关
- 可选:启用"退出时要求解锁"
通过代码检查:
java
public class ScreenPinningHelper {
/**
* 检查Screen Pinning是否启用
*/
public static boolean isScreenPinningEnabled(Context context) {
try {
int enabled = Settings.System.getInt(
context.getContentResolver(),
Settings.System.LOCK_TO_APP_ENABLED,
0
);
return enabled != 0;
} catch (Exception e) {
return false;
}
}
/**
* 检查退出时是否需要解锁
*/
public static boolean isExitLockRequired(Context context) {
try {
int locked = Settings.Secure.getInt(
context.getContentResolver(),
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
0
);
return locked != 0;
} catch (Exception e) {
return false;
}
}
}
6.3.2 Settings实现分析
源码 : /packages/apps/Settings/src/com/android/settings/security/ScreenPinningSettings.java
Screen Pinning设置界面提供:
- 开关控件:启用/禁用功能
- 退出锁定选项:退出时是否需要解锁设备
- 使用说明:如何使用Screen Pinning
相关Settings常量:
java
// Settings.System.LOCK_TO_APP_ENABLED
// 0 = 禁用, 1 = 启用
// Settings.Secure.LOCK_TO_APP_EXIT_LOCKED
// 0 = 退出时不锁定, 1 = 退出时锁定设备
7. 使用场景
7.1 Kiosk模式(专用设备)
场景描述: 将设备配置为单一用途的专用设备,如自助服务终端、信息查询机等。
实现要点:
java
public class KioskModeManager {
/**
* 配置完整的Kiosk模式
*/
public void setupFullKioskMode(Context context) {
DevicePolicyManager dpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName admin = new ComponentName(context, MyDeviceAdmin.class);
// 1. 设置Lock Task白名单(仅Kiosk应用)
String[] packages = {context.getPackageName()};
dpm.setLockTaskPackages(admin, packages);
// 2. 最小化功能(仅系统信息)
int features = DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
dpm.setLockTaskFeatures(admin, features);
// 3. 禁用状态栏和键盘锁
dpm.setStatusBarDisabled(admin, true);
dpm.setKeyguardDisabled(admin, true);
// 4. 添加用户限制
dpm.addUserRestriction(admin, UserManager.DISALLOW_SAFE_BOOT);
dpm.addUserRestriction(admin, UserManager.DISALLOW_FACTORY_RESET);
dpm.addUserRestriction(admin, UserManager.DISALLOW_ADD_USER);
dpm.addUserRestriction(admin, UserManager.DISALLOW_INSTALL_APPS);
dpm.addUserRestriction(admin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
dpm.addUserRestriction(admin, UserManager.DISALLOW_USB_FILE_TRANSFER);
// 5. 设置不可移除
dpm.setUninstallBlocked(admin, context.getPackageName(), true);
// 6. 持续运行
dpm.setLockTaskPackages(admin, packages);
}
/**
* 启动Kiosk应用
*/
public void launchKioskApp(Context context) {
Intent intent = new Intent(context, KioskActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
}
}
典型应用:
- 零售店POS系统
- 餐厅点餐机
- 银行ATM机
- 酒店自助入住机
- 博物馆导览终端
7.2 企业MDM管理
场景描述: 企业IT管理员通过MDM(Mobile Device Management)系统远程管理设备。
实现架构:
┌──────────────────┐
│ MDM Server │
│ (Cloud) │
└────────┬─────────┘
│ HTTPS/WebSocket
│
┌────────▼─────────┐
│ MDM Agent │
│ (Device Admin) │
├──────────────────┤
│ • Policy Sync │
│ • Lock Task Mgmt │
│ • App Whitelist │
│ • Remote Control │
└────────┬─────────┘
│
┌────────▼─────────┐
│ Managed Apps │
│ (在Lock Task中) │
└──────────────────┘
MDM Agent实现示例:
java
public class MdmAgent extends DeviceAdminReceiver {
/**
* 从MDM服务器同步策略
*/
public void syncPolicies(Context context) {
// 1. 获取服务器策略
MdmPolicy policy = fetchPolicyFromServer();
// 2. 应用Lock Task策略
applyLockTaskPolicy(context, policy);
// 3. 应用其他策略
applySecurityPolicy(context, policy);
}
private void applyLockTaskPolicy(Context context, MdmPolicy policy) {
DevicePolicyManager dpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName admin = new ComponentName(context, MdmAgent.class);
// 设置白名单
if (policy.lockTaskPackages != null) {
dpm.setLockTaskPackages(admin, policy.lockTaskPackages);
}
// 设置功能
if (policy.lockTaskFeatures != null) {
dpm.setLockTaskFeatures(admin, policy.lockTaskFeatures);
}
// 自动启动Lock Task(如果配置)
if (policy.autoStartLockTask) {
startManagedApps(context, policy.lockTaskPackages[0]);
}
}
/**
* 监控Lock Task状态
*/
public void monitorLockTaskState(Context context) {
ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
int state = am.getLockTaskModeState();
// 上报状态到MDM服务器
reportStateToServer(state);
// 如果意外退出,重新启动
if (state == ActivityManager.LOCK_TASK_MODE_NONE &&
shouldBeInLockTask()) {
restartLockTask(context);
}
}
}
使用场景:
- 企业办公设备管理
- 员工移动设备控制
- 合规性管理
- 数据保护
7.3 教育场景(考试模式)
场景描述: 在考试期间,限制学生设备只能访问考试应用,防止作弊。
考试模式实现:
java
public class ExamModeManager {
/**
* 启动考试模式
*/
public void startExamMode(Context context, String examAppPackage) {
DevicePolicyManager dpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName admin = getAdminComponent(context);
// 1. 设置考试应用为白名单
String[] packages = {examAppPackage};
dpm.setLockTaskPackages(admin, packages);
// 2. 配置受限功能(允许查看时间,禁止通知)
int features = DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO
| DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
dpm.setLockTaskFeatures(admin, features);
// 3. 禁用网络(可选)
if (shouldDisableNetwork()) {
dpm.addUserRestriction(admin, UserManager.DISALLOW_CONFIG_WIFI);
dpm.addUserRestriction(admin, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
}
// 4. 启动考试应用
Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(examAppPackage);
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
// 5. 记录考试开始时间
saveExamStartTime(System.currentTimeMillis());
}
/**
* 结束考试模式
*/
public void endExamMode(Context context) {
DevicePolicyManager dpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName admin = getAdminComponent(context);
// 1. 清除白名单
dpm.setLockTaskPackages(admin, new String[]{});
// 2. 恢复网络
dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_WIFI);
dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
// 3. 停止Lock Task
ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
if (am.isInLockTaskMode()) {
// 需要在考试应用中调用stopLockTask()
broadcastStopExam(context);
}
// 4. 记录考试结束时间
saveExamEndTime(System.currentTimeMillis());
}
/**
* 监控考试状态
*/
public void monitorExamStatus(Context context) {
// 检查考试时长
long duration = System.currentTimeMillis() - getExamStartTime();
long maxDuration = getMaxExamDuration();
if (duration >= maxDuration) {
// 自动结束考试
endExamMode(context);
notifyExamTimeout(context);
}
// 检查是否意外退出
ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
if (am.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_NONE &&
isExamInProgress()) {
// 记录违规并重新启动
logViolation("Exam mode exited unexpectedly");
restartExamMode(context);
}
}
}
考试应用实现:
java
public class ExamActivity extends Activity {
private CountDownTimer mTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exam);
// 隐藏系统UI
hideSystemUI();
// 启动倒计时
startCountdown();
}
@Override
protected void onResume() {
super.onResume();
// 自动进入Lock Task
startLockTask();
// 注册监听器
registerExamBroadcastReceiver();
}
private void startCountdown() {
long examDuration = getIntent().getLongExtra("duration", 3600000); // 默认1小时
mTimer = new CountDownTimer(examDuration, 1000) {
@Override
public void onTick(long millisUntilFinished) {
updateTimeDisplay(millisUntilFinished);
}
@Override
public void onFinish() {
finishExam();
}
}.start();
}
private void finishExam() {
// 1. 收集答案
submitAnswers();
// 2. 停止Lock Task
stopLockTask();
// 3. 关闭应用
finish();
}
@Override
public void onBackPressed() {
// 考试期间禁用返回键
showWarning("考试进行中,不能退出");
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mTimer != null) {
mTimer.cancel();
}
}
}
使用场景:
- 在线考试
- 技能测试
- 认证考核
- 课堂测验
7.4 公共展示设备
场景描述: 商场、展览会等公共场所的信息展示设备。
实现特点:
java
public class DisplayKioskActivity extends Activity {
private Handler mIdleHandler = new Handler();
private Runnable mIdleRunnable;
private static final long IDLE_TIMEOUT = 60000; // 1分钟无操作
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display);
// 启动Lock Task
startLockTask();
// 设置全屏
setupFullScreen();
// 启动空闲计时器
resetIdleTimer();
// 设置交互监听
setupInteractionListeners();
}
private void setupFullScreen() {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
hideSystemUI();
}
private void setupInteractionListeners() {
View rootView = findViewById(android.R.id.content);
rootView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
return false;
});
}
@Override
public void onUserInteraction() {
super.onUserInteraction();
resetIdleTimer();
}
private void resetIdleTimer() {
mIdleHandler.removeCallbacks(mIdleRunnable);
mIdleRunnable = () -> {
// 空闲超时 - 返回主页
returnToHomePage();
};
mIdleHandler.postDelayed(mIdleRunnable, IDLE_TIMEOUT);
}
private void returnToHomePage() {
// 重置到初始页面
Intent intent = new Intent(this, DisplayKioskActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
private void hideSystemUI() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
);
}
}
使用场景:
- 商场导航屏
- 展览信息亭
- 酒店大堂信息屏
- 机场指引屏
7.5 其他实际应用场景
7.5.1 医疗设备
java
// 医疗设备专用模式
public class MedicalDeviceManager {
public void setupMedicalMode(Context context) {
// 配置高安全性的Lock Task
// - 禁止所有系统功能
// - 仅允许医疗应用
// - 启用数据加密
// - 合规性审计日志
}
}
特点:
- HIPAA合规
- 患者隐私保护
- 数据完整性
- 审计追踪
7.5.2 车载系统
java
// 车载信息娱乐系统
public class VehicleKioskManager {
public void setupDrivingMode(Context context) {
// 驾驶模式
// - 限制分散注意力的应用
// - 允许导航和音乐
// - 语音控制优先
}
}
特点:
- 驾驶安全
- 限制交互
- 语音控制
- 车辆集成
7.5.3 工业控制
java
// 工业控制终端
public class IndustrialControlManager {
public void setupControlMode(Context context) {
// 工业控制模式
// - 仅控制应用
// - 防误操作
// - 实时监控
// - 日志记录
}
}
特点:
- 操作安全
- 实时性
- 稳定性
- 防护等级
8. AOSP其他窗口模式对比
8.1 模式概览
Android系统提供了多种窗口和任务模式,各有不同的用途和特性。
| 模式 | 引入版本 | 主要用途 | 限制级别 |
|---|---|---|---|
| Lock Task | 5.0 | 设备锁定、Kiosk | 高 |
| Screen Pinning | 5.0 | 临时固定 | 中 |
| Multi-Window | 7.0 | 分屏多任务 | 低 |
| Freeform | 7.0 | 自由窗口 | 低 |
| Picture-in-Picture | 8.0 | 画中画 | 低 |
| Home Mode | All | 启动器 | 无 |
| Recents Mode | All | 最近任务 | 无 |
8.2 详细对比
8.2.1 Lock Task vs Screen Pinning
| 特性 | Lock Task (LOCKED) | Screen Pinning (PINNED) |
|---|---|---|
| 权限要求 | DeviceOwner/ProfileOwner | 无(用户确认) |
| 启动方式 | API或自动(白名单) | API或最近任务菜单 |
| 退出方式 | 代码或管理员 | Back+Recents手势 |
| 多任务 | 支持白名单多任务 | 仅单任务 |
| UI限制 | 完全可配置 | 固定限制 |
| 状态栏 | 可完全隐藏 | 部分限制 |
| 导航栏 | 可配置 | 受限但可见 |
| 应用场景 | 企业、Kiosk | 演示、临时锁定 |
8.2.2 Multi-Window模式(分屏)
特点:
- 同时显示两个应用
- 可调整分割比例
- 支持拖拽共享数据
启动方式:
java
// 在分屏模式中启动Activity
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT |
Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Manifest配置:
xml
<activity
android:name=".MainActivity"
android:resizeableActivity="true"
android:supportsPictureInPicture="false" />
与Lock Task对比:
- Multi-Window允许用户自由切换,Lock Task限制切换
- Multi-Window是生产力工具,Lock Task是安全工具
- Multi-Window可以与Lock Task共存(白名单应用可以分屏)
8.2.3 Freeform模式(自由窗口)
特点:
- 类似桌面系统的窗口模式
- 可移动、调整大小
- 支持多窗口重叠
启动方式:
java
// 以Freeform模式启动
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(
WindowConfiguration.WINDOWING_MODE_FREEFORM);
Intent intent = new Intent(this, FreeformActivity.class);
startActivity(intent, options.toBundle());
开启Freeform (需要开发者选项):
bash
adb shell settings put global enable_freeform_support 1
adb shell settings put global force_resizable_activities 1
与Lock Task对比:
- Freeform提供最大自由度,Lock Task提供最大限制
- Freeform适合生产环境,Lock Task适合专用环境
- 二者互斥(Lock Task启动时会退出Freeform)
8.2.4 Picture-in-Picture模式(画中画)
特点:
- 小窗口悬浮显示
- 主要用于视频播放
- 可以在其他应用上层显示
实现示例:
java
public class VideoActivity extends Activity {
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
// 进入PIP模式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PictureInPictureParams params =
new PictureInPictureParams.Builder()
.setAspectRatio(new Rational(16, 9))
.build();
enterPictureInPictureMode(params);
}
}
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
Configuration newConfig) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
if (isInPictureInPictureMode) {
// 隐藏UI控件
hideControls();
} else {
// 显示完整UI
showControls();
}
}
}
Manifest配置:
xml
<activity
android:name=".VideoActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:resizeableActivity="true" />
与Lock Task交互:
- Lock Task启动时会移除PIP窗口(源码:
LockTaskController.java: Line 678) - PIP不能在LOCKED模式中使用
- PINNED模式可能允许PIP(取决于配置)
8.2.5 模式共存矩阵
| 当前模式 | 可启动Lock Task | 可启动Multi-Window | 可启动Freeform | 可启动PIP |
|---|---|---|---|---|
| Normal | ✓ | ✓ | ✓ | ✓ |
| Lock Task (LOCKED) | ✓(白名单) | ✓(白名单) | ✗ | ✗ |
| Screen Pinning | ✗ | ✗ | ✗ | ✗ |
| Multi-Window | ✓ | ✓ | ✓ | ✓ |
| Freeform | ✓ | ✓ | ✓ | ✓ |
| PIP | ✗ | ✓ | ✓ | - |
9. 版本演进历史
9.1 Android 5.0 (Lollipop) - 首次引入
引入功能:
- Lock Task Mode基础框架
- Screen Pinning用户功能
- DevicePolicyManager支持
API变更:
java
// Activity新增方法
public void startLockTask()
public void stopLockTask()
// DevicePolicyManager新增方法
public void setLockTaskPackages(ComponentName admin, String[] packages)
public String[] getLockTaskPackages(ComponentName admin)
public boolean isLockTaskPermitted(String pkg)
// ActivityManager新增方法
public boolean isInLockTaskMode()
Manifest属性:
xml
android:lockTaskMode="normal|never|always|if_whitelisted"
9.2 Android 6.0 (Marshmallow) - 功能增强
新增功能:
- Lock Task Feature标志
- 更细粒度的UI控制
API变更:
java
// DevicePolicyManager新增
public void setLockTaskFeatures(ComponentName admin, int flags)
public int getLockTaskFeatures(ComponentName admin)
新增Feature标志:
LOCK_TASK_FEATURE_SYSTEM_INFOLOCK_TASK_FEATURE_NOTIFICATIONSLOCK_TASK_FEATURE_HOMELOCK_TASK_FEATURE_OVERVIEWLOCK_TASK_FEATURE_GLOBAL_ACTIONS
9.3 Android 7.0 (Nougat) - 多窗口支持
变更:
- Lock Task与Multi-Window的兼容性改进
- 白名单应用可以在Lock Task中分屏
行为变更:
- Lock Task启动时不再强制全屏
- 支持白名单应用之间的分屏
9.4 Android 8.0 (Oreo) - Treble架构
变更:
- Lock Task逻辑重构以适配Treble
- 改进与SystemUI的交互
新增:
LOCK_TASK_FEATURE_KEYGUARD支持
9.5 Android 9.0 (Pie) - 手势导航
变更:
- 支持手势导航系统
- Screen Pinning手势适配
行为变更:
- 手势导航模式下的Screen Pinning退出手势调整
9.6 Android 10 (Q) - 作用域存储
变更:
- Lock Task与作用域存储的兼容性
- 权限模型更新
9.7 Android 11 ® - One-time权限
变更:
- 一次性权限与Lock Task的交互
- 自动重置权限的例外处理
9.8 Android 12 (S) - Material You
变更:
- SystemUI重构对Lock Task的影响
LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK新增
新增Feature:
java
public static final int LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK = 1 << 6;
9.9 Android 13 (T) - 隐私增强
变更:
- 通知权限与Lock Task的交互
- 照片选择器的Lock Task支持
9.10 Android 14 (U) - 企业功能增强
变更:
- Device Policy API现代化
- Lock Task配置简化
9.11 Android 15 (V) - 当前版本
当前状态:
- 代码位置:
/frameworks/base/services/core/java/com/android/server/wm/LockTaskController.java - 核心逻辑稳定,主要是性能优化和Bug修复
- 支持最新的隐私和安全特性
主要改进:
- 性能优化:减少状态切换开销
- 安全增强:更严格的权限检查
- 兼容性:与最新UI特性兼容
9.12 版本兼容性总结
| 功能 | 最低支持版本 | 备注 |
|---|---|---|
| 基础Lock Task | 5.0 (API 21) | |
| Screen Pinning | 5.0 (API 21) | |
| Lock Task Features | 6.0 (API 23) | |
| Multi-Window Lock Task | 7.0 (API 24) | |
| Keyguard Feature | 8.0 (API 26) | |
| Block Activity Start | 12.0 (API 31) |
向后兼容性注意事项:
java
public class LockTaskCompat {
public static void startLockTask(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.startLockTask();
} else {
// 不支持Lock Task
Toast.makeText(activity,
"Lock Task需要Android 5.0+",
Toast.LENGTH_SHORT).show();
}
}
public static void setLockTaskFeatures(DevicePolicyManager dpm,
ComponentName admin,
int features) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
dpm.setLockTaskFeatures(admin, features);
} else {
// Android 6.0以下不支持Feature配置
}
}
}
10. 最佳实践与注意事项
10.1 设计原则
10.1.1 用户体验
DO (推荐):
- 提供清晰的进入/退出提示
- 在合适的时机自动启动Lock Task
- 保留必要的系统功能(如时钟)
- 提供紧急退出机制
DON'T (不推荐):
- 不要突然进入Lock Task而不通知用户
- 不要完全隐藏所有系统信息
- 不要阻止合法的退出操作
- 不要在不合适的场景使用
10.1.2 安全性
最佳实践:
java
public class SecureLockTaskManager {
/**
* 安全地启动Lock Task
*/
public boolean startLockTaskSecurely(Context context, Activity activity) {
// 1. 验证权限
if (!hasRequiredPermissions(context)) {
Log.e(TAG, "Missing required permissions");
return false;
}
// 2. 检查设备状态
if (!isDeviceSecure(context)) {
Log.w(TAG, "Device is not secure");
// 可选:要求用户设置锁屏
return false;
}
// 3. 验证应用签名(防止重打包)
if (!verifyAppSignature(context)) {
Log.e(TAG, "Invalid app signature");
return false;
}
// 4. 记录审计日志
logAuditEvent("LOCK_TASK_STARTED", activity.getClass().getName());
// 5. 启动Lock Task
try {
activity.startLockTask();
return true;
} catch (SecurityException e) {
Log.e(TAG, "Failed to start lock task", e);
return false;
}
}
/**
* 检查设备是否安全
*/
private boolean isDeviceSecure(Context context) {
KeyguardManager km = (KeyguardManager)
context.getSystemService(Context.KEYGUARD_SERVICE);
return km != null && km.isDeviceSecure();
}
}
10.1.3 性能优化
注意事项:
- 避免频繁切换:
java
// BAD: 频繁切换
for (int i = 0; i < 10; i++) {
startLockTask();
Thread.sleep(100);
stopLockTask();
}
// GOOD: 一次性配置
startLockTask();
// 保持Lock Task状态
- 预加载资源:
java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 在启动Lock Task前预加载资源
preloadResources();
// 然后启动Lock Task
startLockTask();
}
- 监听生命周期:
java
@Override
protected void onStop() {
super.onStop();
// 如果Activity停止但Lock Task还在
ActivityManager am = (ActivityManager)
getSystemService(Context.ACTIVITY_SERVICE);
if (am.isInLockTaskMode() && !isFinishing()) {
// 确保Activity回到前台
moveTaskToFront();
}
}
10.2 常见问题与解决方案
10.2.1 问题: 无法启动Lock Task
症状:
SecurityException: Calling package does not have permission
解决方案:
- 检查Manifest配置:
xml
<activity
android:name=".MainActivity"
android:lockTaskMode="normal" <!-- 确保配置正确 -->
android:exported="true" />
- 检查是否在白名单中:
java
DevicePolicyManager dpm = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
String packageName = getPackageName();
boolean isAllowed = dpm.isLockTaskPermitted(packageName);
if (!isAllowed) {
// 添加到白名单
ComponentName admin = getAdminComponent();
dpm.setLockTaskPackages(admin, new String[]{packageName});
}
- 检查DeviceOwner状态:
bash
# 查看DeviceOwner
adb shell dpm list-owners
# 如果没有,设置DeviceOwner (需要未激活设备)
adb shell dpm set-device-owner com.example.app/.AdminReceiver
10.2.2 问题: Lock Task意外退出
症状 :
Lock Task模式自动退出,返回到主屏幕
原因分析:
- 任务被清除
- 应用崩溃
- 系统资源不足
- 白名单配置变更
解决方案:
java
public class LockTaskMonitor extends Service {
private Handler mHandler = new Handler();
private Runnable mCheckRunnable;
@Override
public void onCreate() {
super.onCreate();
startMonitoring();
}
private void startMonitoring() {
mCheckRunnable = new Runnable() {
@Override
public void run() {
ActivityManager am = (ActivityManager)
getSystemService(Context.ACTIVITY_SERVICE);
// 检查Lock Task状态
int state = am.getLockTaskModeState();
if (state == ActivityManager.LOCK_TASK_MODE_NONE) {
// Lock Task已退出,重新启动
Log.w(TAG, "Lock Task exited unexpectedly, restarting");
restartLockTask();
}
// 继续监控
mHandler.postDelayed(this, 5000); // 每5秒检查一次
}
};
mHandler.post(mCheckRunnable);
}
private void restartLockTask() {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mCheckRunnable);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
在Manifest中配置持久服务:
xml
<service
android:name=".LockTaskMonitor"
android:enabled="true"
android:exported="false"
android:persistent="true" />
10.2.3 问题: 状态栏未正确隐藏
症状 :
进入Lock Task后状态栏仍然可见
解决方案:
- 配置Lock Task Features:
java
// 确保未启用SYSTEM_INFO
DevicePolicyManager dpm = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName admin = getAdminComponent();
int features = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
dpm.setLockTaskFeatures(admin, features);
- 使用沉浸式模式:
java
@Override
protected void onResume() {
super.onResume();
// 启动Lock Task
startLockTask();
// 隐藏系统UI
hideSystemUI();
}
private void hideSystemUI() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
- 监听UI可见性变化:
java
decorView.setOnSystemUiVisibilityChangeListener(visibility -> {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// 系统UI重新出现,再次隐藏
decorView.postDelayed(this::hideSystemUI, 100);
}
});
10.2.4 问题: 无法退出Lock Task
症状 :
调用stopLockTask()后没有效果
解决方案:
- 检查调用者UID:
java
// 只有启动Lock Task的Activity才能停止
// 确保在正确的Activity中调用stopLockTask()
public class MainActivity extends Activity {
private boolean mIsLockTaskStarter = false;
@Override
protected void onResume() {
super.onResume();
startLockTask();
mIsLockTaskStarter = true; // 标记为启动者
}
public void exitLockTask() {
if (mIsLockTaskStarter) {
stopLockTask();
} else {
// 不是启动者,需要finish Activity
finish();
}
}
}
- 检查是否为根任务:
java
// 如果是根任务且是LOCKED模式,需要特殊处理
ActivityManager am = (ActivityManager)
getSystemService(Context.ACTIVITY_SERVICE);
int mode = am.getLockTaskModeState();
if (mode == ActivityManager.LOCK_TASK_MODE_LOCKED) {
// LOCKED模式可能需要DeviceOwner权限才能退出
// 或者需要先移除白名单
}
- 使用ADB强制退出 (调试用):
bash
# 查看当前Lock Task状态
adb shell dumpsys activity | grep "mLockTaskMode"
# 强制停止Lock Task
adb shell am stop-lock-task-mode
# 或者结束应用
adb shell am force-stop com.example.app
10.3 测试指南
10.3.1 单元测试
java
@RunWith(AndroidJUnit4.class)
public class LockTaskControllerTest {
private Context mContext;
private ActivityManager mActivityManager;
private DevicePolicyManager mDevicePolicyManager;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getInstrumentation()
.getTargetContext();
mActivityManager = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
mDevicePolicyManager = (DevicePolicyManager)
mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
}
@Test
public void testLockTaskMode() {
// 测试Lock Task状态
int initialState = mActivityManager.getLockTaskModeState();
assertEquals(ActivityManager.LOCK_TASK_MODE_NONE, initialState);
// 启动Lock Task (需要合适的权限)
// ...
// 验证状态变更
// ...
}
@Test
public void testLockTaskPackages() {
ComponentName admin = getAdminComponent();
String testPackage = "com.example.test";
// 设置白名单
mDevicePolicyManager.setLockTaskPackages(
admin, new String[]{testPackage});
// 验证
String[] packages = mDevicePolicyManager.getLockTaskPackages(admin);
assertEquals(1, packages.length);
assertEquals(testPackage, packages[0]);
// 检查权限
boolean isPermitted = mDevicePolicyManager
.isLockTaskPermitted(testPackage);
assertTrue(isPermitted);
}
@Test
public void testLockTaskFeatures() {
ComponentName admin = getAdminComponent();
int features = DevicePolicyManager.LOCK_TASK_FEATURE_HOME
| DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
// 设置功能
mDevicePolicyManager.setLockTaskFeatures(admin, features);
// 验证
int retrievedFeatures = mDevicePolicyManager
.getLockTaskFeatures(admin);
assertEquals(features, retrievedFeatures);
}
}
10.3.2 集成测试
java
@RunWith(AndroidJUnit4.class)
@LargeTest
public class LockTaskIntegrationTest {
@Rule
public ActivityScenarioRule<MainActivity> mActivityRule =
new ActivityScenarioRule<>(MainActivity.class);
@Test
public void testLockTaskLifecycle() {
mActivityRule.getScenario().onActivity(activity -> {
// 1. 启动Lock Task
activity.startLockTask();
// 2. 验证状态
ActivityManager am = (ActivityManager)
activity.getSystemService(Context.ACTIVITY_SERVICE);
int mode = am.getLockTaskModeState();
assertNotEquals(ActivityManager.LOCK_TASK_MODE_NONE, mode);
// 3. 模拟用户操作
// ...
// 4. 停止Lock Task
activity.stopLockTask();
// 5. 验证退出
mode = am.getLockTaskModeState();
assertEquals(ActivityManager.LOCK_TASK_MODE_NONE, mode);
});
}
@Test
public void testLockTaskWithMultipleActivities() {
mActivityRule.getScenario().onActivity(mainActivity -> {
mainActivity.startLockTask();
// 启动第二个Activity
Intent intent = new Intent(mainActivity, SecondActivity.class);
mainActivity.startActivity(intent);
// 验证Lock Task仍然激活
// ...
});
}
@Test
public void testLockTaskRestrictions() {
mActivityRule.getScenario().onActivity(activity -> {
activity.startLockTask();
// 尝试启动系统设置 (应该被阻止)
Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
try {
activity.startActivity(settingsIntent);
fail("Should not be able to start Settings in Lock Task");
} catch (SecurityException e) {
// Expected
}
});
}
}
10.3.3 CTS测试
Android CTS (Compatibility Test Suite) 包含Lock Task相关测试:
测试文件位置:
/cts/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.kt/cts/tests/framework/base/windowmanager/src/android/server/wm/other/LockTaskModeTests.java
运行CTS测试:
bash
# 运行所有Lock Task测试
adb shell am instrument -w -e class android.server.wm.other.LockTaskModeTests \
com.android.cts.windowmanager/androidx.test.runner.AndroidJUnitRunner
# 运行特定测试
adb shell am instrument -w \
-e class android.server.wm.other.LockTaskModeTests#testLockTaskMode \
com.android.cts.windowmanager/androidx.test.runner.AndroidJUnitRunner
10.4 调试技巧
10.4.1 日志分析
bash
# 查看Lock Task相关日志
adb logcat -s ActivityTaskManager:* LockTaskController:* DevicePolicyManager:*
# 使用ProtoLog (需要开启)
adb shell cmd window logging enable-text WM_DEBUG_LOCKTASK
adb logcat -s WindowManager:*
# 查看详细状态
adb shell dumpsys activity | grep -A 20 "LockTask"
10.4.2 实时监控
bash
# 监控Lock Task模式变化
watch -n 1 'adb shell dumpsys activity | grep "mLockTaskMode"'
# 监控任务栈
adb shell dumpsys activity activities | grep "TaskRecord"
10.4.3 开发者工具
java
public class LockTaskDebugHelper {
/**
* 打印Lock Task详细状态
*/
public static void dumpLockTaskState(Context context) {
ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
DevicePolicyManager dpm = (DevicePolicyManager)
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
Log.d(TAG, "========== Lock Task State ==========");
Log.d(TAG, "Mode: " + getLockTaskModeString(
am.getLockTaskModeState()));
Log.d(TAG, "Is In Lock Task: " + am.isInLockTaskMode());
ComponentName admin = getAdminComponent(context);
if (admin != null) {
String[] packages = dpm.getLockTaskPackages(admin);
Log.d(TAG, "Whitelist Packages: " + Arrays.toString(packages));
int features = dpm.getLockTaskFeatures(admin);
Log.d(TAG, "Features: " + getLockTaskFeaturesString(features));
}
Log.d(TAG, "=====================================");
}
private static String getLockTaskModeString(int mode) {
switch (mode) {
case ActivityManager.LOCK_TASK_MODE_NONE:
return "NONE";
case ActivityManager.LOCK_TASK_MODE_LOCKED:
return "LOCKED";
case ActivityManager.LOCK_TASK_MODE_PINNED:
return "PINNED";
default:
return "UNKNOWN(" + mode + ")";
}
}
private static String getLockTaskFeaturesString(int features) {
if (features == DevicePolicyManager.LOCK_TASK_FEATURE_NONE) {
return "NONE";
}
List<String> featureList = new ArrayList<>();
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO) != 0) {
featureList.add("SYSTEM_INFO");
}
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS) != 0) {
featureList.add("NOTIFICATIONS");
}
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_HOME) != 0) {
featureList.add("HOME");
}
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW) != 0) {
featureList.add("OVERVIEW");
}
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS) != 0) {
featureList.add("GLOBAL_ACTIONS");
}
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0) {
featureList.add("KEYGUARD");
}
if ((features & DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK) != 0) {
featureList.add("BLOCK_ACTIVITY_START");
}
return TextUtils.join(" | ", featureList);
}
}
10.5 性能考虑
- 启动时间: Lock Task启动会有轻微延迟(通常<100ms)
- 内存占用: Lock Task本身内存开销很小
- 电池影响 : 如果使用
FLAG_KEEP_SCREEN_ON,注意电池消耗 - 系统资源: LOCKED模式会禁用某些系统服务,可能提升性能
10.6 安全建议
- 永远验证调用者: 不要假设调用者是可信的
- 审计日志: 记录所有Lock Task操作
- 紧急退出: 提供管理员级别的紧急退出机制
- 数据保护: 在Lock Task中处理敏感数据时加密
- 证书pinning: 如果Lock Task应用需要网络通信,使用证书pinning
总结
Lock Task模式是Android提供的强大企业和专用设备管理功能。通过合理使用,可以实现:
- Kiosk模式: 将设备限制为单一或多个特定应用
- 企业管理: 通过MDM远程管理设备
- 安全隔离: 防止用户访问未授权功能
- 临时锁定: Screen Pinning提供灵活的临时锁定
关键要点:
- Lock Task有三种模式:NONE、LOCKED、PINNED
- LOCKED模式需要DeviceOwner/ProfileOwner权限
- 通过Lock Task Features可以细粒度控制系统功能
- 合理配置可以平衡安全性和用户体验
参考资源:
- Android Enterprise官方文档
- DevicePolicyManager API文档
- Activity Lock Task API
- AOSP源码:
/frameworks/base/services/core/java/com/android/server/wm/LockTaskController.java
致敬前辈,砥砺前行!