複数のユーザーの管理

このデベロッパー ガイドでは、Device Policy Controller(DPC)が 専用デバイスで複数の Android ユーザーを管理する

概要

DPC を使用すると、複数のユーザーが 1 台の専用デバイスを共有できます。お客様の DPC アプリは、次の 2 種類のユーザーを作成、管理できます。

  • セカンダリ ユーザー: 個別のアプリやデータが保存されている Android ユーザー できます。管理コンポーネントでユーザーを管理します。これらのユーザーは シフトの開始時にデバイスを回収する場合に便利です。 配達員やセキュリティ担当者です。
  • エフェメラル ユーザーはセカンダリ ユーザーで、ユーザーが デバイスが停止する、切り替わるか、デバイスが再起動する場合もあります。これらのユーザーは セッション終了後にデータを削除できる場所(public-access など) キオスクなどもあります
で確認できます。

既存の DPC を使用して、専用デバイスとセカンダリ できます。DPC の管理コンポーネントが自身を新しいセカンダリの管理者として設定する ユーザーを作成できます。

プライマリ ユーザーと 2 人のセカンダリ ユーザー。
図 1. 管理コンソールから管理者が管理するプライマリ ユーザーとセカンダリ ユーザー 同じ DPC

セカンダリ ユーザーの管理者は、 完全管理対象デバイスです開発を簡素化するために、管理者を共有することを デバイスとセカンダリ ユーザー間の

専用デバイスで複数のユーザーを管理するには、通常は Android 9.0 が必要です。 ただし、このデベロッパー ガイドで使用されているメソッドの一部は、 使用できます。

セカンダリ ユーザー

セカンダリ ユーザーは Wi-Fi に接続し、新しいネットワークを設定できます。ただし、 ネットワークの編集や削除はできません。作成したネットワークは対象外です。

ユーザーを作成する

DPC はバックグラウンドで追加のユーザーを作成して、ユーザーを切り替えることができます。 起動します。プロセスは、セカンダリと 保護します。完全な Google Cloud コンソールの管理者に次の手順を 管理対象デバイスとセカンダリ ユーザー:

  1. DevicePolicyManager.createAndManageUser() を呼び出します。 一時ユーザーを作成するには、 フラグ引数の MAKE_USER_EPHEMERAL
  2. 発信 DevicePolicyManager.startUserInBackground()~ バックグラウンドで起動させますユーザーが実行を開始しますが、 セットアップを完了してから、ユーザーをフォアグラウンドに移して 操作できます。
  3. セカンダリ ユーザーの管理者として、 DevicePolicyManager.setAffiliationIds()~ 新しいユーザーをプライマリユーザーと関連付けます詳しくは、 DPC の調整をご覧ください。
  4. 完全管理対象デバイスの管理者に戻り、 DevicePolicyManager.switchUser(): ユーザーを 使用できます。

次のサンプルは、DPC にステップ 1 を追加する方法を示しています。

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

新しいユーザーを作成または開始するときに、失敗の理由を確認できます UserOperationException 例外をキャッチして getUserOperationResult()。ユーザーの超過 上限は、一般的な失敗の原因となります。

で確認できます。

ユーザーの作成には時間がかかることがあります。ユーザーを頻繁に作成する場合は、 すぐに使えるユーザーをバックグラウンドで準備して、ユーザー エクスペリエンスを向上させる。 場合によっては、すぐに使えるユーザーのメリットと、 1 台のデバイスで許可されるユーザーの数。

共感

新しいユーザーを作成したら、永続的なシリアル番号でユーザーを参照する必要があります。 あります。UserHandle は保持しないでください。これらはシステムが再利用するため、 ユーザーを作成、削除できます。次の呼び出しでシリアル番号を取得します。 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  ...
}

ユーザー構成

ユーザーのニーズに応じて、セカンダリ できます。createAndManageUser() を呼び出すときに、次のフラグを指定できます。

SKIP_SETUP_WIZARD
アップデートを確認してインストールする新規ユーザーの設定ウィザードの実行をスキップします。 ユーザーに Google アカウントや Google サービスを追加するよう求めるメッセージを表示し、 画面ロックこの処理には時間がかかることがあります。また、一部のメンバーには該当しない場合があります ユーザー(公共のインターネット キオスクなど)にもアクセスできるようになります。
LEAVE_ALL_SYSTEM_APPS_ENABLED
新規ユーザーですべてのシステムアプリが有効なままになります。このフラグを設定しない場合、 新規ユーザーには、スマートフォンに必要な最小限のアプリしか含まれていないため、 ファイル ブラウザ、電話アプリ、連絡先、SMS メッセージなどです。

ユーザー ライフサイクルを追跡する

DPC(完全管理対象デバイスの管理者の場合)は、 セカンダリ ユーザーが変わったときに通知を受け取れます。変更後に後続のタスクを実行するには、 これらのコールバック メソッドを DPC の DeviceAdminReceiver サブクラスに追加してください。

onUserStarted()
システムがユーザーを起動した後に呼び出されます。このユーザーはまだセットアップ中または バックグラウンドで実行中の処理です。ユーザーは startedUser から取得できます。 あります。
onUserSwitched()
システムが別のユーザーに切り替わった後に呼び出されます。新規ユーザーを獲得するには switchedUser 引数から取得して、フォアグラウンドで実行されている状態になっている必要があります。
onUserStopped()
ユーザーがログアウトして停止状態になったためにシステムが停止した後に呼び出されます。 新規ユーザー(一時的なユーザーの場合)、または DPC によってユーザーが停止された。取得できるもの: stoppedUser 引数からユーザーを指定します。
onUserAdded()
システムによって新しいユーザーが追加されると呼び出されます。通常、セカンダリ ユーザーは、 セットアップが完了したことを意味します。ユーザーは newUser 引数。
onUserRemoved()
システムがユーザーを削除した後に呼び出されます。ユーザーはすでに削除されているため、 removedUser 引数で表されるユーザーにアクセスできません。

システムがユーザーをフォアグラウンドに移動させたタイミングや、ユーザーを アプリは会話の受信者を登録できます。 ACTION_USER_FOREGROUNDACTION_USER_BACKGROUND ブロードキャスト。

ユーザーの検出

すべてのセカンダリ ユーザーを取得するには、完全管理対象デバイスの管理者が以下を呼び出します。 DevicePolicyManager.getSecondaryUsers()。結果 管理者が作成したセカンダリ ユーザーまたはエフェメラル ユーザーが含まれます。また、結果には セカンダリ ユーザー(またはゲストユーザー)を含めることもできます。 作成します。仕事用プロファイルは利用できないため、結果に表示されません 設定することもできます。次のサンプルは、この方法の使用方法を示しています。

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

セカンダリ ユーザーのステータスを確認するために呼び出すことができるその他のメソッドを次に示します。

DevicePolicyManager.isEphemeralUser()
セカンダリ ユーザーの管理者からこのメソッドを呼び出して、 一時的なユーザーです
DevicePolicyManager.isAffiliatedUser()
セカンダリ ユーザーの管理者からこのメソッドを呼び出して、このユーザーが ユーザーに関連付けられている必要がありますアフィリエーションについて詳しくは、DPC を参照 下記をご覧ください。

ユーザー管理

ユーザーのライフサイクルを完全に管理したい場合は、API を呼び出すことで、 デバイスでユーザーを変更するタイミングと方法をきめ細かく制御できます。たとえば、 一定期間使用しなかった場合にユーザーを削除するか、 ユーザーのシフトが終了する前に未送信の注文をサーバーに送信する。

ログアウト

Android 9.0 ではロック画面にログアウト ボタンが追加され、 セッションを終了できます。ボタンをタップすると、 セカンダリ ユーザーが一時的ログインユーザーの場合は削除して、プライマリ ユーザーが復帰 起動します。Android では、メインユーザーが フォアグラウンドで動作する必要があります。

Android にはデフォルトでセッション終了ボタンは表示されませんが、 完全管理対象デバイスなど)で、 DevicePolicyManager.setLogoutEnabled()。必要に応じて ボタンの現在の状態を確認し、 DevicePolicyManager.isLogoutEnabled()

セカンダリ ユーザーの管理者は、プログラムでユーザーからログアウトして戻ります。 プライマリユーザーに割り当てられますまず、セカンダリ ユーザーとプライマリ ユーザーが 関連付けている場合は、DevicePolicyManager.logoutUser() を呼び出します。条件 ログアウトしたユーザーが一時ユーザーである場合は、 できます。

ユーザーを切り替える

完全管理対象デバイスの管理者は、別のセカンダリ ユーザーに切り替えることもできます。 DevicePolicyManager.switchUser() を呼び出します。便宜上、 null を渡してプライマリ ユーザーに切り替えることができます。

ユーザーを停止する

セカンダリ ユーザーを停止するには、完全管理対象デバイスを所有する DPC が DevicePolicyManager.stopUser()。停止されたユーザーが 一時的なユーザーが停止すると、そのユーザーは停止され、削除されます。

デバイスの制限を超えないように、可能な限りユーザーを停止することをおすすめします。 実行中のユーザーの最大数。

ユーザーを削除する

セカンダリ ユーザーを完全に削除するには、DPC で次のいずれかを呼び出します。 DevicePolicyManager メソッド:

  • 完全管理対象デバイスの管理者は、removeUser() を呼び出すことができます。
  • セカンダリ ユーザーの管理者は、wipeData() を呼び出すことができます。

ログアウト時、停止時、または切り替え時に、エフェメラル ユーザーは削除されます 遠ざかってしまいます

デフォルト UI を無効にする

DPC にユーザー管理用の UI が用意されている場合は、Android の組み込みの マルチユーザー インターフェースです。これを行うには、 DevicePolicyManager.setLogoutEnabled() を作成し、 DISALLOW_USER_SWITCH の制限の例を以下に示します。 次の例をご覧ください。

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

デバイスを使用するユーザーが、Android の組み込み UI を使用してセカンダリ ユーザーを追加できない 完全管理対象デバイスの管理者は、 DISALLOW_ADD_USER のユーザー制限。

セッション メッセージ

デバイスを使用しているユーザーが新しいユーザーに切り替えると、Android は スイッチをハイライト表示しますAndroid には次のメッセージが表示されます。

  • デバイスがセカンダリに切り替わったときに表示される Start-user-session メッセージ 解除することはできません。
  • デバイスがプライマリ ユーザーに戻ったときに表示されるエンドユーザー セッション メッセージ 解除されます。

2 人のセカンダリ ユーザーを切り替える際に、メッセージは表示されません。

メッセージがすべての状況に適しているとは限らないため、 メールの本文が翻訳されますたとえば、ソリューションでエフェメラル ユーザーを使用すると、 次のようなメッセージに反映できます。ブラウザの停止 セッションと個人データを削除しています...

メッセージは数秒間だけ表示されるので、 簡潔で明確なフレーズにしますメッセージをカスタマイズするには、管理者が DevicePolicyManager メソッド setStartUserSessionMessage() および setEndUserSessionMessage() です。 次の例をご覧ください。

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

カスタム メッセージを削除して Android のデフォルトに戻すには、null を渡します ブロックすることもできます。現在のメッセージ テキストを確認する必要がある場合は、 getStartUserSessionMessage() または getEndUserSessionMessage()

DPC でローカライズされたメッセージを設定する必要があります。 表示されます。また、メッセージの更新が必要で、 ユーザーの言語 / 地域が変わります。

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

DPC 調整

セカンダリ ユーザーを管理するには、通常、DPC のインスタンスが 2 つ必要です。1 つは 他方はセカンダリ ユーザーを所有し、他方は完全管理対象デバイスとなります。作成時 新規ユーザーを追加した場合、完全管理対象デバイスの管理者は その新しいユーザーの管理者として

関連付けられたユーザー

このデベロッパー ガイドに記載されている API の一部は、セカンダリ ユーザーが 提携関係がある。Android では一部の機能が無効になるため、 (ネットワーク ロギングなど)とは、関連付けられていない新しいセカンダリ ユーザーを ユーザーの関連付けはできるだけ早く行うようにしてください。例をご覧ください。 セットアップをご覧ください。

設定

新しいセカンダリ ユーザーを設定する(セカンダリ ユーザーを所有する DPC から) 人々に利用してもらうことです。この設定は DeviceAdminReceiver.onEnabled() コールバック。以前に createAndManageUser() の呼び出しで管理者用エクストラを設定すると、 intent 引数から値を取得します。次の例は コールバックで新しいセカンダリ ユーザーが呼び出される:

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

DPC 間の RPC

2 つの DPC インスタンスが別々のユーザーで実行されている場合でも、 セカンダリ ユーザーは相互に通信できます。 別の DPC のサービスを呼び出すと、ユーザーの境界を超えるため、DPC は 通常どおりに bindService() を呼び出します。 Android。実行中のサービスにバインドするには、 別のユーザー、 DevicePolicyManager.bindDeviceAdminServiceAsUser()

RPC を呼び出すプライマリ ユーザーと、関連付けられた 2 つのセカンダリ ユーザー。
図 2. 関連するプライマリ ユーザーとセカンダリ ユーザーの管理者 サービス メソッドの呼び出し

DPC は、返されたユーザーで実行されているサービスにのみバインドできます。 DevicePolicyManager.getBindDeviceAdminTargetUsers()。 次の例は、管理者にバインドされているセカンダリ ユーザーの管理者を示しています。 次の要件が適用されます。

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

参考情報

専用デバイスについて詳しくは、次のドキュメントをご覧ください。