Panduan developer ini menjelaskan bagaimana pengontrol kebijakan perangkat (DPC) Anda dapat mengelola beberapa pengguna Android di perangkat khusus.
Ringkasan
DPC dapat membantu beberapa orang berbagi satu perangkat khusus. DPC Anda berjalan di perangkat terkelola sepenuhnya dapat membuat dan mengelola dua jenis pengguna:
- Pengguna sekunder adalah pengguna Android yang menyimpan aplikasi dan data terpisah antar sesi. Anda mengelola pengguna dengan komponen admin. Para pengguna ini berguna untuk kasus di mana perangkat diambil ketika {i>shift<i} bekerja, seperti pengemudi pengiriman atau petugas keamanan.
- Pengguna ephemeral adalah pengguna sekunder yang dihapus oleh sistem saat pengguna berhenti, beralih, atau perangkat dimulai ulang. Para pengguna ini berguna dalam berbagai kasus di mana data dapat dihapus setelah sesi selesai, seperti akses publik kios internet.
Anda menggunakan DPC yang ada untuk mengelola perangkat khusus dan DPC sekunder pelanggan. Komponen admin di DPC menetapkan dirinya sendiri sebagai admin untuk fitur sekunder baru pengguna saat Anda membuatnya.
Admin pengguna sekunder harus berada dalam paket yang sama dengan admin pengguna merupakan perangkat yang terkelola sepenuhnya. Untuk menyederhanakan pengembangan, sebaiknya Anda membagikan informasi antara perangkat dan pengguna sekunder.
Mengelola banyak pengguna pada perangkat khusus biasanya memerlukan Android 9.0, namun beberapa metode yang digunakan dalam panduan pengembang ini tersedia di Android versi sebelumnya.
Pengguna sekunder
Pengguna sekunder dapat terhubung ke Wi-Fi dan dapat mengonfigurasi jaringan baru. Namun, mereka tidak dapat mengedit atau menghapus jaringan, bahkan jaringan yang mereka buat.
Membuat pengguna
DPC dapat membuat pengguna tambahan di latar belakang dan kemudian dapat mengalihkannya ke latar depan. Prosesnya hampir sama, baik untuk sekunder maupun {i>ephemeral user<i}. Terapkan langkah-langkah berikut untuk Admin perangkat terkelola dan pengguna sekunder:
- Panggil
DevicePolicyManager.createAndManageUser()
. Untuk membuat pengguna efemeral, sertakanMAKE_USER_EPHEMERAL
dalam argumen flag. - Telepon
DevicePolicyManager.startUserInBackground()
ke memulai aktivitas pengguna di latar belakang. Pengguna mulai berlari tetapi Anda perlu untuk menyelesaikan penyiapan sebelum membawa pengguna ke latar depan dan menampilkannya kepada pengguna yang menggunakan perangkat. - Pada admin pengguna sekunder, panggil
DevicePolicyManager.setAffiliationIds()
ke mengafiliasi pengguna baru dengan pengguna utama. Lihat Koordinasi DPC di bawah. - Kembali ke admin perangkat terkelola sepenuhnya, panggil
DevicePolicyManager.switchUser()
untuk mengalihkan pengguna ke latar depan.
Contoh berikut menunjukkan cara menambahkan langkah 1 ke DPC:
Kotlin
val dpm = getContext().getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager // If possible, reuse an existing affiliation ID across the // primary user and (later) the ephemeral user. val identifiers = dpm.getAffiliationIds(adminName) if (identifiers.isEmpty()) { identifiers.add(UUID.randomUUID().toString()) dpm.setAffiliationIds(adminName, identifiers) } // Pass an affiliation ID to the ephemeral user in the admin extras. val adminExtras = PersistableBundle() adminExtras.putString(AFFILIATION_ID_KEY, identifiers.first()) // Include any other config for the new user here ... // Create the ephemeral user, using this component as the admin. try { val ephemeralUser = dpm.createAndManageUser( adminName, "tmp_user", adminName, adminExtras, DevicePolicyManager.MAKE_USER_EPHEMERAL or DevicePolicyManager.SKIP_SETUP_WIZARD) } catch (e: UserManager.UserOperationException) { if (e.userOperationResult == UserManager.USER_OPERATION_ERROR_MAX_USERS) { // Find a way to free up users... } }
Java
DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); // If possible, reuse an existing affiliation ID across the // primary user and (later) the ephemeral user. Set<String> identifiers = dpm.getAffiliationIds(adminName); if (identifiers.isEmpty()) { identifiers.add(UUID.randomUUID().toString()); dpm.setAffiliationIds(adminName, identifiers); } // Pass an affiliation ID to the ephemeral user in the admin extras. PersistableBundle adminExtras = new PersistableBundle(); adminExtras.putString(AFFILIATION_ID_KEY, identifiers.iterator().next()); // Include any other config for the new user here ... // Create the ephemeral user, using this component as the admin. try { UserHandle ephemeralUser = dpm.createAndManageUser( adminName, "tmp_user", adminName, adminExtras, DevicePolicyManager.MAKE_USER_EPHEMERAL | DevicePolicyManager.SKIP_SETUP_WIZARD); } catch (UserManager.UserOperationException e) { if (e.getUserOperationResult() == UserManager.USER_OPERATION_ERROR_MAX_USERS) { // Find a way to free up users... } }
Saat membuat atau memulai pengguna baru, Anda dapat memeriksa alasan kegagalan
dengan mengambil pengecualian UserOperationException
dan memanggil
getUserOperationResult()
. Melebihi jumlah pengguna
batas adalah alasan kegagalan yang umum:
Membuat pengguna dapat memerlukan waktu beberapa saat. Jika Anda sering membuat pengguna, Anda dapat meningkatkan pengalaman pengguna dengan menyiapkan pengguna yang siap digunakan di latar belakang. Anda mungkin perlu menyeimbangkan keuntungan dari pengguna yang siap pakai dengan jumlah pengguna yang diizinkan di suatu perangkat.
Identifikasi
Setelah membuat pengguna baru, Anda harus merujuk ke pengguna dengan
angka Jangan mempertahankan UserHandle
karena sistem mendaur ulangnya saat Anda
membuat dan menghapus pengguna. Dapatkan nomor seri dengan memanggil
UserManager.getSerialNumberForUser()
:
Kotlin
// After calling createAndManageUser() use a device-unique serial number // (that isn’t recycled) to identify the new user. secondaryUser?.let { val userManager = getContext().getSystemService(UserManager::class.java) val ephemeralUserId = userManager!!.getSerialNumberForUser(it) // Save the serial number to storage ... }
Java
// After calling createAndManageUser() use a device-unique serial number // (that isn’t recycled) to identify the new user. if (secondaryUser != null) { UserManager userManager = getContext().getSystemService(UserManager.class); long ephemeralUserId = userManager.getSerialNumberForUser(secondaryUser); // Save the serial number to storage ... }
Konfigurasi pengguna
Bergantung pada kebutuhan pengguna, Anda dapat menyesuaikan penyiapan
pelanggan. Anda dapat menyertakan tanda berikut saat memanggil createAndManageUser()
:
SKIP_SETUP_WIZARD
- Melewati menjalankan wizard penyiapan pengguna baru yang memeriksa dan menginstal update, meminta pengguna untuk menambahkan Akun Google beserta layanan Google, dan menetapkan kunci layar. Proses ini dapat memerlukan waktu beberapa saat dan mungkin tidak berlaku untuk semua pengguna pengguna—misalnya kios internet publik.
LEAVE_ALL_SYSTEM_APPS_ENABLED
- Membiarkan semua aplikasi sistem tetap aktif di pengguna baru. Jika Anda tidak menetapkan penanda ini, pengguna baru hanya berisi serangkaian aplikasi minimal yang diperlukan ponsel beroperasi—biasanya {i>file browser<i}, telepon telepon, kontak, dan pesan SMS.
Mengikuti siklus proses pengguna
DPC (jika admin perangkat terkelola sepenuhnya) mungkin merasa terbantu untuk
mengetahui kapan pengguna
sekunder berubah. Untuk menjalankan tugas lanjutan setelah perubahan, ganti
metode callback berikut di subclass DeviceAdminReceiver
DPC:
onUserStarted()
- Dipanggil setelah sistem memulai pengguna. Pengguna ini mungkin
masih menyiapkan atau
berjalan di latar belakang. Anda bisa mendapatkan pengguna dari
startedUser
argumen. onUserSwitched()
- Dipanggil setelah sistem beralih ke pengguna lain. Anda bisa mendapatkan
pengguna baru
yang sekarang berjalan di latar depan dari argumen
switchedUser
. onUserStopped()
- Dipanggil setelah sistem menghentikan pengguna karena mereka telah logout, beralih ke
pengguna baru (jika pengguna bersifat sementara), atau DPC menghentikan pengguna. Anda bisa mendapatkan
pengguna dari argumen
stoppedUser
. onUserAdded()
- Dipanggil saat sistem menambahkan pengguna baru. Biasanya, pengguna
sekunder tidak
sudah disiapkan sepenuhnya ketika
DPC mendapatkan callback. Anda bisa mendapatkan pengguna dari
Argumen
newUser
. onUserRemoved()
- Dipanggil setelah sistem menghapus pengguna. Karena pengguna sudah dihapus,
Anda tidak dapat mengakses pengguna yang diwakili oleh argumen
removedUser
.
Untuk mengetahui kapan sistem membawa pengguna ke latar depan atau mengirim pengguna ke
latar belakang, aplikasi dapat mendaftarkan penerima untuk
ACTION_USER_FOREGROUND
dan
ACTION_USER_BACKGROUND
.
Temukan pengguna
Untuk mendapatkan semua pengguna sekunder, admin perangkat terkelola sepenuhnya dapat memanggil
DevicePolicyManager.getSecondaryUsers()
Hasil
termasuk pengguna sekunder atau {i>ephemeral<i} yang dibuat oleh admin. Hasilnya juga
termasuk pengguna sekunder (atau pengguna tamu) yang mungkin digunakan seseorang
buat. Hasil penelusuran tidak menyertakan profil kerja karena belum
pengguna sekunder. Contoh berikut menunjukkan cara menggunakan metode ini:
Kotlin
// The device is stored for the night. Stop all running secondary users. dpm.getSecondaryUsers(adminName).forEach { dpm.stopUser(adminName, it) }
Java
// The device is stored for the night. Stop all running secondary users. for (UserHandle user : dpm.getSecondaryUsers(adminName)) { dpm.stopUser(adminName, user); }
Berikut adalah metode lain yang dapat Anda panggil untuk mengetahui status pengguna sekunder:
DevicePolicyManager.isEphemeralUser()
- Panggil metode ini dari admin pengguna sekunder untuk mengetahui apakah ini pengguna singkat.
DevicePolicyManager.isAffiliatedUser()
- Panggil metode ini dari admin pengguna sekunder untuk mengetahui apakah pengguna ini berafiliasi dengan pengguna utama. Untuk mempelajari afiliasi lebih lanjut, lihat DPC koordinasi di bawah ini.
Pengelolaan pengguna
Jika Anda ingin mengelola siklus proses pengguna sepenuhnya, Anda dapat memanggil API untuk mengontrol kapan dan bagaimana perangkat mengubah pengguna. Sebagai contoh, Anda dapat menghapus pengguna jika perangkat tidak digunakan selama jangka waktu tertentu atau Anda dapat mengirim pesanan yang tidak terkirim ke server sebelum {i>shift<i} seseorang selesai.
Keluar
Android 9.0 menambahkan tombol {i>log-out<i} ke layar kunci sehingga seseorang yang menggunakan dapat mengakhiri sesinya. Setelah mengetuk tombol tersebut, sistem akan menghentikan pengguna sekunder, menghapus pengguna jika bersifat sementara, dan pengguna utama kembali ke latar depan. Android menyembunyikan tombol saat pengguna utama berada di latar depan karena pengguna utama tidak dapat keluar.
Android tidak menampilkan tombol akhiri sesi secara default, tetapi admin Anda (dari
perangkat terkelola sepenuhnya) dapat mengaktifkannya dengan memanggil
DevicePolicyManager.setLogoutEnabled()
Jika Anda ingin
mengkonfirmasi status tombol saat ini, memanggil
DevicePolicyManager.isLogoutEnabled()
Admin pengguna sekunder dapat membuat pengguna logout secara terprogram dan kembali
kepada pengguna utama. Pertama, pastikan pengguna
sekunder dan utama adalah
terafiliasi, lalu panggil DevicePolicyManager.logoutUser()
. Jika
pengguna yang {i>log-out<i} adalah pengguna {i>ephemeral<i},
sistem berhenti dan kemudian menghapus
.
Ganti pengguna
Untuk beralih ke pengguna sekunder lain, admin perangkat terkelola sepenuhnya dapat
panggil DevicePolicyManager.switchUser()
. Untuk memudahkan, Anda
dapat meneruskan null
untuk beralih ke pengguna utama.
Menghentikan pengguna
Untuk menghentikan pengguna sekunder, DPC yang memiliki perangkat terkelola sepenuhnya dapat memanggil
DevicePolicyManager.stopUser()
Jika pengguna yang
berhenti adalah
{i>ephemeral user<i}, pengguna dihentikan kemudian dihapus.
Sebaiknya hentikan pengguna jika memungkinkan agar tetap berada di bawah batas perangkat jumlah maksimum pengguna berjalan.
Menghapus pengguna
Untuk menghapus pengguna sekunder secara permanen, DPC dapat memanggil salah satu
Metode DevicePolicyManager
:
- Admin perangkat terkelola sepenuhnya dapat memanggil
removeUser()
. - Admin pengguna sekunder dapat memanggil
wipeData()
.
Sistem menghapus pengguna sementara saat mereka logout, dihentikan, atau diganti jauh darinya.
Menonaktifkan UI default
Jika DPC menyediakan UI untuk mengelola pengguna, Anda dapat menonaktifkan fitur bawaan Android
{i>multi-user interface<i}. Anda dapat melakukan ini
dengan memanggil
DevicePolicyManager.setLogoutEnabled()
dan menambahkan
Pembatasan DISALLOW_USER_SWITCH
seperti yang ditunjukkan di
contoh berikut:
Kotlin
// Explicitly disallow logging out using Android UI (disabled by default). dpm.setLogoutEnabled(adminName, false) // Disallow switching users in Android's UI. This DPC can still // call switchUser() to manage users. dpm.addUserRestriction(adminName, UserManager.DISALLOW_USER_SWITCH)
Java
// Explicitly disallow logging out using Android UI (disabled by default). dpm.setLogoutEnabled(adminName, false); // Disallow switching users in Android's UI. This DPC can still // call switchUser() to manage users. dpm.addUserRestriction(adminName, UserManager.DISALLOW_USER_SWITCH);
Pengguna perangkat tidak dapat menambahkan pengguna sekunder dengan UI bawaan Android
karena admin perangkat terkelola sepenuhnya akan otomatis menambahkan
Batasan pengguna DISALLOW_ADD_USER
.
Pesan sesi
Saat pengguna yang menggunakan perangkat beralih ke pengguna baru, Android akan menampilkan panel untuk menyoroti {i>switch<i}. Android akan menampilkan pesan berikut:
- Pesan sesi pengguna awal ditampilkan saat perangkat beralih ke pesan sekunder dari pengguna utama.
- Pesan sesi pengguna akhir ditampilkan saat perangkat kembali ke pengguna utama dari pengguna sekunder.
Sistem tidak menampilkan pesan saat beralih di antara dua pengguna sekunder.
Karena pesan mungkin tidak cocok untuk semua situasi, Anda dapat mengubah teks dari pesan tersebut. Misalnya, jika solusi Anda menggunakan pengguna {i>ephemeral<i} Anda dapat merefleksikannya dalam pesan seperti: Menghentikan browser sesi & menghapus data pribadi...
Sistem menampilkan pesan selama beberapa detik, jadi setiap pesan
harus berupa frasa yang singkat dan jelas. Untuk menyesuaikan pesan, admin Anda dapat memanggil
metode DevicePolicyManager
setStartUserSessionMessage()
dan
setEndUserSessionMessage()
seperti yang ditampilkan di
contoh berikut:
Kotlin
// Short, easy-to-read messages shown at the start and end of a session. // In your app, store these strings in a localizable resource. internal val START_USER_SESSION_MESSAGE = "Starting guest session…" internal val END_USER_SESSION_MESSAGE = "Stopping & clearing data…" // ... dpm.setStartUserSessionMessage(adminName, START_USER_SESSION_MESSAGE) dpm.setEndUserSessionMessage(adminName, END_USER_SESSION_MESSAGE)
Java
// Short, easy-to-read messages shown at the start and end of a session. // In your app, store these strings in a localizable resource. private static final String START_USER_SESSION_MESSAGE = "Starting guest session…"; private static final String END_USER_SESSION_MESSAGE = "Stopping & clearing data…"; // ... dpm.setStartUserSessionMessage(adminName, START_USER_SESSION_MESSAGE); dpm.setEndUserSessionMessage(adminName, END_USER_SESSION_MESSAGE);
Teruskan null
untuk menghapus pesan kustom Anda dan kembali ke setelan default Android
membuat pesan teks. Jika Anda perlu memeriksa teks pesan saat ini, hubungi
getStartUserSessionMessage()
atau
getEndUserSessionMessage()
.
DPC Anda harus menetapkan pesan yang dilokalkan untuk lokalitas pengguna saat ini. Anda juga perlu memperbarui pesan saat perubahan lokal pengguna:
Kotlin
override fun onReceive(context: Context?, intent: Intent?) { // Added the <action android:name="android.intent.action.LOCALE_CHANGED" /> // intent filter for our DeviceAdminReceiver subclass in the app manifest file. if (intent?.action === ACTION_LOCALE_CHANGED) { // Android's resources return a string suitable for the new locale. getManager(context).setStartUserSessionMessage( getWho(context), context?.getString(R.string.start_user_session_message)) getManager(context).setEndUserSessionMessage( getWho(context), context?.getString(R.string.end_user_session_message)) } super.onReceive(context, intent) }
Java
public void onReceive(Context context, Intent intent) { // Added the <action android:name="android.intent.action.LOCALE_CHANGED" /> // intent filter for our DeviceAdminReceiver subclass in the app manifest file. if (intent.getAction().equals(ACTION_LOCALE_CHANGED)) { // Android's resources return a string suitable for the new locale. getManager(context).setStartUserSessionMessage( getWho(context), context.getString(R.string.start_user_session_message)); getManager(context).setEndUserSessionMessage( getWho(context), context.getString(R.string.end_user_session_message)); } super.onReceive(context, intent); }
Koordinasi DPC
Mengelola pengguna sekunder biasanya memerlukan dua instance DPC—satu yang memiliki perangkat terkelola sepenuhnya sementara yang lain memiliki pengguna sekunder. Saat membuat pengguna baru, admin perangkat terkelola sepenuhnya menyetel instance lain dirinya sebagai admin pengguna baru.
Pengguna terafiliasi
Beberapa API dalam panduan developer ini hanya berfungsi saat pengguna sekunder berafiliasi. Karena Android menonaktifkan beberapa fitur (misalnya logging jaringan) saat Anda menambahkan pengguna sekunder baru yang tidak terafiliasi ke perangkat itu, Anda harus segera mengafiliasi pengguna sesegera mungkin. Lihat contohnya di Penyiapan di bawah.
Penyiapan
Siapkan pengguna sekunder baru (dari DPC yang memiliki pengguna sekunder) sebelum
mengizinkan orang
menggunakannya. Anda dapat melakukan pengaturan ini dari
Callback DeviceAdminReceiver.onEnabled()
. Jika sebelumnya Anda
menyetel tambahan admin apa pun dalam panggilan ke createAndManageUser()
, Anda bisa mendapatkan
nilai dari argumen intent
. Contoh berikut menunjukkan DPC yang berafiliasi
pengguna sekunder baru di callback:
Kotlin
override fun onEnabled(context: Context?, intent: Intent?) { super.onEnabled(context, intent) // Get the affiliation ID (our DPC previously put in the extras) and // set the ID for this new secondary user. intent?.getStringExtra(AFFILIATION_ID_KEY)?.let { val dpm = getManager(context) dpm.setAffiliationIds(getWho(context), setOf(it)) } // Continue setup of the new secondary user ... }
Java
public void onEnabled(Context context, Intent intent) { // Get the affiliation ID (our DPC previously put in the extras) and // set the ID for this new secondary user. String affiliationId = intent.getStringExtra(AFFILIATION_ID_KEY); if (affiliationId != null) { DevicePolicyManager dpm = getManager(context); dpm.setAffiliationIds(getWho(context), new HashSet<String>(Arrays.asList(affiliationId))); } // Continue setup of the new secondary user ... }
RPC antar-DPC
Meskipun dua instance DPC berjalan di bawah pengguna terpisah, DPC
yang memiliki perangkat dan pengguna sekunder
dapat berkomunikasi satu sama lain.
Karena memanggil layanan DPC lain melewati batas pengguna, DPC Anda tidak bisa
hubungi bindService()
seperti yang biasa Anda lakukan
Android. Untuk mengikat ke
layanan yang berjalan di
pengguna lain, panggil
DevicePolicyManager.bindDeviceAdminServiceAsUser()
DPC hanya dapat mengikat ke layanan yang berjalan di pengguna yang dikembalikan oleh
DevicePolicyManager.getBindDeviceAdminTargetUsers()
Contoh berikut menunjukkan admin dari binding pengguna sekunder ke admin
dari perangkat terkelola sepenuhnya:
Kotlin
// From a secondary user, the list contains just the primary user. dpm.getBindDeviceAdminTargetUsers(adminName).forEach { // Set up the callbacks for the service connection. val intent = Intent(mContext, FullyManagedDeviceService::class.java) val serviceconnection = object : ServiceConnection { override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) { // Call methods on service ... } override fun onServiceDisconnected(componentName: ComponentName) { // Clean up or reconnect if needed ... } } // Bind to the service as the primary user [it]. val bindSuccessful = dpm.bindDeviceAdminServiceAsUser(adminName, intent, serviceconnection, Context.BIND_AUTO_CREATE, it) }
Java
// From a secondary user, the list contains just the primary user. List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(adminName); if (targetUsers.isEmpty()) { // If the users aren't affiliated, the list doesn't contain any users. return; } // Set up the callbacks for the service connection. Intent intent = new Intent(mContext, FullyManagedDeviceService.class); ServiceConnection serviceconnection = new ServiceConnection() { @Override public void onServiceConnected( ComponentName componentName, IBinder iBinder) { // Call methods on service ... } @Override public void onServiceDisconnected(ComponentName componentName) { // Clean up or reconnect if needed ... } }; // Bind to the service as the primary user. UserHandle primaryUser = targetUsers.get(0); boolean bindSuccessful = dpm.bindDeviceAdminServiceAsUser( adminName, intent, serviceconnection, Context.BIND_AUTO_CREATE, primaryUser);
Referensi lainnya
Untuk mempelajari perangkat khusus lebih lanjut, baca dokumen berikut:
- Ringkasan perangkat khusus adalah ringkasan dari perangkat yang terdedikasi.
- Mode kunci tugas menjelaskan cara mengunci perangkat khusus ke satu atau serangkaian aplikasi.
- Buku resep perangkat khusus dengan contoh lebih lanjut untuk membatasi perangkat khusus dan meningkatkan performa pengalaman yang lancar bagi developer.