鎖定任務模式

本開發人員指南說明如何將專用裝置鎖定為單一應用程式或一組應用程式。如果您是企業行動管理服務 (EMM) 開發人員或解決方案整合商,請參閱本指南,瞭解如何在解決方案中新增鎖定工作模式。

總覽

Android 能以類似資訊站的方式執行任務,這種沉浸式的做法稱為「鎖定任務模式」。如果您正在開發資訊站應用程式或啟動器以顯示一組應用程式,就可以使用鎖定工作模式。當系統在鎖定任務模式下執行時,裝置使用者通常無法看到通知、無法存取未列入許可清單的應用程式,也無法返回主畫面 (除非已將主畫面列入許可清單)。

只有經裝置政策控制器 (DPC) 列入許可清單的應用程式,才能在系統處於鎖定任務模式時執行。由於裝置使用者無法一律離開鎖定任務模式,因此應用程式已加入許可清單。

如何結合用於鎖定任務模式的應用程式許可清單,並將 DPC 加入許可清單的方式取決於要解決的問題。例如:

  • 結合資訊站 (用來顯示內容) 和迷你 DPC (用於鎖定任務模式的許可清單) 的單一應用程式套件。
  • DPC 屬於企業行動管理服務解決方案的一部分,可在鎖定任務模式下啟動客戶的行動應用程式。

產品供應資訊

在 Android 5.0 以上版本中,系統可透過鎖定任務模式執行。表 1 顯示哪些 Android 版本支援將使用者將應用程式加入許可清單。

表 1. Android 版本支援裝置政策控制器 (DPC) 管理模式
Android 版本 DPC 管理 附註
Android 5.0 (API 級別 21) 以上版本 完全受管理的裝置
Android 8.0 (API 級別 26) 以上版本 關聯的次要使用者 次要使用者必須與主要使用者的關聯請參閱「多位使用者」總覽。
Android 9.0 (API 級別 28) 以上版本 次要使用者

在 Android 9.0 以上版本中,DPC 可以啟動任何應用程式的活動,並進入鎖定任務模式。在舊版中,應用程式必須已支援在鎖定任務模式下啟動自己的活動。

將應用程式加入許可清單

DPC 必須先將應用程式加入許可清單,才能在鎖定任務模式下使用這些應用程式。呼叫 DevicePolicyManager.setLockTaskPackages() 來將用於鎖定工作模式的應用程式加入許可清單,如以下範例所示:

Kotlin

// Allowlist two apps.
private val KIOSK_PACKAGE = "com.example.kiosk"
private val PLAYER_PACKAGE = "com.example.player"
private val APP_PACKAGES = arrayOf(KIOSK_PACKAGE, PLAYER_PACKAGE)

// ...

val context = context
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
val adminName = getComponentName(context)
dpm.setLockTaskPackages(adminName, APP_PACKAGES)

Java

// Allowlist two apps.
private static final String KIOSK_PACKAGE = "com.example.kiosk";
private static final String PLAYER_PACKAGE = "com.example.player";
private static final String[] APP_PACKAGES = {KIOSK_PACKAGE, PLAYER_PACKAGE};

// ...

Context context = getContext();
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminName = getComponentName(context);
dpm.setLockTaskPackages(adminName, APP_PACKAGES);

如要找出先前獲準用於鎖定任務模式的應用程式,DPC 可以呼叫 DevicePolicyManager.getLockTaskPackages()。其他應用程式可以呼叫 DevicePolicyManager.isLockTaskPermitted(),確認應用程式套件支援鎖定工作模式。

啟動鎖定任務模式

在 Android 9.0 (API 級別 28) 以上版本中,您可以在鎖定任務模式下啟動其他應用程式的活動。如果活動已在前景或背景執行,您必須重新啟動該活動。呼叫 ActivityOptions.setLockTaskEnabled(),並在啟動活動時提供這些選項。下列程式碼片段是其中一種做法:

Kotlin

// Set an option to turn on lock task mode when starting the activity.
val options = ActivityOptions.makeBasic()
options.setLockTaskEnabled(true)

// Start our kiosk app's main activity with our lock task mode option.
val packageManager = context.packageManager
val launchIntent = packageManager.getLaunchIntentForPackage(KIOSK_PACKAGE)
if (launchIntent != null) {
    context.startActivity(launchIntent, options.toBundle())
}

Java

// Set an option to turn on lock task mode when starting the activity.
ActivityOptions options = ActivityOptions.makeBasic();
options.setLockTaskEnabled(true);

// Start our kiosk app's main activity with our lock task mode option.
PackageManager packageManager = context.getPackageManager();
Intent launchIntent = packageManager.getLaunchIntentForPackage(KIOSK_PACKAGE);
if (launchIntent != null) {
  context.startActivity(launchIntent, options.toBundle());
}

在 Android 9.0 以下版本中,應用程式會呼叫 Activity.startLockTask(),以鎖定任務模式啟動自己的活動。如要呼叫此方法,活動必須在前景執行 (請參閱「活動生命週期概念」),因此我們建議在 ActivityFragmentonResume() 方法中呼叫。以下說明如何呼叫 startLockTask()

Kotlin

// In our Fragment subclass.
override fun onResume() {
    super.onResume()
    // First, confirm that this package is allowlisted to run in lock task mode.
    if (dpm.isLockTaskPermitted(context.packageName)) {
        activity.startLockTask()
    } else {
        // Because the package isn't allowlisted, calling startLockTask() here
        // would put the activity into screen pinning mode.
    }
}

Java

// In our Fragment subclass.
@Override
public void onResume() {
  super.onResume();

  // First, confirm that this package is allowlisted to run in lock task mode.
  if (dpm.isLockTaskPermitted(context.getPackageName())) {
    getActivity().startLockTask();
  } else {
    // Because the package isn't allowlisted, calling startLockTask() here
    // would put the activity into screen pinning mode.
  }
}

請勿在裝置鎖定時啟動鎖定工作模式,因為使用者可能無法解鎖裝置。您可以呼叫 KeyguardManager 方法可確認裝置是否處於鎖定狀態,並使用 Activity 生命週期回呼 (例如解鎖後呼叫的 onResume()) 來啟動鎖定任務模式。

只要活動不會啟動新工作 (啟動已加入許可清單的應用程式工作除外),應用程式處於鎖定任務模式下的應用程式即可啟動新活動。如要瞭解工作與活動之間的關係,請參閱「瞭解工作和返回堆疊」指南。

或者,您也可以在應用程式資訊清單檔案中宣告活動在鎖定任務模式下執行時的行為。如要讓系統在鎖定任務模式下自動執行活動,請將 android:lockTaskMode 屬性設為 if_whitelisted,如以下範例所示:

<activity
    android:name=".MainActivity"
    android:lockTaskMode="if_whitelisted">
    <!-- ... -->
</activity>

如要進一步瞭解如何在應用程式資訊清單檔案中宣告選項,請參閱 lockTaskMode 參考資料。

停止鎖定任務模式

DPC 可將應用程式套件從許可清單中移除,藉此從遠端停止鎖定任務模式。在 Android 6.0 (API 級別 23) 以上版本中呼叫 DevicePolicyManager.setLockTaskPackages(),然後從許可清單陣列中省略套件名稱。更新許可清單時,應用程式會回到堆疊中的上一個工作。

如果活動之前稱為 startLockTask(),該活動可以呼叫 Activity.stopLockTask() 來停止鎖定任務模式。這個方法僅適用於已啟動鎖定任務模式的活動。

生命週期回呼

如要瞭解應用程式 (在同一使用者中執行) 進入及結束鎖定任務模式的時間,DPC 可能會派上用場。如要接收回呼,請在 DPC 的 DeviceAdminReceiver 子類別中覆寫下列回呼方法:

onLockTaskModeEntering()
在應用程式進入鎖定工作模式後呼叫。您可以從 pkg 引數取得應用程式的套件名稱。
onLockTaskModeExiting()
在應用程式結束鎖定工作模式後呼叫。這個回呼不會收到應用程式的相關資訊。

如果您在鎖定工作模式下啟動另一個應用程式,則必須在自己的應用程式中追蹤執行狀態。如要檢查目前應用程式是否在鎖定任務模式下執行,請使用 ActivityManager 中的方法,如以下範例所示:

Kotlin

// Check if this app is in lock task mode. Screen pinning doesn't count.
var isLockTaskModeRunning = false

val activityManager = context
        .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    isLockTaskModeRunning =
            activityManager.lockTaskModeState ==
            ActivityManager.LOCK_TASK_MODE_LOCKED
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Deprecated in API level 23.
    isLockTaskModeRunning = activityManager.isInLockTaskMode
}

if (isLockTaskModeRunning) {
    // Show the exit button ...
}

Java

// Check if this app is in lock task mode. Screen pinning doesn't count.
boolean isLockTaskModeRunning = false;

ActivityManager activityManager = (ActivityManager)
    getContext().getSystemService(Context.ACTIVITY_SERVICE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  isLockTaskModeRunning = activityManager.getLockTaskModeState()
      == ActivityManager.LOCK_TASK_MODE_LOCKED;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  // Deprecated in API level 23.
  isLockTaskModeRunning = activityManager.isInLockTaskMode();
}

if (isLockTaskModeRunning) {
  // Show the exit button ...
}

自訂 UI

當應用程式在鎖定任務模式下執行時,系統使用者介面 (UI) 會以下列方式變更:

  • 狀態列是空白的,且通知和系統資訊已隱藏。
  • 系統會隱藏「首頁」和「總覽」按鈕,
  • 其他應用程式無法啟動新活動。
  • 螢幕鎖定功能 (如有設定) 已停用。

在 Android 9.0 以上版本中啟用鎖定任務模式時,DPC 可在裝置上啟用特定系統 UI 功能,對於開發人員建立自訂啟動器來說非常實用。呼叫 DevicePolicyManager.setLockTaskFeatures(),如以下程式碼片段所示:

Kotlin

// Enable the Home and Overview buttons so that our custom launcher can respond
// using our custom activities. Implicitly disables all other features.
dpm.setLockTaskFeatures(
        adminName,
        DevicePolicyManager.LOCK_TASK_FEATURE_HOME or
              DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW)

Java

// Enable the Home and Overview buttons so that our custom launcher can respond
// using our custom activities. Implicitly disables all other features.
dpm.setLockTaskFeatures(adminName,
    DevicePolicyManager.LOCK_TASK_FEATURE_HOME |
          DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW);

系統不會停用您未納入 flags 引數的任何功能。已啟用的 UI 功能會在啟動之間保持鎖定工作模式。如果裝置已處於鎖定任務模式,您對鎖定工作功能所做的任何變更都會立即顯示。表 2 說明可自訂的 UI 功能。

表 2. 鎖定任務模式中的可自訂系統 UI 功能
系統 UI 功能 說明
LOCK_TASK_FEATURE_HOME 顯示首頁按鈕。啟用自訂啟動器:除非您將預設的 Android 啟動器加入許可清單,否則輕觸已啟用的主畫面按鈕沒有任何動作。
LOCK_TASK_FEATURE_OVERVIEW 顯示「總覽」按鈕 (輕觸這個按鈕可開啟「最近」畫面)。啟用這個按鈕時,必須一併啟用首頁按鈕。
LOCK_TASK_FEATURE_GLOBAL_ACTIONS 啟用長按電源鍵時顯示的全域動作對話方塊。唯一在未呼叫 setLockTaskFeatures() 時啟用的功能。如果您停用這個對話方塊,使用者通常就無法關閉裝置。
LOCK_TASK_FEATURE_NOTIFICATIONS 啟用所有應用程式的通知。此模式會在狀態列、抬頭通知和可展開的通知欄中顯示通知圖示。但即使啟用這個按鈕,也必須啟用首頁按鈕。輕觸開啟新面板的通知動作和按鈕,在鎖定工作模式下無法運作。
LOCK_TASK_FEATURE_SYSTEM_INFO 啟用狀態列的系統資訊區域,其中包含連線、電池、音效和震動選項等指標。
LOCK_TASK_FEATURE_KEYGUARD 啟用可能在裝置上設定的任何螢幕鎖定。通常不適用於具備公開使用者的裝置,例如資訊資訊站或數位電子看板。
LOCK_TASK_FEATURE_NONE 停用上述所有系統 UI 功能。

啟用鎖定任務模式時,DPC 可呼叫 DevicePolicyManager.getLockTaskFeatures() 來取得裝置的可用功能清單。當裝置退出鎖定工作模式時,使用者介面會返回現有裝置政策要求的狀態。

封鎖視窗和重疊

當應用程式在鎖定任務模式下執行時,其他應用程式和背景服務可以建立新視窗,讓 Android 顯示在應用程式鎖定任務模式下。應用程式和服務會建立這些視窗,向使用裝置的使用者顯示浮動式訊息、對話方塊和重疊畫面。您的 DPC 可以新增 DISALLOW_CREATE_WINDOWS 使用者限制,防止這種情況發生。以下範例說明如何在 onLockTaskModeEntering() 回呼中執行此操作:

Kotlin

// Called just after entering lock task mode.
override fun onLockTaskModeEntering(context: Context, intent: Intent) {
    val dpm = getManager(context)
    val admin = getWho(context)

    dpm.addUserRestriction(admin, UserManager.DISALLOW_CREATE_WINDOWS)
}

Java

// Called just after entering lock task mode.
public void onLockTaskModeEntering(Context context, Intent intent) {
  DevicePolicyManager dpm = getManager(context);
  ComponentName admin = getWho(context);

  dpm.addUserRestriction(admin, UserManager.DISALLOW_CREATE_WINDOWS);
}

當裝置結束鎖定工作模式時,DPC 可以移除使用者限制。

其他資源

想進一步瞭解專用裝置,請參閱下列文件: