Cookbook perangkat khusus

Cookbook ini membantu developer dan integrator sistem meningkatkan kualitas solusi perangkat khusus mereka. Ikuti resep petunjuk kami untuk menemukan solusi bagi perilaku perangkat khusus. Cookbook ini sangat cocok untuk developer yang sudah memiliki aplikasi perangkat khusus. Jika Anda baru memulai, baca Ringkasan perangkat khusus.

Aplikasi Home kustom

Resep ini berguna jika Anda mengembangkan aplikasi untuk menggantikan Layar utama Android dan Peluncur.

Jadilah aplikasi layar utama

Anda dapat menetapkan aplikasi Anda sebagai aplikasi layar utama perangkat agar diluncurkan secara otomatis saat perangkat dimulai. Anda juga dapat mengaktifkan tombol Beranda yang membawa aplikasi yang diizinkan ke latar depan dalam mode tugas kunci.

Semua aplikasi layar utama menangani kategori intent CATEGORY_HOME—inilah cara sistem mengenali aplikasi layar utama. Untuk menjadi aplikasi layar utama default, tetapkan salah satu aktivitas aplikasi Anda sebagai pengendali intent Home pilihan, dengan memanggil DevicePolicyManager.addPersistentPreferredActivity() seperti yang ditunjukkan pada contoh berikut:

Kotlin

// Create an intent filter to specify the Home category.
val filter = IntentFilter(Intent.ACTION_MAIN)
filter.addCategory(Intent.CATEGORY_HOME)
filter.addCategory(Intent.CATEGORY_DEFAULT)

// Set the activity as the preferred option for the device.
val activity = ComponentName(context, KioskModeActivity::class.java)
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
dpm.addPersistentPreferredActivity(adminName, filter, activity)

Java

// Create an intent filter to specify the Home category.
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);

// Set the activity as the preferred option for the device.
ComponentName activity = new ComponentName(context, KioskModeActivity.class);
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.addPersistentPreferredActivity(adminName, filter, activity);

Anda tetap harus mendeklarasikan filter intent di file manifes aplikasi seperti ditunjukkan dalam cuplikan XML berikut:

<activity
        android:name=".KioskModeActivity"
        android:label="@string/kiosk_mode"
        android:launchMode="singleInstance"
        android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.HOME"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Biasanya Anda tidak ingin aplikasi peluncur muncul di layar Ringkasan. Namun, Anda tidak perlu menambahkan excludeFromRecents ke deklarasi aktivitas karena Peluncur Android menyembunyikan aktivitas yang pertama kali diluncurkan saat sistem berjalan dalam mode mengunci tugas.

Tampilkan tugas terpisah

FLAG_ACTIVITY_NEW_TASK dapat menjadi flag yang berguna untuk aplikasi jenis peluncur karena setiap tugas baru muncul sebagai item terpisah di layar Ringkasan. Untuk mempelajari tugas lebih lanjut di layar Ringkasan, baca Layar Terbaru.

Kios publik

Resep ini bagus untuk perangkat tanpa pengawasan di ruang publik, tetapi juga dapat membantu banyak pengguna perangkat khusus berfokus pada tugas mereka.

Kunci perangkat

Guna membantu memastikan bahwa perangkat digunakan untuk tujuan yang dimaksudkan, Anda dapat menambahkan batasan pengguna yang tercantum pada tabel 1.

Tabel 1. Batasan pengguna untuk perangkat kios
Pembatasan pengguna Deskripsi
DISALLOW_FACTORY_RESET Mencegah pengguna perangkat mereset perangkat ke setelan default pabrik. Admin perangkat terkelola sepenuhnya dan pengguna utama dapat menetapkan batasan ini.
DISALLOW_SAFE_BOOT Mencegah pengguna perangkat memulai perangkat dalam mode aman yang tidak memungkinkan sistem meluncurkan aplikasi secara otomatis. Admin perangkat terkelola sepenuhnya dan pengguna utama dapat menetapkan batasan ini.
DISALLOW_MOUNT_PHYSICAL_MEDIA Mencegah pengguna perangkat memasang volume penyimpanan apa pun yang mungkin dipasang ke perangkat. Admin perangkat terkelola sepenuhnya dan pengguna utama dapat menetapkan batasan ini.
DISALLOW_ADJUST_VOLUME Membisukan perangkat dan mencegah pengguna perangkat mengubah setelan volume suara dan getaran. Pastikan kios Anda tidak memerlukan audio untuk fitur aksesibilitas atau pemutaran media. Admin perangkat terkelola sepenuhnya, pengguna utama, pengguna sekunder, dan profil kerja dapat menetapkan batasan ini.
DISALLOW_ADD_USER Mencegah pengguna perangkat menambahkan pengguna baru, seperti pengguna sekunder atau pengguna yang dibatasi. Sistem akan otomatis menambahkan batasan pengguna ini ke perangkat terkelola sepenuhnya, tetapi batasan tersebut mungkin telah dihapus. Admin perangkat terkelola sepenuhnya dan pengguna utama dapat menetapkan batasan ini.

Cuplikan berikut menunjukkan cara menetapkan pembatasan:

Kotlin

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
arrayOf(
        UserManager.DISALLOW_FACTORY_RESET,
        UserManager.DISALLOW_SAFE_BOOT,
        UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
        UserManager.DISALLOW_ADJUST_VOLUME,
        UserManager.DISALLOW_ADD_USER).forEach { dpm.addUserRestriction(adminName, it) }

Java

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
String[] restrictions = {
    UserManager.DISALLOW_FACTORY_RESET,
    UserManager.DISALLOW_SAFE_BOOT,
    UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    UserManager.DISALLOW_ADJUST_VOLUME,
    UserManager.DISALLOW_ADD_USER};

for (String restriction: restrictions) dpm.addUserRestriction(adminName, restriction);

Anda mungkin perlu menghapus batasan ini saat aplikasi berada dalam mode admin sehingga admin IT masih dapat menggunakan fitur ini untuk pemeliharaan perangkat. Untuk menghapus pembatasan, panggil DevicePolicyManager.clearUserRestriction().

Sembunyikan dialog error

Di beberapa lingkungan, seperti demonstrasi retail atau tampilan informasi publik, Anda mungkin tidak ingin menampilkan dialog error kepada pengguna. Di Android 9.0 (API level 28) atau yang lebih baru, Anda dapat menyembunyikan dialog error sistem untuk aplikasi yang error atau tidak responsif dengan menambahkan pembatasan pengguna DISALLOW_SYSTEM_ERROR_DIALOGS. Sistem akan memulai ulang aplikasi yang tidak responsif seolah-olah pengguna perangkat menutup aplikasi dari dialog. Contoh berikut menunjukkan cara Anda dapat melakukan ini:

Kotlin

override fun onEnabled(context: Context, intent: Intent) {
    val dpm = getManager(context)
    val adminName = getWho(context)

    dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS)
}

Java

public void onEnabled(Context context, Intent intent) {
  DevicePolicyManager dpm = getManager(context);
  ComponentName adminName = getWho(context);

  dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS);
}

Jika admin pengguna utama atau sekunder menetapkan batasan ini, sistem akan menyembunyikan dialog error hanya untuk pengguna tersebut. Jika admin perangkat terkelola sepenuhnya menetapkan batasan ini, sistem akan menyembunyikan dialog untuk semua pengguna.

Menjaga layar agar tetap aktif

Jika membuat kios, Anda dapat menghentikan perangkat agar tidur saat perangkat sedang menjalankan aktivitas aplikasi. Tambahkan tanda tata letak FLAG_KEEP_SCREEN_ON ke jendela aplikasi seperti yang ditunjukkan dalam contoh berikut:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Keep the screen on and bright while this kiosk activity is running.
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}

Java

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

  // Keep the screen on and bright while this kiosk activity is running.
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

Sebaiknya periksa apakah perangkat dicolokkan ke pengisi daya AC, USB, atau nirkabel. Daftarkan siaran perubahan baterai dan gunakan nilai BatteryManager untuk menemukan status pengisian daya. Anda bahkan dapat mengirim peringatan jarak jauh ke admin IT jika perangkat tidak terhubung ke sumber listrik. Untuk petunjuk langkah demi langkah, baca Memantau Level Baterai dan Status Pengisian Daya.

Anda juga dapat menetapkan setelan global STAY_ON_WHILE_PLUGGED_IN agar perangkat tetap aktif saat terhubung ke sumber listrik. Admin perangkat terkelola sepenuhnya, di Android 6.0 (API level 23) atau yang lebih baru, dapat memanggil DevicePolicyManager.setGlobalSetting() seperti yang ditunjukkan dalam contoh berikut:

Kotlin

val pluggedInto = BatteryManager.BATTERY_PLUGGED_AC or
        BatteryManager.BATTERY_PLUGGED_USB or
        BatteryManager.BATTERY_PLUGGED_WIRELESS
dpm.setGlobalSetting(adminName,
        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, pluggedInto.toString())

Java

int pluggedInto = BatteryManager.BATTERY_PLUGGED_AC |
    BatteryManager.BATTERY_PLUGGED_USB |
    BatteryManager.BATTERY_PLUGGED_WIRELESS;
dpm.setGlobalSetting( adminName,
    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, String.valueOf(pluggedInto));

Paket aplikasi

Bagian ini berisi resep untuk menginstal aplikasi secara efisien ke perangkat khusus.

Menyimpan paket aplikasi dalam cache

Jika pengguna perangkat bersama semuanya memiliki kumpulan aplikasi umum, sebaiknya hindari mendownload aplikasi jika memungkinkan. Untuk menyederhanakan penyediaan pengguna di perangkat bersama dengan sekumpulan pengguna tetap, seperti perangkat untuk pekerja shift, di Android 9.0 (API level 28) atau yang lebih baru, Anda dapat menyimpan cache paket aplikasi (APK) yang diperlukan untuk sesi multi-pengguna.

Penginstalan APK yang di-cache (yang sudah terinstal di perangkat) terjadi dalam dua tahap:

  1. Komponen admin dari perangkat yang terkelola sepenuhnya (atau delegasi—lihat berikut) menetapkan daftar APK yang akan dipertahankan di perangkat.
  2. Komponen admin dari pengguna sekunder yang berafiliasi (atau delegasinya) dapat menginstal APK yang di-cache atas nama pengguna. Admin perangkat terkelola sepenuhnya, pengguna utama, atau profil kerja yang berafiliasi (atau delegasinya) juga dapat menginstal aplikasi yang di-cache jika diperlukan.

Untuk menetapkan daftar APK yang akan dipertahankan di perangkat, admin akan memanggil DevicePolicyManager.setKeepUninstalledPackages(). Metode ini tidak memeriksa apakah APK telah diinstal di perangkat—berguna jika Anda ingin menginstal aplikasi tepat sebelum Anda membutuhkannya untuk pengguna. Untuk mendapatkan daftar paket yang telah ditetapkan sebelumnya, Anda dapat memanggil DevicePolicyManager.getKeepUninstalledPackages(). Setelah Anda memanggil setKeepUninstalledPackages() dengan perubahan, atau saat pengguna sekunder dihapus, sistem akan menghapus APK yang di-cache yang tidak diperlukan lagi.

Untuk menginstal APK yang di-cache, panggil DevicePolicyManager.installExistingPackage(). Metode ini hanya dapat menginstal aplikasi yang telah di-cache oleh sistem—solusi perangkat khusus Anda (atau pengguna perangkat) harus terlebih dahulu menginstal aplikasi di perangkat sebelum Anda dapat memanggil metode ini.

Contoh berikut menunjukkan cara menggunakan panggilan API ini di admin perangkat terkelola sepenuhnya dan pengguna sekunder:

Kotlin

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
val cachedAppPackageName = "com.example.android.myapp"
dpm.setKeepUninstalledPackages(adminName, listOf(cachedAppPackageName))

// ...

// The admin of a secondary user installs the app.
val success = dpm.installExistingPackage(adminName, cachedAppPackageName)

Java

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
String cachedAppPackageName = "com.example.android.myapp";
List<String> packages = new ArrayList<String>();
packages.add(cachedAppPackageName);
dpm.setKeepUninstalledPackages(adminName, packages);

// ...

// The admin of a secondary user installs the app.
boolean success = dpm.installExistingPackage(adminName, cachedAppPackageName);

Mendelegasikan aplikasi

Anda dapat mendelegasikan aplikasi lain untuk mengelola cache aplikasi. Anda dapat melakukannya untuk memisahkan fitur solusi atau menawarkan kemampuan kepada admin IT untuk menggunakan aplikasi mereka sendiri. Aplikasi delegasi mendapatkan izin yang sama dengan komponen admin. Misalnya, delegasi aplikasi dari admin pengguna sekunder dapat memanggil installExistingPackage(), tetapi tidak dapat memanggil setKeepUninstalledPackages().

Untuk membuat delegasi, panggil DevicePolicyManager.setDelegatedScopes() dan sertakan DELEGATION_KEEP_UNINSTALLED_PACKAGES dalam argumen cakupan. Contoh berikut menunjukkan cara agar aplikasi lain dapat menjadi delegasi:

Kotlin

var delegatePackageName = "com.example.tools.kept_app_assist"

// Check that the package is installed before delegating.
try {
    context.packageManager.getPackageInfo(delegatePackageName, 0)
    dpm.setDelegatedScopes(
            adminName,
            delegatePackageName,
            listOf(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES))
} catch (e: PackageManager.NameNotFoundException) {
    // The delegate app isn't installed. Send a report to the IT admin ...
}

Java

String delegatePackageName = "com.example.tools.kept_app_assist";

// Check that the package is installed before delegating.
try {
  context.getPackageManager().getPackageInfo(delegatePackageName, 0);
  dpm.setDelegatedScopes(
      adminName,
      delegatePackageName,
      Arrays.asList(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES));
} catch (PackageManager.NameNotFoundException e) {
  // The delegate app isn't installed. Send a report to the IT admin ...
}

Jika semuanya berjalan lancar, aplikasi delegasi akan menerima siaran ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED dan menjadi delegasi. Aplikasi dapat memanggil metode dalam panduan ini seolah-olah aplikasi tersebut adalah pemilik perangkat atau pemilik profil. Saat memanggil metode DevicePolicyManager, delegasi akan meneruskan null untuk argumen komponen admin.

Menginstal paket aplikasi

Terkadang, ada gunanya menginstal aplikasi kustom yang di-cache secara lokal ke perangkat khusus. Misalnya, perangkat khusus sering di-deploy ke lingkungan atau area dengan bandwidth terbatas tanpa konektivitas internet. Solusi perangkat khusus Anda harus memperhatikan bandwidth pelanggan. Aplikasi Anda dapat memulai penginstalan paket aplikasi (APK) lain menggunakan class PackageInstaller.

Meskipun aplikasi apa pun dapat menginstal APK, admin di perangkat yang terkelola sepenuhnya dapat menginstal (atau meng-uninstal) paket tanpa interaksi pengguna. Admin dapat mengelola perangkat, pengguna sekunder yang berafiliasi, atau profil kerja yang berafiliasi. Setelah menyelesaikan penginstalan, sistem akan memposting notifikasi yang dilihat oleh semua pengguna perangkat. Notifikasi ini memberi tahu pengguna perangkat bahwa aplikasi telah diinstal (atau diupdate) oleh admin mereka.

Tabel 2. Versi Android yang mendukung penginstalan paket tanpa interaksi pengguna
Versi Android Komponen admin untuk penginstalan dan uninstal
Android 9.0 (API level 28) atau yang lebih tinggi Pengguna sekunder dan profil kerja yang berafiliasi—baik di perangkat yang terkelola sepenuhnya
Android 6.0 (API level 23) atau yang lebih tinggi Perangkat terkelola sepenuhnya

Cara Anda mendistribusikan satu atau beberapa salinan APK ke perangkat khusus akan bergantung pada seberapa jauh perangkat tersebut dan mungkin seberapa jauh jarak perangkat satu sama lain. Solusi Anda harus mengikuti praktik terbaik keamanan sebelum menginstal APK ke perangkat khusus.

Anda dapat menggunakan PackageInstaller.Session untuk membuat sesi yang mengantrekan satu atau beberapa APK untuk diinstal. Pada contoh berikut, kita menerima masukan status dalam aktivitas (mode singleTop), tetapi Anda dapat menggunakan layanan atau penerima siaran:

Kotlin

// First, create a package installer session.
val packageInstaller = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(
        PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
// The I/O streams can't be open when installation begins.
session.openWrite("apk", 0, -1).use { output ->
    getContext().resources.openRawResource(R.raw.app).use { input ->
        input.copyTo(output, 2048)
    }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
val intent = Intent(context, activity.javaClass)
intent.action = "com.android.example.APK_INSTALLATION_ACTION"
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val statusReceiver = pendingIntent.intentSender

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver)

Java

// First, create a package installer session.
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
try (
    // These I/O streams can't be open when installation begins.
    OutputStream output = session.openWrite("apk", 0, -1);
    InputStream input = getContext().getResources().openRawResource(R.raw.app);
) {
  byte[] buffer = new byte[2048];
  int n;
  while ((n = input.read(buffer)) >= 0) {
    output.write(buffer, 0, n);
  }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
Intent intent = new Intent(context, getActivity().getClass());
intent.setAction("com.android.example.APK_INSTALLATION_ACTION");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver);

Sesi ini mengirimkan masukan status tentang penginstalan menggunakan intent. Periksa setiap kolom EXTRA_STATUS intent untuk mendapatkan status. Ingat, admin tidak menerima update status STATUS_PENDING_USER_ACTION karena pengguna perangkat tidak perlu menyetujui penginstalan.

Untuk meng-uninstal aplikasi, Anda dapat memanggil PackageInstaller.uninstall. Admin perangkat terkelola sepenuhnya, pengguna, dan profil kerja dapat meng-uninstal paket tanpa interaksi pengguna yang menjalankan versi Android yang didukung (lihat tabel 2).

Membekukan update sistem

Perangkat Android menerima update over the air (OTA) untuk software sistem dan aplikasi. Untuk membekukan versi OS selama periode penting, seperti hari libur atau waktu sibuk lainnya, perangkat khusus dapat menangguhkan update sistem OTA hingga 90 hari. Untuk mempelajari lebih lanjut, baca Mengelola update sistem.

Remote config

Konfigurasi terkelola Android memungkinkan admin IT mengonfigurasi aplikasi dari jarak jauh. Anda dapat menampilkan setelan seperti daftar yang diizinkan, host jaringan, atau URL konten agar aplikasi lebih berguna bagi admin IT.

Jika aplikasi Anda mengekspos konfigurasinya, jangan lupa untuk menyertakan setelan dalam dokumentasi Anda. Untuk mempelajari lebih lanjut cara mengekspos konfigurasi aplikasi dan merespons perubahan setelan, baca Menyiapkan konfigurasi terkelola.

Penyiapan pengembangan

Saat Anda mengembangkan solusi untuk perangkat khusus, terkadang ada baiknya untuk menetapkan aplikasi Anda sebagai admin perangkat yang terkelola sepenuhnya tanpa mereset ke setelan pabrik. Untuk menyetel admin perangkat terkelola sepenuhnya, ikuti langkah-langkah berikut:

  1. Bangun dan instal aplikasi pengontrol kebijakan perangkat (DPC) di perangkat.
  2. Pastikan tidak ada akun di perangkat.
  3. Jalankan perintah berikut di shell Android Debug Bridge (adb). Anda harus mengganti com.example.dpc/.MyDeviceAdminReceiver dalam contoh dengan nama komponen admin aplikasi Anda:

    adb shell dpm set-device-owner com.example.dpc/.MyDeviceAdminReceiver

Untuk membantu pelanggan men-deploy solusi, Anda harus melihat metode pendaftaran lain. Sebaiknya pendaftaran kode QR untuk perangkat khusus.

Referensi lainnya

Untuk mempelajari perangkat khusus lebih lanjut, baca dokumen berikut: