Chế độ khoá tác vụ

Hướng dẫn dành cho nhà phát triển này giải thích cách khoá các thiết bị chuyên dụng đối với một ứng dụng hoặc một nhóm ứng dụng. Nếu bạn là nhà phát triển giải pháp quản lý di động dành cho doanh nghiệp (EMM) hoặc nhà tích hợp các giải pháp, hãy đọc hướng dẫn này để thêm chế độ khoá tác vụ vào giải pháp của bạn.

Tổng quan

Android có thể chạy các tác vụ ở chế độ chìm (immerse), kiểu kiosk, được gọi là chế độ khoá tác vụ. Bạn có thể dùng chế độ khoá tác vụ nếu đang phát triển ứng dụng kiosk hoặc trình chạy để trình bày một tập hợp ứng dụng. Khi hệ thống chạy ở chế độ khoá tác vụ, người dùng thiết bị thường không xem được thông báo, truy cập vào các ứng dụng không có trong danh sách cho phép hoặc quay lại màn hình chính (trừ phi màn hình chính có trong danh sách cho phép).

Chỉ các ứng dụng đã được trình kiểm soát chính sách thiết bị (DPC) đưa vào danh sách cho phép mới có thể chạy khi hệ thống đang ở chế độ khoá tác vụ. Các ứng dụng được đưa vào danh sách cho phép vì người sử dụng thiết bị không phải lúc nào cũng thoát khỏi chế độ khoá tác vụ.

Cách bạn kết hợp ứng dụng được thêm vào danh sách cho phép để dùng chế độ khoá tác vụ và DPC vào danh sách cho phép sẽ tuỳ thuộc vào vấn đề bạn muốn giải quyết. Dưới đây là một số ví dụ:

  • Một gói ứng dụng kết hợp kiosk (để trình bày nội dung) và DPC mini (để đưa chính nó vào danh sách cho phép chế độ khoá tác vụ).
  • DPC là một phần của giải pháp quản lý tính di động dành cho doanh nghiệp, chạy các ứng dụng di động của khách hàng ở chế độ khoá tác vụ.

Phạm vi cung cấp

Hệ thống có thể chạy ở chế độ khoá tác vụ trong Android 5.0 trở lên. Bảng 1 cho thấy các phiên bản Android hỗ trợ việc đưa các ứng dụng vào danh sách cho phép theo người dùng.

Bảng 1. Hỗ trợ phiên bản Android cho chế độ quản trị DPC
Phiên bản Android DPC quản lý Ghi chú
Android 5.0 (API cấp 21) trở lên Thiết bị được quản lý hoàn toàn
Android 8.0 (API cấp 26) trở lên Người dùng phụ được liên kết Người dùng phụ phải được liên kết với người dùng chính. Xem thông tin tổng quan về nhiều người dùng.
Android 9.0 (API cấp 28) trở lên Người dùng phụ

Trên Android 9.0 trở lên, DPC có thể bắt đầu hoạt động của bất kỳ ứng dụng nào ở chế độ khoá tác vụ. Trong các phiên bản cũ, ứng dụng phải hỗ trợ bắt đầu hoạt động của chính nó ở chế độ khoá tác vụ.

Đưa ứng dụng vào danh sách cho phép

DPC phải đưa các ứng dụng vào danh sách cho phép trước khi có thể sử dụng chúng ở chế độ khoá tác vụ. Gọi DevicePolicyManager.setLockTaskPackages() để đưa các ứng dụng vào danh sách cho phép của chế độ khoá tác vụ như trong mẫu sau:

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);

Để tìm các ứng dụng trước đó đã được đưa vào chế độ khoá tác vụ, DPC có thể gọi DevicePolicyManager.getLockTaskPackages(). Các ứng dụng khác có thể gọi DevicePolicyManager.isLockTaskPermitted() để xác nhận rằng một gói ứng dụng hỗ trợ chế độ khoá tác vụ.

Bắt đầu chế độ khoá tác vụ

Trong Android 9.0 (API cấp 28) trở lên, bạn có thể bắt đầu hoạt động của một ứng dụng khác ở chế độ khoá tác vụ. Nếu một hoạt động đang chạy ở nền trước hoặc trong nền, bạn cần chạy lại hoạt động đó. Gọi ActivityOptions.setLockTaskEnabled() và cung cấp các tuỳ chọn này khi bắt đầu hoạt động. Đoạn mã sau đây hướng dẫn một cách mà bạn có thể thực hiện việc này:

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());
}

Trong các phiên bản Android trước 9.0, một ứng dụng sẽ bắt đầu các hoạt động của chính nó ở chế độ khoá tác vụ bằng cách gọi Activity.startLockTask(). Để gọi phương thức này, hoạt động phải đang chạy ở nền trước (xem phần Khái niệm vòng đời hoạt động). Vì vậy, bạn nên gọi phương thức onResume() của Activity hoặc Fragment. Sau đây là cách bạn có thể gọi 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.
  }
}

Đừng bắt đầu chế độ khoá tác vụ khi thiết bị đang khoá vì người dùng có thể không mở khoá được thiết bị. Bạn có thể gọi các phương thức KeyguardManager để tìm hiểu xem thiết bị có bị khoá hay không và dùng lệnh gọi lại trong vòng đời Activity (chẳng hạn như onResume() được gọi sau khi mở khoá) để bắt đầu chế độ khoá tác vụ.

Ứng dụng ở chế độ khoá tác vụ có thể bắt đầu hoạt động mới miễn là hoạt động đó không bắt đầu một tác vụ mới, ngoại trừ các tác vụ chạy ứng dụng trong danh sách cho phép. Để hiểu cách các tác vụ liên quan đến hoạt động, hãy đọc hướng dẫn Tìm hiểu về Tác vụ và Ngăn xếp lui.

Ngoài ra, bạn có thể khai báo trong tệp kê khai ứng dụng về cách hoạt động của một hoạt động khi hệ thống đang chạy ở chế độ khoá tác vụ. Để hệ thống tự động chạy hoạt động của bạn ở chế độ khoá tác vụ, hãy đặt thuộc tính android:lockTaskMode thành if_whitelisted như minh hoạ trong ví dụ sau:

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

Bạn có thể tìm hiểu thêm về cách khai báo các tuỳ chọn trong tệp kê khai ứng dụng bằng cách đọc tài liệu tham khảo về lockTaskMode.

Dừng chế độ khoá tác vụ

DPC có thể dừng từ xa chế độ khoá tác vụ bằng cách xoá gói ứng dụng khỏi danh sách cho phép. Gọi DevicePolicyManager.setLockTaskPackages() trong Android 6.0 (API cấp 23) trở lên và bỏ qua tên gói khỏi mảng danh sách cho phép. Khi bạn cập nhật danh sách cho phép, ứng dụng sẽ quay lại tác vụ trước đó trong ngăn xếp.

Nếu trước đây một hoạt động có tên là startLockTask(), thì hoạt động đó có thể gọi Activity.stopLockTask() để dừng chế độ khoá tác vụ. Phương thức này chỉ dùng được cho hoạt động đã bắt đầu chế độ khoá tác vụ.

Phương thức gọi lại trong vòng đời

DPC của bạn có thể thấy hữu ích khi biết khi nào một ứng dụng (chạy cùng một người dùng) truy cập và thoát khỏi chế độ khoá tác vụ. Để nhận lệnh gọi lại, hãy ghi đè các phương thức gọi lại sau đây trong lớp con DeviceAdminReceiver của DPC:

onLockTaskModeEntering()
Được gọi sau khi một ứng dụng chuyển sang chế độ khoá tác vụ. Bạn có thể lấy tên gói của một ứng dụng qua đối số pkg.
onLockTaskModeExiting()
Được gọi sau khi ứng dụng thoát khỏi chế độ khoá tác vụ. Lệnh gọi lại này không nhận được thông tin về ứng dụng.

Nếu chạy một ứng dụng khác ở chế độ khoá tác vụ, bạn cần theo dõi trạng thái đang chạy trong ứng dụng của mình. Để kiểm tra xem ứng dụng hiện tại có đang chạy ở chế độ khoá tác vụ hay không, hãy dùng các phương thức trên ActivityManager như minh hoạ trong ví dụ sau:

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 ...
}

Tuỳ chỉnh giao diện người dùng

Khi một ứng dụng chạy ở chế độ khoá tác vụ, giao diện người dùng hệ thống (UI) sẽ thay đổi theo những cách sau:

  • Thanh trạng thái trống với các thông báo và thông tin hệ thống bị ẩn.
  • Nút Màn hình chính và Tổng quan bị ẩn.
  • Các ứng dụng khác không thể chạy hoạt động mới.
  • Màn hình khoá (nếu được đặt) sẽ tắt.

Trong Android 9.0 trở lên khi bạn bật chế độ khoá tác vụ, DPC có thể bật một số tính năng giao diện người dùng hệ thống trên thiết bị — hữu ích cho các nhà phát triển tạo trình chạy tuỳ chỉnh. Gọi DevicePolicyManager.setLockTaskFeatures() như minh hoạ trong đoạn mã sau:

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);

Hệ thống sẽ tắt mọi tính năng mà bạn không đưa vào đối số flags. Các tính năng trên giao diện người dùng đã bật vẫn tồn tại giữa các lần chạy ở chế độ khoá tác vụ. Nếu thiết bị đã ở chế độ khoá tác vụ, thì mọi thay đổi bạn thực hiện đối với các tính năng khoá tác vụ sẽ hiển thị ngay lập tức. Bảng 2 mô tả các tính năng giao diện người dùng mà bạn có thể tuỳ chỉnh.

Bảng 2. Các tính năng có thể tuỳ chỉnh trên giao diện người dùng hệ thống trong chế độ khoá tác vụ
Tính năng giao diện người dùng hệ thống Nội dung mô tả
LOCK_TASK_FEATURE_HOME Hiển thị nút Màn hình chính. Bật cho trình chạy tuỳ chỉnh – nhấn vào nút Màn hình chính đã bật sẽ không có thao tác nào trừ phi bạn đưa trình chạy Android mặc định vào danh sách cho phép.
LOCK_TASK_FEATURE_OVERVIEW Hiện nút Tổng quan (nhấn vào nút này sẽ mở màn hình Gần đây). Nếu bật nút này, bạn cũng phải bật nút Trang chủ.
LOCK_TASK_FEATURE_GLOBAL_ACTIONS Bật hộp thoại thao tác chung xuất hiện khi nhấn và giữ nút nguồn. Tính năng duy nhất được bật khi setLockTaskFeatures() chưa được gọi. Người dùng thường không thể tắt nguồn thiết bị nếu bạn tắt hộp thoại này.
LOCK_TASK_FEATURE_NOTIFICATIONS Bật thông báo cho tất cả ứng dụng. Cột này hiển thị các biểu tượng thông báo trong thanh trạng thái, thông báo quan trọng và ngăn thông báo có thể mở rộng. Nếu bạn bật nút này, bạn cũng phải bật nút Trang chủ. Các thao tác nhấn vào thông báo và các nút mở bảng điều khiển mới không hoạt động ở chế độ khoá tác vụ.
LOCK_TASK_FEATURE_SYSTEM_INFO Bật vùng thông tin hệ thống của thanh trạng thái chứa các chỉ báo như kết nối, pin cũng như tuỳ chọn âm thanh và rung.
LOCK_TASK_FEATURE_KEYGUARD Bật mọi màn hình khoá có thể được đặt trên thiết bị. Thường không phù hợp với những thiết bị có người dùng công cộng như kiosk thông tin hoặc bảng hiệu kỹ thuật số.
LOCK_TASK_FEATURE_NONE Tắt tất cả các tính năng giao diện người dùng hệ thống nêu trên.

DPC có thể gọi DevicePolicyManager.getLockTaskFeatures() để lấy danh sách các tính năng có trên thiết bị khi chế độ khoá tác vụ được bật. Khi thiết bị thoát khỏi chế độ khoá tác vụ, giao diện người dùng sẽ trở về trạng thái bắt buộc theo chính sách thiết bị hiện tại.

Chặn cửa sổ và lớp phủ

Khi một ứng dụng chạy ở chế độ khoá tác vụ, các ứng dụng khác và dịch vụ nền có thể tạo cửa sổ mới mà Android hiển thị trước ứng dụng đó ở chế độ khoá tác vụ. Các ứng dụng và dịch vụ tạo các cửa sổ này để hiển thị thông báo ngắn, hộp thoại và lớp phủ cho người dùng thiết bị. DPC của bạn có thể ngăn những điều này bằng cách thêm quy tắc hạn chế người dùng DISALLOW_CREATE_WINDOWS. Ví dụ sau cho thấy cách bạn có thể thực hiện việc này trong lệnh gọi lại 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 của bạn có thể xoá chế độ hạn chế người dùng khi thiết bị thoát khỏi chế độ khoá tác vụ.

Tài nguyên khác

Để tìm hiểu thêm về các thiết bị chuyên dụng, hãy đọc các tài liệu sau: