Android 15 Lock Task 模式深度分析(第一部分)

Android 15 Lock Task 模式深度分析(第一部分)


目录

  1. [Lock Task 模式概述](#Lock Task 模式概述)
  2. 核心架构与实现
  3. 代码流程分析
  4. 关键类与方法
  5. 应用层使用方法
  6. 企业管理配置
  7. 使用场景
  8. AOSP其他窗口模式对比
  9. 版本演进历史
  10. 最佳实践与注意事项

1. Lock Task 模式概述

1.1 什么是Lock Task模式

Lock Task模式是Android从5.0(Lollipop)开始引入的一种特殊任务锁定机制,主要用于企业环境和专用设备场景。它允许设备管理员或应用将设备锁定到特定的应用或任务,限制用户访问其他应用或系统功能。

核心特性

  • 任务锁定: 将用户限制在特定应用或任务集合中
  • 系统UI限制: 可配置地禁用状态栏、通知、导航按钮等
  • 安全隔离: 防止用户切换到其他应用或访问敏感功能
  • 可配置性: 支持细粒度的功能控制

1.2 三种Lock Task模式

根据源码 /frameworks/base/core/java/android/app/ActivityManager.java,系统定义了三种Lock Task状态:

java 复制代码
// ActivityManager.java: Line 1231-1241
public static final int LOCK_TASK_MODE_NONE = 0;    // 未启用锁定任务模式
public static final int LOCK_TASK_MODE_LOCKED = 1;  // 完全锁定模式(企业模式)
public static final int LOCK_TASK_MODE_PINNED = 2;  // 屏幕固定模式(Screen Pinning)
1.2.1 LOCK_TASK_MODE_NONE (0)
  • 正常模式,没有任务锁定
  • 用户可以自由切换应用和访问所有系统功能
1.2.2 LOCK_TASK_MODE_LOCKED (1)
  • 完全锁定模式(企业/Kiosk模式)
  • 需要DeviceOwner或ProfileOwner权限
  • 设备完全锁定在白名单应用中
  • 系统功能根据DevicePolicyManager配置进行限制
  • 通常用于企业专用设备、自助终端等场景

特点

  • 无法通过物理按键退出(除非配置允许)
  • 可配置允许的系统功能(Home、Recents、通知等)
  • 需要管理员权限才能退出
  • 支持多任务白名单
1.2.3 LOCK_TASK_MODE_PINNED (2)
  • 屏幕固定模式(Screen Pinning)
  • 普通应用可以调用,用户需要确认
  • 锁定单个任务到屏幕
  • 用户可以通过特定手势退出(同时按Back+Recents或根据设置)
  • 主要用于临时演示、考试模式等

特点

  • 需要用户明确同意
  • 可以通过系统设置的手势退出
  • 退出后可选择是否需要解锁设备
  • 仅锁定单个任务

1.3 与其他模式的区别

特性 Lock Task (Locked) Screen Pinning 正常模式
权限要求 DeviceOwner/ProfileOwner 无(用户确认)
退出方式 代码或管理员 手势组合 无限制
多任务支持 支持白名单多任务 仅单任务 无限制
系统UI控制 完全可配置 固定限制 无限制
典型场景 Kiosk、MDM 演示、考试 日常使用

2. 核心架构与实现

2.1 架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     Application Layer                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Activity   │  │DevicePolicy  │  │Settings App  │      │
│  │startLockTask │  │   Manager    │  │Screen Pinning│      │
│  │stopLockTask  │  │              │  │              │      │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘      │
└─────────┼──────────────────┼──────────────────┼─────────────┘
          │                  │                  │
          │                  │                  │
┌─────────▼──────────────────▼──────────────────▼─────────────┐
│                    Framework Layer                           │
│  ┌──────────────────────────────────────────────────────┐   │
│  │        ActivityTaskManagerService (ATMS)             │   │
│  │  startLockTaskMode() / stopLockTaskMode()            │   │
│  └─────────────────────┬────────────────────────────────┘   │
│                        │                                     │
│  ┌─────────────────────▼────────────────────────────────┐   │
│  │           LockTaskController (核心控制器)            │   │
│  │  • 模式状态管理 (mLockTaskModeState)                 │   │
│  │  • 任务列表维护 (mLockTaskModeTasks)                 │   │
│  │  • 白名单管理 (mLockTaskPackages)                    │   │
│  │  • 权限检查 (getLockTaskAuth)                        │   │
│  │  • UI状态控制 (setStatusBarState/setKeyguardState)   │   │
│  └──────┬──────────┬──────────┬──────────┬───────────────┘   │
│         │          │          │          │                   │
└─────────┼──────────┼──────────┼──────────┼───────────────────┘
          │          │          │          │
┌─────────▼──────────▼──────────▼──────────▼───────────────────┐
│                    System Services                            │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐         │
│  │ StatusBar    │ │WindowManager │ │DevicePolicy  │         │
│  │   Service    │ │   Service    │ │   Service    │         │
│  └──────────────┘ └──────────────┘ └──────────────┘         │
└───────────────────────────────────────────────────────────────┘

2.2 核心类关系

复制代码
ActivityTaskManagerService
    ├── LockTaskController (主控制器)
    │   ├── mLockTaskModeTasks: ArrayList<Task>
    │   ├── mLockTaskPackages: SparseArray<String[]>
    │   ├── mLockTaskFeatures: SparseIntArray
    │   └── mLockTaskModeState: int
    │
    ├── Task
    │   ├── mLockTaskAuth: int (权限级别)
    │   └── mLockTaskUid: int (启动者UID)
    │
    └── ActivityRecord
        └── lockTaskLaunchMode: int (Manifest配置)

2.3 关键文件路径

文件 路径 作用
LockTaskController.java /frameworks/base/services/core/java/com/android/server/wm/ 核心控制器,管理Lock Task状态和逻辑
ActivityTaskManagerService.java /frameworks/base/services/core/java/com/android/server/wm/ ATMS,提供公开接口
Activity.java /frameworks/base/core/java/android/app/ 应用层API(startLockTask/stopLockTask)
ActivityManager.java /frameworks/base/core/java/android/app/ 定义常量和状态
ActivityInfo.java /frameworks/base/core/java/android/content/pm/ 定义lockTaskMode属性
DevicePolicyManager.java /frameworks/base/core/java/android/app/admin/ 企业策略管理
Task.java /frameworks/base/services/core/java/com/android/server/wm/ 任务类,包含锁定授权信息
ScreenPinningRequest.java /frameworks/base/packages/SystemUI/src/com/android/systemui/recents/ SystemUI屏幕固定请求UI

3. 代码流程分析

3.1 启动Lock Task流程

3.1.1 应用层调用流程
复制代码
Application
    │
    ├─ Activity.startLockTask()
    │   └─ frameworks/base/core/java/android/app/Activity.java: Line 9456
    │
    ├─ ActivityClient.getInstance().startLockTaskModeByToken(mToken)
    │   └─ 通过Binder IPC调用服务端
    │
    ├─ ActivityTaskManagerService.startLockTaskModeByToken()
    │   └─ frameworks/base/services/core/java/com/android/server/wm/
    │       ActivityTaskManagerService.java
    │
    └─ ATMS.startLockTaskMode(task, isSystemCaller=false)
        └─ Line 2591
3.1.2 系统层调用流程(Screen Pinning)
复制代码
SystemUI (ScreenPinningRequest)
    │
    ├─ User clicks "Start" button
    │   └─ ScreenPinningRequest.onClick()
    │       └─ Line 188-193
    │
    ├─ ActivityTaskManager.getService().startSystemLockTaskMode(taskId)
    │   └─ Line 190
    │
    ├─ ATMS.startSystemLockTaskMode(taskId)
    │   └─ Line 2574
    │
    └─ ATMS.startLockTaskMode(task, isSystemCaller=true)
        └─ Line 2591
3.1.3 详细启动流程

源码路径 : frameworks/base/services/core/java/com/android/server/wm/LockTaskController.java

java 复制代码
// Line 648-684
void startLockTaskMode(@NonNull Task task, boolean isSystemCaller, int callingUid) {
    // 步骤1: 检查任务授权
    if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
        return; // 任务不允许锁定
    }

    // 步骤2: 处理非系统调用
    if (!isSystemCaller) {
        task.mLockTaskUid = callingUid; // 记录调用者UID

        // 步骤3: 检查授权类型
        if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
            // 需要用户确认 - 显示Screen Pinning对话框
            StatusBarManagerInternal statusBarManager =
                LocalServices.getService(StatusBarManagerInternal.class);
            if (statusBarManager != null) {
                statusBarManager.showScreenPinningRequest(
                    task.mTaskId, task.mUserId);
            }
            return; // 等待用户确认后再次调用
        } else if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
            // 如果当前是Screen Pinning模式,先退出
            stopLockTaskMode(null, true, callingUid);
        }
    }

    // 步骤4: 移除PIP任务(Picture-in-Picture)
    mSupervisor.mRootWindowContainer.removeRootTasksInWindowingModes(
        WINDOWING_MODE_PINNED);

    // 步骤5: 设置Lock Task模式
    int lockTaskModeState = isSystemCaller ?
        LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED;
    setLockTaskMode(task, lockTaskModeState, "startLockTask", true);
}

关键步骤说明

  1. 授权检查 : 验证任务的mLockTaskAuth属性
  2. 用户确认: PINNABLE类型需要显示确认对话框
  3. 模式冲突处理: 处理与Screen Pinning的冲突
  4. PIP清理: 移除画中画任务
  5. 模式设置 : 调用setLockTaskMode()执行实际锁定
3.1.4 setLockTaskMode核心逻辑
java 复制代码
// Line 691-737
private void setLockTaskMode(@NonNull Task task, int lockTaskModeState,
                             String reason, boolean andResume) {
    // 验证授权
    if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
        return;
    }

    // 检查是否违反Lock Task规则
    if (isLockTaskModeViolation(task)) {
        Slog.e(TAG_LOCKTASK, "Attempt to start unauthorized lock task");
        return;
    }

    // 首次进入Lock Task - 初始化
    if (mLockTaskModeTasks.isEmpty() && task.intent != null) {
        mSupervisor.mRecentTasks.onLockTaskModeStateChanged(
            lockTaskModeState, task.mUserId);

        // 在Handler线程启动Lock Task
        mHandler.post(() -> performStartLockTask(
            task.intent.getComponent().getPackageName(),
            task.mUserId,
            lockTaskModeState));
    }

    // 添加任务到锁定列表
    if (!mLockTaskModeTasks.contains(task)) {
        mLockTaskModeTasks.add(task);
    }

    // 设置Lock Task UID
    if (task.mLockTaskUid == -1) {
        task.mLockTaskUid = task.effectiveUid;
    }

    // 将任务移到前台
    if (andResume) {
        mSupervisor.findTaskToMoveToFront(task, 0, null, reason,
            lockTaskModeState != LOCK_TASK_MODE_NONE);
        mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
    }
}
3.1.5 performStartLockTask - 系统状态设置
java 复制代码
// Line 740-760
private void performStartLockTask(String packageName, int userId,
                                  int lockTaskModeState) {
    try {
        // 1. 显示进入Toast(仅Screen Pinning)
        if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
            IStatusBarService statusBar = getStatusBarService();
            if (statusBar != null) {
                statusBar.showPinningEnterExitToast(true);
            }
        }

        // 2. 通知WindowManager
        mWindowManager.onLockTaskStateChanged(lockTaskModeState);

        // 3. 更新内部状态
        mLockTaskModeState = lockTaskModeState;

        // 4. 通知任务变更监听器
        mTaskChangeNotificationController.notifyLockTaskModeChanged(
            mLockTaskModeState);

        // 5. 设置StatusBar状态(禁用相关功能)
        setStatusBarState(lockTaskModeState, userId);

        // 6. 设置Keyguard状态(禁用锁屏)
        setKeyguardState(lockTaskModeState, userId);

        // 7. 通知DevicePolicyManager
        if (getDevicePolicyManager() != null) {
            getDevicePolicyManager().notifyLockTaskModeChanged(
                true, packageName, userId);
        }
    } catch (RemoteException ex) {
        throw new RuntimeException(ex);
    }
}

3.2 退出Lock Task流程

3.2.1 退出流程调用链
复制代码
Application/System
    │
    ├─ Activity.stopLockTask()
    │   └─ ActivityClient.getInstance().stopLockTaskModeByToken(mToken)
    │
    ├─ ATMS.stopLockTaskModeInternal(token, isSystemCaller)
    │   └─ Line 2617
    │
    ├─ LockTaskController.stopLockTaskMode(task, stopAppPinning, uid)
    │   └─ Line 493
    │
    ├─ LockTaskController.clearLockedTask(task)
    │   └─ Line 552
    │
    └─ LockTaskController.performStopLockTask(userId)
        └─ Line 588 (在Handler线程执行)
3.2.2 stopLockTaskMode详细逻辑
java 复制代码
// Line 493-528
void stopLockTaskMode(@Nullable Task task, boolean stopAppPinning,
                      int callingUid) {
    // 步骤1: 检查当前状态
    if (mLockTaskModeState == LOCK_TASK_MODE_NONE) {
        return; // 未处于Lock Task模式
    }

    // 步骤2: 处理Screen Pinning退出
    if (stopAppPinning) {
        if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
            clearLockedTasks("stopAppPinning");
        } else {
            // 完全锁定模式不能通过此方式退出
            Slog.e(TAG_LOCKTASK, "Attempted to stop app pinning while fully locked");
            showLockTaskToast(); // 显示提示
        }
        return;
    }

    // 步骤3: 验证调用者权限
    if (task == null) {
        throw new IllegalArgumentException("can't stop LockTask for null task");
    }

    // 步骤4: 检查UID匹配
    if (callingUid != task.mLockTaskUid &&
        (task.mLockTaskUid != 0 || callingUid != task.effectiveUid)) {
        throw new SecurityException("Invalid uid, expected " +
            task.mLockTaskUid + " callingUid=" + callingUid);
    }

    // 步骤5: 清除任务
    clearLockedTask(task);
}
3.2.3 clearLockedTask - 任务清理
java 复制代码
// Line 552-569
void clearLockedTask(final Task task) {
    if (task == null || mLockTaskModeTasks.isEmpty()) {
        return;
    }

    // 如果是根任务,清除所有锁定任务
    if (task == mLockTaskModeTasks.get(0)) {
        // 反向清除所有子任务
        for (int i = mLockTaskModeTasks.size() - 1; i > 0; --i) {
            clearLockedTask(mLockTaskModeTasks.get(i));
        }
    }

    // 移除任务
    removeLockedTask(task);

    // 如果还有剩余任务,继续
    if (mLockTaskModeTasks.isEmpty()) {
        return;
    }

    // 清理任务内容
    task.performClearTaskForReuse(false);
    mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
}
3.2.4 performStopLockTask - 系统状态恢复
java 复制代码
// Line 588-617
private void performStopLockTask(int userId) {
    // 步骤1: 更新状态(提前更新避免竞态)
    final int oldLockTaskModeState = mLockTaskModeState;
    mLockTaskModeState = LOCK_TASK_MODE_NONE;

    // 步骤2: 通知状态变更
    mTaskChangeNotificationController.notifyLockTaskModeChanged(
        mLockTaskModeState);

    try {
        // 步骤3: 恢复StatusBar
        setStatusBarState(mLockTaskModeState, userId);

        // 步骤4: 恢复Keyguard
        setKeyguardState(mLockTaskModeState, userId);

        // 步骤5: 退出Screen Pinning时锁定设备
        if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
            lockKeyguardIfNeeded(userId);
        }

        // 步骤6: 通知DevicePolicyManager
        if (getDevicePolicyManager() != null) {
            getDevicePolicyManager().notifyLockTaskModeChanged(
                false, null, userId);
        }

        // 步骤7: 显示退出Toast
        if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
            IStatusBarService statusBar = getStatusBarService();
            if (statusBar != null) {
                statusBar.showPinningEnterExitToast(false);
            }
        }

        // 步骤8: 通知WindowManager
        mWindowManager.onLockTaskStateChanged(mLockTaskModeState);
    } catch (RemoteException ex) {
        throw new RuntimeException(ex);
    }
}

3.3 权限检查流程

3.3.1 getLockTaskAuth - 计算任务授权级别

源码 : LockTaskController.java: Line 812-844

java 复制代码
int getLockTaskAuth(@Nullable ActivityRecord rootActivity, @Nullable Task task) {
    // 步骤1: 基本检查
    if (rootActivity == null && task == null) {
        return LOCK_TASK_AUTH_DONT_LOCK;
    }
    if (rootActivity == null) {
        return LOCK_TASK_AUTH_PINNABLE;
    }

    // 步骤2: 获取包名和用户ID
    final String pkg = (task == null || task.realActivity == null) ?
        rootActivity.packageName : task.realActivity.getPackageName();
    final int userId = task != null ? task.mUserId : rootActivity.mUserId;

    int lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;

    // 步骤3: 根据Manifest配置计算权限
    switch (rootActivity.lockTaskLaunchMode) {
        case LOCK_TASK_LAUNCH_MODE_DEFAULT:
            // 如果在白名单中 -> ALLOWLISTED,否则 -> PINNABLE
            lockTaskAuth = isPackageAllowlisted(userId, pkg)
                ? LOCK_TASK_AUTH_ALLOWLISTED
                : LOCK_TASK_AUTH_PINNABLE;
            break;

        case LOCK_TASK_LAUNCH_MODE_NEVER:
            // 永不锁定
            lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
            break;

        case LOCK_TASK_LAUNCH_MODE_ALWAYS:
            // 特权应用,自动锁定
            lockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
            break;

        case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
            // 仅白名单中可锁定
            lockTaskAuth = isPackageAllowlisted(userId, pkg)
                ? LOCK_TASK_AUTH_LAUNCHABLE
                : LOCK_TASK_AUTH_PINNABLE;
            break;
    }

    return lockTaskAuth;
}
3.3.2 权限级别说明

源码 : LockTaskController.java: Line 132-141

java 复制代码
/** 不能进入Lock Task模式 */
static final int LOCK_TASK_AUTH_DONT_LOCK = 0;

/** 可以进入Screen Pinning,需要用户批准。不能覆盖现有Lock Task */
static final int LOCK_TASK_AUTH_PINNABLE = 1;

/** 自动以LOCKED模式启动。可以覆盖现有Lock Task */
static final int LOCK_TASK_AUTH_LAUNCHABLE = 2;

/** 无需批准进入Lock Task。可以覆盖现有Lock Task */
static final int LOCK_TASK_AUTH_ALLOWLISTED = 3;

/** 特权应用,自动以LOCKED模式启动。可以覆盖现有Lock Task */
static final int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;

4. 关键类与方法

4.1 LockTaskController核心成员

源码路径 : /frameworks/base/services/core/java/com/android/server/wm/LockTaskController.java

java 复制代码
public class LockTaskController {
    // 状态管理
    private volatile int mLockTaskModeState = LOCK_TASK_MODE_NONE;

    // 任务列表(按进入Lock Task顺序)
    private final ArrayList<Task> mLockTaskModeTasks = new ArrayList<>();

    // 白名单管理(userId -> 包名数组)
    private final SparseArray<String[]> mLockTaskPackages = new SparseArray<>();

    // 功能标志(userId -> feature flags)
    private final SparseIntArray mLockTaskFeatures = new SparseIntArray();

    // 系统服务引用
    IStatusBarService mStatusBarService;
    IDevicePolicyManager mDevicePolicyManager;
    WindowManagerService mWindowManager;
    LockPatternUtils mLockPatternUtils;

    // Handler用于异步操作
    private final Handler mHandler;
}

4.2 关键方法列表

方法名 作用 调用时机
startLockTaskMode(Task, boolean, int) 启动Lock Task模式 Activity.startLockTask()或系统调用
stopLockTaskMode(Task, boolean, int) 停止Lock Task模式 Activity.stopLockTask()或系统调用
getLockTaskAuth(ActivityRecord, Task) 计算任务授权级别 任务创建或状态检查时
isLockTaskModeViolation(Task, boolean) 检查是否违反Lock Task规则 启动新任务时
updateLockTaskPackages(int, String[]) 更新白名单 DPM调用
updateLockTaskFeatures(int, int) 更新功能标志 DPM调用
setStatusBarState(int, int) 配置状态栏状态 进入/退出Lock Task
setKeyguardState(int, int) 配置锁屏状态 进入/退出Lock Task
isTaskLocked(Task) 检查任务是否锁定 任务操作前
activityBlockedFromFinish(ActivityRecord) 检查Activity是否允许结束 Activity.finish()时

4.3 StatusBar禁用标志

源码 : LockTaskController.java: Line 94-126

java 复制代码
// PINNED模式的StatusBar禁用标志
static final int STATUS_BAR_MASK_PINNED = StatusBarManager.DISABLE_MASK
    & (~StatusBarManager.DISABLE_BACK)     // 允许返回
    & (~StatusBarManager.DISABLE_HOME)     // 允许Home
    & (~StatusBarManager.DISABLE_RECENT);  // 允许最近任务

// LOCKED模式的StatusBar禁用标志(更严格)
static final int STATUS_BAR_MASK_LOCKED = StatusBarManager.DISABLE_MASK
    & (~StatusBarManager.DISABLE_EXPAND)   // 禁止下拉
    & (~StatusBarManager.DISABLE_NOTIFICATION_TICKER)
    & (~StatusBarManager.DISABLE_SYSTEM_INFO)
    & (~StatusBarManager.DISABLE_BACK);

4.4 Lock Task Feature标志映射

DevicePolicyManager中定义的功能标志:

java 复制代码
// DevicePolicyManager.java: Line 3018-3091
public static final int LOCK_TASK_FEATURE_NONE = 0;
public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1;      // 系统信息(时钟等)
public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 1 << 1; // 通知
public static final int LOCK_TASK_FEATURE_HOME = 1 << 2;        // Home按钮
public static final int LOCK_TASK_FEATURE_OVERVIEW = 1 << 3;    // 最近任务
public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = 1 << 4; // 电源菜单
public static final int LOCK_TASK_FEATURE_KEYGUARD = 1 << 5;    // 锁屏
public static final int LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK = 1 << 6; // 阻止启动新Activity

映射到StatusBar标志:

java 复制代码
// LockTaskController.java: Line 105-126
static {
    STATUS_BAR_FLAG_MAP_LOCKED = new SparseArray<>();

    // SYSTEM_INFO -> 允许显示时钟和系统图标
    STATUS_BAR_FLAG_MAP_LOCKED.append(
        DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO,
        new Pair<>(StatusBarManager.DISABLE_CLOCK,
                   StatusBarManager.DISABLE2_SYSTEM_ICONS));

    // NOTIFICATIONS -> 允许通知图标和通知面板
    STATUS_BAR_FLAG_MAP_LOCKED.append(
        DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS,
        new Pair<>(StatusBarManager.DISABLE_NOTIFICATION_ICONS |
                   StatusBarManager.DISABLE_NOTIFICATION_ALERTS,
                   StatusBarManager.DISABLE2_NOTIFICATION_SHADE));

    // HOME -> 允许Home按钮
    STATUS_BAR_FLAG_MAP_LOCKED.append(
        DevicePolicyManager.LOCK_TASK_FEATURE_HOME,
        new Pair<>(StatusBarManager.DISABLE_HOME,
                   StatusBarManager.DISABLE2_NONE));

    // OVERVIEW -> 允许最近任务按钮
    STATUS_BAR_FLAG_MAP_LOCKED.append(
        DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW,
        new Pair<>(StatusBarManager.DISABLE_RECENT,
                   StatusBarManager.DISABLE2_NONE));

    // GLOBAL_ACTIONS -> 允许电源菜单
    STATUS_BAR_FLAG_MAP_LOCKED.append(
        DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
        new Pair<>(StatusBarManager.DISABLE_NONE,
                   StatusBarManager.DISABLE2_GLOBAL_ACTIONS));
}

5. 应用层使用方法

5.1 Manifest配置

源码路径 : /frameworks/base/core/res/res/values/attrs_manifest.xml

在AndroidManifest.xml的<activity>标签中配置android:lockTaskMode属性:

xml 复制代码
<activity
    android:name=".MainActivity"
    android:lockTaskMode="normal|never|always|if_whitelisted"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

lockTaskMode属性值说明:

常量 说明
normal (0) LOCK_TASK_LAUNCH_MODE_DEFAULT 默认模式。可调用startLockTask(),需白名单或用户确认
never (1) LOCK_TASK_LAUNCH_MODE_NEVER 禁止锁定。无法进入Lock Task模式
always (2) LOCK_TASK_LAUNCH_MODE_ALWAYS 自动锁定。Activity启动时自动进入LOCKED模式(需系统权限)
if_whitelisted (3) LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED 白名单模式。在白名单中自动锁定,否则需用户确认

示例 : /frameworks/base/tests/LockTaskTests/AndroidManifest.xml

xml 复制代码
<!-- 默认模式 -->
<activity
    android:name=".LockDefaultActivity"
    android:lockTaskMode="normal" />

<!-- 禁止锁定 -->
<activity
    android:name=".LockTaskNeverActivity"
    android:lockTaskMode="never" />

<!-- 白名单模式 -->
<activity
    android:name=".LockWhitelistedActivity"
    android:lockTaskMode="if_whitelisted" />

<!-- 自动锁定(特权应用) -->
<activity
    android:name=".LockAtLaunchActivity"
    android:lockTaskMode="always" />

5.2 代码API使用

5.2.1 启动Lock Task

源码 : /frameworks/base/core/java/android/app/Activity.java: Line 9456-9458

java 复制代码
public class MainActivity extends Activity {
    @Override
    protected void onResume() {
        super.onResume();

        // 方式1: 直接启动Lock Task
        try {
            startLockTask();
        } catch (SecurityException e) {
            // 处理权限异常
            Log.e(TAG, "Failed to start lock task", e);
        }
    }

    // 方式2: 检查后启动
    private void startLockTaskIfNeeded() {
        ActivityManager am = (ActivityManager)
            getSystemService(Context.ACTIVITY_SERVICE);

        // 检查当前状态
        int lockTaskMode = am.getLockTaskModeState();
        if (lockTaskMode == ActivityManager.LOCK_TASK_MODE_NONE) {
            startLockTask();
        }
    }
}

注意事项:

  • 必须在Activity的onResume()之后调用
  • 如果应用不在白名单且lockTaskMode为normal,会显示用户确认对话框
  • 特权应用(系统应用)或白名单应用可以直接进入LOCKED模式
  • 普通应用只能进入PINNED模式(Screen Pinning)
5.2.2 停止Lock Task

源码 : /frameworks/base/core/java/android/app/Activity.java: Line 9476-9478

java 复制代码
public class MainActivity extends Activity {
    private void exitLockTask() {
        try {
            stopLockTask();
        } catch (SecurityException e) {
            // 只有启动Lock Task的Activity才能停止
            Log.e(TAG, "Failed to stop lock task", e);
        }
    }

    @Override
    public void onBackPressed() {
        // 在Lock Task模式中,可以选择性地处理返回键
        ActivityManager am = (ActivityManager)
            getSystemService(Context.ACTIVITY_SERVICE);

        if (am.getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE) {
            // 显示确认对话框或直接退出
            showExitConfirmDialog();
        } else {
            super.onBackPressed();
        }
    }

    private void showExitConfirmDialog() {
        new AlertDialog.Builder(this)
            .setTitle("退出锁定模式")
            .setMessage("确定要退出锁定模式吗?")
            .setPositiveButton("确定", (dialog, which) -> stopLockTask())
            .setNegativeButton("取消", null)
            .show();
    }
}
5.2.3 检查Lock Task状态
java 复制代码
public class LockTaskHelper {
    private final Context mContext;

    public boolean isInLockTaskMode() {
        ActivityManager am = (ActivityManager)
            mContext.getSystemService(Context.ACTIVITY_SERVICE);
        return am.isInLockTaskMode();
    }

    public int getLockTaskModeState() {
        ActivityManager am = (ActivityManager)
            mContext.getSystemService(Context.ACTIVITY_SERVICE);
        return am.getLockTaskModeState();
    }

    public String getLockTaskModeString() {
        int mode = getLockTaskModeState();
        switch (mode) {
            case ActivityManager.LOCK_TASK_MODE_NONE:
                return "正常模式";
            case ActivityManager.LOCK_TASK_MODE_LOCKED:
                return "完全锁定模式";
            case ActivityManager.LOCK_TASK_MODE_PINNED:
                return "屏幕固定模式";
            default:
                return "未知模式";
        }
    }
}
5.2.4 显示退出提示

源码 : /frameworks/base/core/java/android/app/Activity.java: Line 9485-9487

java 复制代码
public class MainActivity extends Activity {
    private void showExitMessage() {
        // 显示系统定义的退出Lock Task模式提示消息
        showLockTaskEscapeMessage();
    }
}

5.3 完整示例应用

java 复制代码
package com.example.locktaskdemo;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class LockTaskDemoActivity extends Activity {
    private static final String TAG = "LockTaskDemo";

    private TextView mStatusText;
    private Button mStartButton;
    private Button mStopButton;
    private ActivityManager mActivityManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mActivityManager = (ActivityManager)
            getSystemService(Context.ACTIVITY_SERVICE);

        mStatusText = findViewById(R.id.status_text);
        mStartButton = findViewById(R.id.start_button);
        mStopButton = findViewById(R.id.stop_button);

        mStartButton.setOnClickListener(v -> startLockTaskMode());
        mStopButton.setOnClickListener(v -> stopLockTaskMode());

        updateUI();
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateUI();
    }

    private void startLockTaskMode() {
        try {
            startLockTask();
            Toast.makeText(this, "Lock Task模式已启动", Toast.LENGTH_SHORT).show();
            Log.i(TAG, "Lock Task mode started");
        } catch (SecurityException e) {
            Toast.makeText(this, "无法启动Lock Task: " + e.getMessage(),
                Toast.LENGTH_LONG).show();
            Log.e(TAG, "Failed to start lock task", e);
        }
    }

    private void stopLockTaskMode() {
        try {
            stopLockTask();
            Toast.makeText(this, "Lock Task模式已停止", Toast.LENGTH_SHORT).show();
            Log.i(TAG, "Lock Task mode stopped");
        } catch (SecurityException e) {
            Toast.makeText(this, "无法停止Lock Task: " + e.getMessage(),
                Toast.LENGTH_LONG).show();
            Log.e(TAG, "Failed to stop lock task", e);
        }
    }

    private void updateUI() {
        int lockTaskMode = mActivityManager.getLockTaskModeState();
        String statusText;

        switch (lockTaskMode) {
            case ActivityManager.LOCK_TASK_MODE_LOCKED:
                statusText = "状态: 完全锁定模式 (LOCKED)";
                mStartButton.setEnabled(false);
                mStopButton.setEnabled(true);
                break;
            case ActivityManager.LOCK_TASK_MODE_PINNED:
                statusText = "状态: 屏幕固定模式 (PINNED)";
                mStartButton.setEnabled(false);
                mStopButton.setEnabled(true);
                break;
            case ActivityManager.LOCK_TASK_MODE_NONE:
            default:
                statusText = "状态: 正常模式 (NONE)";
                mStartButton.setEnabled(true);
                mStopButton.setEnabled(false);
                break;
        }

        mStatusText.setText(statusText);
    }

    @Override
    public void onBackPressed() {
        if (mActivityManager.isInLockTaskMode()) {
            // 在Lock Task模式中,显示提示而不是直接退出
            showLockTaskEscapeMessage();
        } else {
            super.onBackPressed();
        }
    }
}

布局文件 (res/layout/activity_main.xml):

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    android:gravity="center">

    <TextView
        android:id="@+id/status_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="状态: 正常模式"
        android:textSize="18sp"
        android:layout_marginBottom="32dp"/>

    <Button
        android:id="@+id/start_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动 Lock Task"
        android:layout_marginBottom="16dp"/>

    <Button
        android:id="@+id/stop_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止 Lock Task"
        android:enabled="false"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="提示:\n• 需要设备管理员权限或用户确认\n• 在锁定模式中,系统功能会受限\n• 可以通过代码或手势退出"
        android:textSize="14sp"
        android:layout_marginTop="32dp"/>
</LinearLayout>

Manifest配置:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.locktaskdemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Lock Task Demo"
        android:theme="@style/Theme.AppCompat">

        <activity
            android:name=".LockTaskDemoActivity"
            android:lockTaskMode="normal"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

致敬前辈,砥砺前行!

相关推荐
zh_xuan2 小时前
kotlin launch函数
android·kotlin·协程·launch
贤泽3 小时前
android 15 AOSP Broadcast 广播机制源码分析
android·aosp
啥都想学点3 小时前
第1天:搭建 flutter 和 Android 环境
android·flutter
huohuopro3 小时前
Android WebView 输入法同步问题解决方案
android
草莓熊Lotso3 小时前
Ext 系列文件系统核心:块、分区、inode 与块组结构详解
android·linux·c语言·开发语言·c++·人工智能·文件
桂花很香,旭很美4 小时前
ADB 安卓实战手册
android·adb
summerkissyou198714 小时前
Android Handler:机制、原理与示例
android
哈哈浩丶15 小时前
安卓系统全流程启动
android·linux·驱动开发
summerkissyou198716 小时前
Android-Audio-MediaPlayer-播放-流程
android·audio