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

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

نظرة عامة

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

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

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

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

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

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

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

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

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

يوضّح النموذج التالي كيفية إضافة الخطوة 1 إلى وحدة التحكّم بسياسة الجهاز (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...
  }
}

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

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

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

تسجيل الخروج

أضاف 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 الرسائل التالية:

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

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

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

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

مرِّر 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)

تحتاج إدارة المستخدمين الثانويين عادةً إلى مثيلين من وحدة التحكّم بسياسة الجهاز (DPC)؛ أحدهما يمتلك الجهاز المدار بالكامل بينما يمتلك الآخر المستخدم الثانوي. عند إنشاء حساب مستخدم جديد، يعيّن مشرف الجهاز المُدار بالكامل مثيلاً آخر لنفسه كمشرف للمستخدم الجديد.

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

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

ضبط إعدادات

عليك إعداد المستخدمين الثانويين الجدد (من وحدة التحكّم بسياسة الجهاز (DPC) الذي يملك المستخدم الثانوي) قبل السماح للمستخدمين باستخدامهم. يمكنك إجراء هذا الإعداد من خلال معاودة الاتصال بـ 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 ...
}

استدعاء إجراء عن بُعد (RPC) بين وحدات التحكّم بسياسة الجهاز (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);

مراجع إضافية

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