鎖定任務模式

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

總覽

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

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

根據要解決的問題,如何結合用於鎖定任務模式的應用程式許可清單和許可清單 DPC。例如:

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

適用地區

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

表 1. DPC 管理員模式的 Android 版本支援
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 可以移除使用者限制。

其他資源

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