إدارة مستخدمين متعددين

يوضّح دليل المطوّر هذا كيف يمكن لوحدة التحكّم بسياسة الجهاز (DPC) إدارة العديد من مستخدمي Android على الأجهزة المخصّصة.

نظرة عامة

يمكن لوحدة التحكّم بسياسة الجهاز (DPC) مساعدة عدة مستخدمين في مشاركة جهاز واحد مخصَّص. يمكن لوحدة التحكّم بسياسة الجهاز (DPC) الذي يعمل على جهاز مُدار بالكامل إنشاء وإدارة نوعين من المستخدمين:

  • المستخدمون الثانويون هم مستخدمو Android الذين لديهم تطبيقات وبيانات منفصلة محفوظة بين الجلسات. يمكنك إدارة المستخدم من خلال مكوّن مشرف. ويكون هؤلاء المستخدمون مفيدون للحالات التي يتم فيها استلام الجهاز في بداية نوبة العمل، مثل سائقي التوصيل أو العاملين في الأمن.
  • المستخدمون المؤقتون هم المستخدمون الثانويون الذين يحذفهم النظام عند توقف المستخدم أو توقفه عن العمل أو إعادة تشغيل الجهاز. هؤلاء المستخدمون مفيدون للحالات التي يمكن فيها حذف البيانات بعد انتهاء الجلسة، مثل أكشاك الإنترنت المتاحة للجميع.

يمكنك استخدام وحدة التحكّم بسياسة الجهاز (DPC) الحالية لإدارة الجهاز المخصّص والمستخدمين الثانويين. عند إنشاء أحد مكونات وحدة التحكّم بسياسة الجهاز (DPC)، يتم ضبطه كمشرف للمستخدمين الثانويين الجدد.

المستخدم الأساسي ومستخدمان ثانويان.
الشكل 1. المستخدمون الأساسيون والثانويون الذين يديرهم مشرفون من وحدة التحكّم بسياسة الجهاز نفسه

يجب أن ينتمي المشرفون على المستخدم الثانوي إلى الحزمة نفسها التي ينتمي إليها مشرف الجهاز المدار بالكامل. لتبسيط التطوير، نوصي بمشاركة مشرف بين الجهاز والمستخدمين الثانويين.

تتطلب عادةً إدارة عدة مستخدمين على أجهزة مخصصة استخدام الإصدار 9.0 من نظام التشغيل Android، إلا أن بعض الطرق المستخدمة في دليل هذا المطوّر تتوفر في الإصدارات السابقة من نظام التشغيل Android.

المستخدمون الثانويون

يمكن للمستخدمين الثانويين الاتصال بشبكة Wi-Fi وإعداد شبكات جديدة. ومع ذلك، لا يمكنهم تعديل الشبكات أو حذفها، ولا حتى الشبكات التي أنشأها.

إنشاء مستخدمين

يمكن لوحدة التحكّم بسياسة الجهاز إنشاء مستخدمين إضافيين في الخلفية ثم تبديلهم إلى المقدّمة. تتشابه العملية تقريبًا لكل من المستخدمين الثانويين والمؤقتين. نفِّذ الخطوات التالية في مشرفي الجهاز المُدار بالكامل والمستخدم الثانوي:

  1. الاتصال بالرقم DevicePolicyManager.createAndManageUser() لإنشاء مستخدم مؤقت، يمكنك تضمين MAKE_USER_EPHEMERAL في وسيطة الإبلاغ.
  2. يمكنك استدعاء DevicePolicyManager.startUserInBackground() لبدء المستخدم في الخلفية. يبدأ المستخدم في العمل ولكنك ستحتاج إلى إنهاء الإعداد قبل نقل المستخدم إلى المقدمة وعرضه للشخص الذي يستخدم الجهاز.
  3. في مشرف المستخدم الثانوي، تواصَل مع DevicePolicyManager.setAffiliationIds() لربط المستخدم الجديد بالمستخدم الأساسي. راجِع تنسيق وحدة التحكّم بسياسة الجهاز أدناه.
  4. في صفحة مشرف الجهاز المُدار بالكامل، اطلب DevicePolicyManager.switchUser() لتبديل المستخدم إلى المقدّمة.

يوضّح النموذج التالي كيفية إضافة الخطوة 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(). يُعد تجاوز حدود المستخدم أسباب إخفاق شائعة:

قد يستغرق إنشاء حساب مستخدم بعض الوقت. إذا كنت تقوم بإنشاء المستخدمين بشكل متكرر، فيمكنك تحسين تجربة المستخدم عن طريق إعداد مستخدم جاهز للاستخدام في الخلفية. قد تحتاج إلى الموازنة بين مزايا المستخدم الجاهز للاستخدام والحد الأقصى لعدد المستخدمين المسموح بهم على الجهاز.

التعريف

بعد إنشاء مستخدم جديد، يجب عليك الإشارة إلى المستخدم برقم تسلسلي ثابت. لا تثبِّت 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) (إذا كان مشرفًا للجهاز المُدار بالكامل) من المفيد معرفة متى يتغير المستخدمون الثانويون. لتشغيل مهام المتابعة بعد التغييرات، يمكنك إلغاء طرق معاودة الاتصال هذه في الفئة الفرعية DeviceAdminReceiver لوحدة التحكّم بسياسة الجهاز:

onUserStarted()
يتم الاتصال بعد أن يبدأ النظام تشغيل أحد المستخدمين. ربما لا يزال هذا المستخدم قيد الإعداد أو قيد التشغيل في الخلفية. يمكنك الحصول على المستخدم من الوسيطة startedUser.
onUserSwitched()
يتم الاتصال بعد تبديل النظام إلى مستخدم آخر. يمكنك الحصول على المستخدم الجديد الذي يتم تشغيله الآن في المقدّمة من الوسيطة switchedUser.
onUserStopped()
يتم استدعاء هذه الدالة بعد أن يوقف النظام المستخدم لأنّه سجّل الخروج، أو انتقل إلى مستخدم جديد (إذا كان المستخدم مؤقتًا)، أو أوقفت وحدة التحكّم بسياسة الجهاز المستخدم. يمكنك الحصول على المستخدم من الوسيطة stoppedUser.
onUserAdded()
يتم الاتصال به عند إضافة النظام لمستخدم جديد. عادةً، لا يتم إعداد المستخدمين الثانويين بالكامل عندما تتلقى وحدة التحكم بسياسة الجهاز رد الاتصال. يمكنك الحصول على المستخدم من الوسيطة newUser.
onUserRemoved()
يتم الاتصال بعد حذف النظام لمستخدم. بما أنّه تم حذف المستخدم، لا يمكنك الوصول إلى المستخدم الذي يتم تمثيله بالوسيطة removedUser.

لمعرفة متى يرسل النظام مستخدمًا إلى المقدّمة أو يرسله إلى الخلفية، يمكن للتطبيقات تسجيل مستلِم في عمليات البث على ACTION_USER_FOREGROUND وACTION_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()
يمكنك الاتصال بهذه الطريقة من مشرف مستخدم ثانوي لمعرفة ما إذا كان هذا المستخدم مرتبطًا بالمستخدم الأساسي. لمزيد من المعلومات عن الارتباط، يُرجى الاطّلاع على تنسيق وحدة التحكّم بسياسة الجهاز أدناه.

إدارة المستخدمين

إذا كنت تريد إدارة دورة حياة المستخدمين بشكل كامل، يمكنك استدعاء واجهات برمجة التطبيقات للتحكّم الدقيق في وقت وكيفية تغيير الجهاز للمستخدمين. على سبيل المثال، يمكنك حذف مستخدم عند عدم استخدام الجهاز لفترة زمنية أو يمكنك إرسال أي طلبات لم يتم إرسالها إلى خادم قبل انتهاء وردية المستخدم.

تسجيل الخروج

أضاف نظام التشغيل Android 9.0 زر تسجيل الخروج إلى شاشة القفل حتى يتمكن من يستخدم الجهاز إنهاء الجلسة. بعد النقر على الزر، يوقف النظام المستخدم الثانوي، ويحذف المستخدم إذا كان مؤقتًا، ثم يعود المستخدم الأساسي إلى المقدمة. يخفي Android الزر عندما يكون المستخدم الأساسي في المقدمة لأن المستخدم الأساسي لا يمكنه تسجيل الخروج.

لا يعرض Android زر إنهاء الجلسة تلقائيًا، ولكن يمكن للمشرف (جهاز مُدار بالكامل) تفعيله من خلال طلب DevicePolicyManager.setLogoutEnabled(). إذا كنت بحاجة إلى تأكيد الحالة الحالية للزر، اتصل بـ DevicePolicyManager.isLogoutEnabled().

يمكن لمشرف المستخدم الثانوي تسجيل خروج المستخدم آليًا والرجوع إلى المستخدم الأساسي. أولاً، تأكَّد من أنّ المستخدمين الثانويين والمستخدمين الأساسيين تابعين، ثم اتصل بـ DevicePolicyManager.logoutUser(). إذا كان المستخدم الذي تم تسجيل الخروج منه مستخدمًا مؤقتًا، يتوقف النظام ثم يحذفه.

التبديل بين المستخدمين

للتبديل إلى مستخدم ثانوي آخر، يمكن لمشرف جهاز مُدار بالكامل الاتصال بـ DevicePolicyManager.switchUser(). لتسهيل الأمر، يمكنك تمرير null للتبديل إلى المستخدم الأساسي.

إيقاف مستخدم

لإيقاف مستخدم ثانوي، يمكن لوحدة التحكّم بسياسة الجهاز التي تمتلك جهازًا مُدارًا بالكامل الاتصال بالرقم DevicePolicyManager.stopUser(). إذا كان المستخدم الذي تم إيقافه مستخدمًا مؤقتًا، فيتم إيقاف المستخدم ثم حذفه.

ننصح بإيقاف المستخدمين متى أمكن ذلك للمساعدة في عدم تجاوز الحد الأقصى لعدد المستخدمين قيد التشغيل على الجهاز.

حذف مستخدم

لحذف مستخدم ثانوي نهائيًا، يمكن لوحدة التحكّم بسياسة الجهاز الاتصال بإحدى طرق DevicePolicyManager التالية:

  • يمكن لمشرف جهاز مُدار بالكامل الاتصال بالرقم removeUser().
  • يمكن لمشرف المستخدم الثانوي الاتصال بـ wipeData().

يحذف النظام المستخدمين المؤقتين عند تسجيل خروجهم أو إيقافهم أو الابتعاد عنهم.

إيقاف واجهة المستخدم التلقائية

إذا كانت وحدة التحكّم بسياسة الجهاز (DPC) توفّر واجهة مستخدم لإدارة المستخدمين، يمكنك إيقاف الواجهة المتعدّدة المستخدمين المضمَّنة في 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، لأن مشرفي الأجهزة المُدارة بالكامل يضيفون تلقائيًا القيد على DISALLOW_ADD_USER للمستخدم.

رسائل الجلسة

عندما ينتقل المستخدم الذي يستخدم أحد الأجهزة إلى مستخدم جديد، يعرض Android لوحة لإبراز مفتاح التبديل. يعرض Android الرسائل التالية:

  • رسالة جلسة المستخدم للمبتدئين التي تظهر عند انتقال الجهاز إلى مستخدم ثانوي من المستخدم الأساسي.
  • رسالة جلسة المستخدم النهائي تظهر عندما يعود الجهاز إلى المستخدم الأساسي من مستخدم ثانوي.

لا يعرض النظام الرسائل عند التبديل بين مستخدمين ثانويين.

نظرًا لأن الرسائل قد لا تكون مناسبة لكل الحالات، يمكنك تغيير نص هذه الرسائل. على سبيل المثال، إذا كان الحلّ يستخدم جلسات المستخدم المؤقتة، يمكنك إظهار ذلك في الرسائل مثل: إيقاف جلسة المتصفّح وحذف البيانات الشخصية...

يعرض النظام الرسالة لمدة ثانيتين فقط، لذا يجب أن تكون كل رسالة عبارة قصيرة وواضحة. لتخصيص الرسائل، يمكن للمشرف استدعاء طريقة DevicePolicyManagersetStartUserSessionMessage() و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);

مرِّر null لحذف رسائلك المخصّصة والعودة إلى رسائل Android التلقائية. إذا كنت بحاجة إلى التحقّق من نص الرسالة الحالية، اتصِل بالرقم getStartUserSessionMessage() أو getEndUserSessionMessage().

يجب أن تضبط وحدة التحكّم بسياسة الجهاز الرسائل المترجَمة لللغة الحالية للمستخدم. تحتاج أيضًا إلى تحديث الرسائل عند تغيير لغة المستخدم:

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)، إحداهما تمتلك الجهاز المُدار بالكامل بينما تمتلك الآخر المستخدم الثانوي. عند إنشاء مستخدم جديد، يعيّن مشرف الجهاز المُدار بالكامل مثيلاً آخر لنفسه كمشرف للمستخدم الجديد.

المستخدمون التابعون

لا تعمل بعض واجهات برمجة التطبيقات الواردة في دليل مطوِّر البرامج هذا إلا عندما يكون المستخدمون الثانويون تابعين. بما أنّ نظام Android يوقف بعض الميزات (مثل تسجيل بيانات الشبكة) عند إضافة مستخدمين ثانويين جدد غير تابعين إلى الجهاز، عليك ربط المستخدمين التابعين في أقرب وقت ممكن. يمكنك الاطّلاع على المثال في الإعداد أدناه.

ضبط إعدادات الجهاز

عليك إعداد المستخدمين الثانويين الجدد (من وحدة التحكّم بسياسة الجهاز التي تملك المستخدم الثانوي) قبل السماح لهم باستخدامها. يمكنك إجراء هذا الإعداد من خلال معاودة الاتصال بـ DeviceAdminReceiver.onEnabled(). إذا سبق لك ضبط أي إضافات مشرفين في المكالمة على createAndManageUser()، يمكنك الحصول على القيم من الوسيطة intent. يوضح المثال التالي وحدة تحكّم بسياسة الجهاز (DPC) تضم مستخدمًا ثانويًا جديدًا في عملية معاودة الاتصال:

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)

وعلى الرغم من تشغيل مثيلي وحدة التحكّم بسياسة الجهاز (DPC) ضمن مستخدمين منفصلين، يمكن لوحدات التحكّم بسياسة الجهاز (DPC) التي تمتلك الجهاز والمستخدمين الثانويين التواصل مع بعضهم بعضًا. بما أنّ طلب خدمة أخرى لوحدة التحكّم بسياسة الجهاز (DPC) يتجاوز حدود المستخدم، لا يمكن لوحدة التحكّم بسياسة الجهاز الاتصال بـ bindService() كما هو الحال عادةً في Android. للربط بخدمة تعمل في مستخدم آخر، اتصل بـ DevicePolicyManager.bindDeviceAdminServiceAsUser().

مستخدم أساسي ومستخدمان ثانويان تابعان لك يتصلان بـ RPC.
الشكل 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);

مصادر إضافية

لمعرفة المزيد من المعلومات عن الأجهزة المخصَّصة، يمكنك قراءة المستندات التالية: