تفاعل مع مركز الأمان

إعادة التوجيه إلى مركز الأمان

يمكن لأي تطبيق فتح مركز الأمان باستخدام الإجراء android.content.Intent.ACTION_SAFETY_CENTER (قيمة السلسلة android.intent.action.SAFETY_CENTER ).

لفتح مركز الأمان، قم بإجراء اتصال من داخل مثيل Activity :

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

إعادة التوجيه إلى مشكلة محددة

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

الإضافات المقصودة التي تعيد توجيه بطاقة تحذير محددة:

  • EXTRA_SAFETY_SOURCE_ID
    • قيمة السلسلة: android.safetycenter.extra.SAFETY_SOURCE_ID
    • نوع السلسلة: يحدد معرف مصدر الأمان لبطاقة التحذير المرتبطة
    • مطلوب لإعادة التوجيه إلى هذه القضية للعمل
  • EXTRA_SAFETY_SOURCE_ISSUE_ID
    • قيمة السلسلة: android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
    • نوع السلسلة: يحدد معرف بطاقة التحذير
    • مطلوب لإعادة التوجيه إلى هذه القضية للعمل
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • قيمة السلسلة: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • نوع UserHandle : يحدد UserHandle لبطاقة التحذير المرتبطة
    • اختياري (الافتراضي هو المستخدم الحالي)

يمكن استخدام مقتطف الكود أدناه من داخل مثيل Activity لفتح شاشة مركز الأمان لمشكلة معينة:

UserHandle theUserHandleThisIssueCameFrom = …;

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER)
.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID, "TheSafetySourceIdThisIssueCameFrom")
.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID, "TheSafetySourceIssueIdToRedirectTo")
.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_USER_HANDLE, theUserHandleThisIssueCameFrom);

startActivity(openSafetyCenterIntent);

إعادة التوجيه إلى صفحة فرعية محددة (بدءًا من Android 14)

في Android 14 أو الإصدارات الأحدث، يتم تقسيم صفحة مركز الأمان إلى صفحات فرعية متعددة تمثل SafetySourcesGroup المختلفة (في Android 13، يظهر ذلك كإدخالات قابلة للطي).

من الممكن إعادة التوجيه إلى صفحة فرعية محددة باستخدام هذه النية الإضافية:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • قيمة السلسلة: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • نوع السلسلة: يحدد معرف SafetySourcesGroup
    • مطلوب لإعادة التوجيه إلى الصفحة الفرعية للعمل

يمكن استخدام مقتطف الكود أدناه من داخل مثيل Activity لفتح شاشة مركز الأمان على صفحة فرعية محددة:

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER)
.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID, "TheSafetySourcesGroupId");

startActivity(openSafetyCenterIntent);

استخدم واجهات برمجة التطبيقات لمصدر مركز الأمان

تتوفر واجهات برمجة التطبيقات لمصدر مركز الأمان باستخدام SafetyCenterManager (وهو @SystemApi ). يتوفر الرمز الخاص بسطح واجهة برمجة التطبيقات (API) في Code Search . يتوفر كود التنفيذ الخاص بواجهات برمجة التطبيقات في Code Search .

الأذونات

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

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • يُستخدم لواجهة برمجة تطبيقات SafetyCenterManager#isSafetyCenterEnabled() (غير مطلوبة لمصادر مركز الأمان، فهي تحتاج فقط إلى إذن SEND_SAFETY_CENTER_UPDATE )
    • يتم استخدامه بواسطة تطبيقات النظام التي تتحقق من تمكين مركز الأمان
    • يُمنح فقط لتطبيقات النظام المُدرجة في القائمة المسموح بها
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • يُستخدم لواجهة برمجة التطبيقات الممكّنة وواجهة برمجة تطبيقات مصادر الأمان
    • تستخدم من قبل مصادر السلامة فقط
    • يُمنح فقط لتطبيقات النظام المُدرجة في القائمة المسموح بها

تتمتع هذه الأذونات بامتيازات ولا يمكنك الحصول عليها إلا عن طريق إضافتها إلى الملف ذي الصلة، على سبيل المثال، ملف com.android.settings.xml لتطبيق الإعدادات، وإلى ملف AndroidManifest.xml الخاص بالتطبيق. راجع protectionLevel لمزيد من المعلومات حول نموذج الإذن.

احصل على SafetyCenterManager

SafetyCenterManager هي فئة @SystemApi يمكن الوصول إليها من تطبيقات النظام بدءًا من Android 13. توضح هذه المكالمة كيفية الحصول على SafetyCenterManager:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
  // Must be on T or above to interact with Safety Center.
  return;
}
SafetyCenterManager safetyCenterManager = context.getSystemService(SafetyCenterManager.class);
if (safetyCenterManager == null) {
  // Should not be null on T.
  return;
}

تحقق من تمكين مركز الأمان

تتحقق هذه المكالمة من تمكين مركز الأمان. تتطلب المكالمة إما إذن READ_SAFETY_CENTER_STATUS أو إذن SEND_SAFETY_CENTER_UPDATE :

boolean isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled();
if (isSafetyCenterEnabled) {
  // …
} else {
  // …
}

توفير بيانات

يتم توفير بيانات مصدر مركز الأمان مع String sourceId المحدد إلى مركز الأمان مع كائن SafetySourceData ، الذي يمثل إدخال واجهة المستخدم وقائمة المشكلات (بطاقات التحذير). يمكن أن يكون لإدخال واجهة المستخدم وبطاقات التحذير مستويات خطورة مختلفة محددة في فئة SafetySourceData :

  • SEVERITY_LEVEL_UNSPECIFIED
    • لم يتم تحديد خطورة
    • اللون: رمادي أو شفاف (اعتمادًا على SafetySourcesGroup للإدخال)
    • يُستخدم للبيانات الديناميكية التي تظهر كمدخل ثابت في واجهة المستخدم أو لإظهار إدخال غير محدد
    • لا يجوز استخدامها لبطاقات التحذير
  • SEVERITY_LEVEL_INFORMATION
    • معلومات أساسية أو اقتراح بسيط
    • الون الاخضر
  • SEVERITY_LEVEL_RECOMMENDATION
    • توصية بأن يتخذ المستخدم إجراءً بشأن هذه المشكلة، لأنها قد تعرضه للخطر
    • اللون الأصفر
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • تحذير بالغ الأهمية بأنه يجب على المستخدم اتخاذ إجراء بشأن هذه المشكلة، لأنها تمثل خطرًا
    • لون احمر

SafetySourceData

يتكون كائن SafetySourceData من إدخال واجهة المستخدم وبطاقات التحذير والثوابت.

  • مثيل SafetySourceStatus الاختياري (إدخال واجهة المستخدم)
  • قائمة مثيلات SafetySourceIssue (بطاقات التحذير)
  • إضافات Bundle الاختيارية (بدءًا من 14)
  • الثوابت:
    • يجب أن تتكون قائمة SafetySourceIssue من مشكلات ذات معرفات فريدة.
    • يجب ألا يكون مثيل SafetySourceIssue أكثر أهمية من SafetySourceStatus إذا كان هناك واحد (ما لم تكن SafetySourceStatus هي SEVERITY_LEVEL_UNSPECIFIED ، وفي هذه الحالة يُسمح بمشاكل SEVERITY_LEVEL_INFORMATION ).
    • يجب استيفاء المتطلبات الإضافية التي يفرضها تكوين واجهة برمجة التطبيقات (API)، على سبيل المثال، إذا كان المصدر خاصًا بالمشكلة فقط، فيجب ألا يوفر مثيل SafetySourceStatus .

SafetySourceStatus

  • عنوان CharSequence مطلوب
  • مطلوب ملخص CharSequence
  • مستوى الخطورة المطلوب
  • مثيل PendingIntent اختياري لإعادة توجيه المستخدم إلى الصفحة الصحيحة (يستخدم الإعداد الافتراضي intentAction من التكوين، إن وجد)
  • IconAction اختياري (يظهر كرمز جانبي عند الإدخال) يتكون من:
    • نوع الأيقونة المطلوبة، والتي يجب أن تكون أحد الأنواع التالية:
      • ICON_TYPE_GEAR : يظهر على شكل ترس بجوار إدخال واجهة المستخدم
      • ICON_TYPE_INFO : يظهر كرمز معلومات بجوار إدخال واجهة المستخدم
    • مطلوب PendingIntent لإعادة توجيه المستخدم إلى صفحة أخرى
  • قيمة اختيارية enabled منطقية تسمح بوضع علامة على إدخال واجهة المستخدم على أنه معطل، بحيث لا يكون قابلاً للنقر (الافتراضي هو true )
  • الثوابت:
    • يجب أن تفتح مثيلات PendingIntent مثيل Activity .
    • إذا تم تعطيل الإدخال، فيجب تعيينه SEVERITY_LEVEL_UNSPECIFIED .
    • المتطلبات الإضافية التي يفرضها تكوين API.

SafetySourceIssue

  • مطلوب معرف String فريد
  • عنوان CharSequence مطلوب
  • عنوان فرعي اختياري CharSequence
  • مطلوب ملخص CharSequence
  • مستوى الخطورة المطلوب
  • فئة المشكلة الاختيارية، والتي يجب أن تكون واحدة من:
    • ISSUE_CATEGORY_DEVICE : تؤثر المشكلة على جهاز المستخدم.
    • ISSUE_CATEGORY_ACCOUNT : تؤثر المشكلة على حسابات المستخدم.
    • ISSUE_CATEGORY_GENERAL : تؤثر المشكلة على السلامة العامة للمستخدم. هذا هو الافتراضي.
    • ISSUE_CATEGORY_DATA (بدءًا من Android 14): تؤثر المشكلة على بيانات المستخدم.
    • ISSUE_CATEGORY_PASSWORDS (بدءًا من Android 14): تؤثر المشكلة على كلمات مرور المستخدم.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (بدءًا من Android 14): تؤثر المشكلة على السلامة الشخصية للمستخدم.
  • قائمة عناصر Action التي يمكن للمستخدم اتخاذها لهذه المشكلة، حيث يتكون كل مثيل Action من:
    • مطلوب معرف String فريد
    • تسمية CharSequence المطلوبة
    • مطلوب PendingIntent لإعادة توجيه المستخدم إلى صفحة أخرى أو معالجة الإجراء مباشرة من شاشة مركز الأمان
    • منطقي اختياري لتحديد ما إذا كان من الممكن حل هذه المشكلة مباشرةً من شاشة مركز الأمان (الافتراضي false )
    • رسالة نجاح اختيارية CharSequence ، ليتم عرضها للمستخدم عند حل المشكلة بنجاح مباشرةً من شاشة مركز الأمان
  • PendingIntent اختياري يتم استدعاؤه عندما يرفض المستخدم المشكلة (الافتراضي هو عدم استدعاء أي شيء)
  • معرف نوع إصدار String المطلوبة؛ وهذا مشابه لمعرف المشكلة ولكن ليس من الضروري أن يكون فريدًا ويستخدم للتسجيل
  • String اختيارية لمعرف إلغاء البيانات المكررة، وهذا يسمح بنشر نفس SafetySourceIssue من مصادر مختلفة وعرضها مرة واحدة فقط في واجهة المستخدم على افتراض أن لديهم نفس deduplicationGroup (بدءًا من Android 14). إذا لم يتم تحديد ذلك، فلن يتم إلغاء تكرار المشكلة أبدًا
  • CharSequence اختياري لعنوان الإسناد، وهو نص يوضح مكان إنشاء بطاقة التحذير (بدءًا من Android 14). إذا لم يتم تحديده، يستخدم عنوان SafetySourcesGroup
  • إمكانية اتخاذ إجراءات بشأن المشكلات الاختيارية (بدءًا من Android 14)، والتي يجب أن تكون واحدة مما يلي:
    • ISSUE_ACTIONABILITY_MANUAL : يحتاج المستخدم إلى حل هذه المشكلة يدويًا. هذا هو الافتراضي.
    • ISSUE_ACTIONABILITY_TIP : هذه المشكلة مجرد نصيحة وقد لا تتطلب أي إدخال من المستخدم.
    • ISSUE_ACTIONABILITY_AUTOMATIC : لقد تم بالفعل معالجة هذه المشكلة وقد لا تتطلب أي إدخال من المستخدم.
  • سلوك الإشعارات الاختياري (بدءًا من Android 14)، والذي يجب أن يكون واحدًا مما يلي:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED : سيقرر مركز الأمان ما إذا كانت هناك حاجة إلى إرسال إشعار لبطاقة التحذير. هذا هو الافتراضي.
    • NOTIFICATION_BEHAVIOR_NEVER : لم يتم نشر أي إشعار.
    • NOTIFICATION_BEHAVIOR_DELAYED : يتم نشر إشعار بعد مرور بعض الوقت على الإبلاغ عن المشكلة لأول مرة.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY : يتم نشر إشعار بمجرد الإبلاغ عن المشكلة.
  • Notification اختياري، لإظهار إشعار مخصص مع بطاقة التحذير (بدءًا من Android 14). إذا لم يتم تحديده، فسيتم اشتقاق Notification من بطاقة التحذير. مكونة من:
    • عنوان CharSequence مطلوب
    • مطلوب ملخص CharSequence
    • قائمة عناصر Action التي يمكن للمستخدم اتخاذها لهذا الإشعار
  • الثوابت:
    • يجب أن تتكون قائمة مثيلات Action من إجراءات ذات معرفات فريدة
    • يجب أن تحتوي قائمة مثيلات Action على عنصر Action واحد أو عنصرين. إذا لم تكن قابلية التنفيذ هي ISSUE_ACTIONABILITY_MANUAL ، فسيتم السماح بعدم وجود Action .
    • يجب ألا يفتح OnDismiss PendingIntent مثيل Activity
    • المتطلبات الإضافية التي يفرضها تكوين API

يتم توفير البيانات عند أحداث معينة إلى مركز الأمان، لذلك من الضروري تحديد سبب قيام المصدر بتوفير SafetySourceData مع مثيل SafetyEvent .

SafetyEvent

  • النوع المطلوب والذي يجب أن يكون واحداً من:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED : تم تغيير حالة المصدر.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED : الاستجابة لإشارة التحديث/إعادة الفحص من مركز الأمان؛ استخدم هذا بدلاً من SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED لكي يتمكن مركز الأمان من تتبع طلب التحديث/إعادة الفحص.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED : لقد قمنا بحل SafetySourceIssue.Action مباشرة من شاشة مركز الأمان؛ استخدم هذا بدلاً من SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED ليتمكن مركز الأمان من تتبع SafetySourceIssue.Action الذي يتم حله.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : لقد حاولنا حل SafetySourceIssue.Action مباشرة من شاشة مركز الأمان، لكننا فشلنا في القيام بذلك؛ استخدم هذا بدلاً من SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED لكي يتمكن مركز الأمان من تتبع فشل SafetySourceIssue.Action .
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : لقد تغيرت لغة الجهاز، لذلك نقوم بتحديث نص البيانات المقدمة؛ يُسمح باستخدام SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED لهذا الغرض.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED : نحن نقدم هذه البيانات كجزء من التشغيل الأولي حيث أن بيانات مركز الأمان لا تستمر عبر عمليات إعادة التشغيل؛ يُسمح باستخدام SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED لهذا الغرض.
  • معرف String اختياري لمعرف بث التحديث.
  • يتم حل معرف String الاختياري لمثيل SafetySourceIssue .
  • يتم حل معرف String الاختياري لمثيل SafetySourceIssue.Action .
  • الثوابت:
    • يجب توفير معرف بث التحديث إذا كان النوع SAFETY_EVENT_TYPE_REFRESH_REQUESTED
    • يجب توفير معرفات المشكلة والإجراء إذا كان النوع إما SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED أو SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED

فيما يلي مثال لكيفية قيام المصدر بتقديم البيانات إلى مركز الأمان (في هذه الحالة، يقدم إدخالاً ببطاقة تحذير واحدة):

PendingIntent redirectToMyScreen =
    PendingIntent.getActivity(
        context, requestCode, redirectToMyScreenIntent, PendingIntent.FLAG_IMMUTABLE);
SafetySourceData safetySourceData =
    new SafetySourceData.Builder()
        .setStatus(
            new SafetySourceStatus.Builder(
                    "title", "summary", SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION)
                .setPendingIntent(redirectToMyScreen)
                .build())
        .addIssue(
            new SafetySourceIssue.Builder(
                    "MyIssueId",
                    "title",
                    "summary",
                    SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
                    "MyIssueTypeId")
                .setSubtitle("subtitle")
                .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
                .addAction(
                    new SafetySourceIssue.Action.Builder(
                            "MyIssueActionId", "label", redirectToMyScreen)
                        .build())
                .build())
        .build();
SafetyEvent safetyEvent = new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
safetyCenterManager.setSafetySourceData("MySourceId", safetySourceData, safetyEvent);

الحصول على البيانات الأخيرة المقدمة

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

استخدم هذا الرمز للحصول على آخر البيانات المقدمة إلى مركز الأمان:

SafetySourceData lastDataProvided = safetyCenterManager.getSafetySourceData("MySourceId");

الإبلاغ عن خطأ

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

يمكنك تقديم الخطأ باستخدام SafetySourceErrorDetails ، والذي يتكون من:

  • SafetySourceErrorDetails : مثيل SafetyEvent المطلوب :
// An error has occurred in the background, need to clear the Safety Center data to avoid showing data that may not be valid anymore
SafetyEvent safetyEvent = new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
SafetySourceErrorDetails safetySourceErrorDetails = new SafetySourceErrorDetails(safetyEvent);
safetyCenterManager.reportSafetySourceError("MySourceId", safetySourceErrorDetails);

الاستجابة لطلب التحديث أو إعادة الفحص

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

ويتم ذلك عن طريق استقبال البث بالإجراء التالي:

  • ACTION_REFRESH_SAFETY_SOURCES
    • قيمة السلسلة: android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • يتم تشغيله عندما يرسل مركز الأمان طلبًا لتحديث بيانات مصدر الأمان لتطبيق معين
    • نية محمية لا يمكن إرسالها إلا عن طريق النظام
    • يتم إرساله إلى جميع مصادر الأمان في ملف التكوين كهدف صريح ويتطلب إذن SEND_SAFETY_CENTER_UPDATE

يتم توفير الإضافات التالية كجزء من هذا البث:

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • قيمة السلسلة: android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • يمثل نوع صفيف السلسلة ( String[] ) معرفات المصدر المطلوب تحديثها للتطبيق المحدد
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • قيمة السلسلة: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • النوع الصحيح يمثل نوع الطلب @IntDef
    • يجب أن يكون واحدًا من:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA : يطلب من المصدر تقديم البيانات بسرعة نسبيًا، عادةً عندما يفتح المستخدم الصفحة
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA : يطلب من المصدر تقديم بيانات حديثة قدر الإمكان، عادةً عندما يضغط المستخدم على زر إعادة المسح
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

    • قيمة السلسلة: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
    • يمثل نوع السلسلة معرفًا فريدًا للتحديث المطلوب

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

يستجيب BroadcastReceiver لطلب التحديث:

public final class SafetySourceReceiver extends BroadcastReceiver {
  // All the safety sources owned by this application.
  private static final String[] ALL_SAFETY_SOURCES = new String[] {"MySourceId1", "…"};
  @Override
  public void onReceive(Context context, Intent intent) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
      // Must be on T or above to interact with Safety Center.
      return;
    }
    String action = intent.getAction();
    if (!SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES.equals(action)) {
      return;
    }
    String refreshBroadcastId =
        intent.getStringExtra(SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
    if (refreshBroadcastId == null) {
      // Should always be provided.
      return;
    }
    String[] sourceIds =
        intent.getStringArrayExtra(SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS);
    if (sourceIds == null) {
      sourceIds = ALL_SAFETY_SOURCES;
    }
    int requestType =
        intent.getIntExtra(
            SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE,
            SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA);
    SafetyCenterManager safetyCenterManager = context.getSystemService(SafetyCenterManager.class);
    if (safetyCenterManager == null) {
      // Should not be null on T.
      return;
    }
    if (!safetyCenterManager.isSafetyCenterEnabled()) {
      // Preferably, no Safety Source code should be run if Safety Center is disabled.
      return;
    }
    SafetyEvent refreshSafetyEvent =
        new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
            .setRefreshBroadcastId(refreshBroadcastId)
            .build();
    for (String sourceId : sourceIds) {
      SafetySourceData safetySourceData = getSafetySourceDataFor(sourceId, requestType);
      // Set the data (or report an error with reportSafetySourceError, if something went wrong).
      safetyCenterManager.setSafetySourceData(sourceId, safetySourceData, refreshSafetyEvent);
    }
  }
  private SafetySourceData getSafetySourceDataFor(String sourceId, int requestType) {
    switch (requestType) {
      case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
        return getRefreshSafetySourceDataFor(sourceId);
      case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
        return getRescanSafetySourceDataFor(sourceId);
      default:
    }
    return getRefreshSafetySourceDataFor(sourceId);
  }
  // Data to provide when the user opens the page or on specific events.
  private SafetySourceData getRefreshSafetySourceDataFor(String sourceId) {
    // Get data for the source, if it's a fast operation it could potentially be executed in the
    // receiver directly.
    // Otherwise, it must start some kind of foreground service or expedited job.
    return null;
  }
  // Data to provide when the user pressed the rescan button.
  private SafetySourceData getRescanSafetySourceDataFor(String sourceId) {
    // Could be implemented the same way as getRefreshSafetySourceDataFor, depending on the source's
    // need.
    // Otherwise, could potentially perform a longer task.
    // In which case, it must start some kind of foreground service or expedited job.
    return null;
  }
}

تم الإعلان عن نفس مثيل BroadcastReceiver في المثال أعلاه في AndroidManifest.xml :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="…">
    <application>
    <!-- … -->
        <receiver android:name=".SafetySourceReceiver"
            android:exported="false">
            <intent-filter>
                <action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
            </intent-filter>
        </receiver>
    <!-- … -->
    </application>
</manifest>

ومن الناحية المثالية، يتم تنفيذ مصدر مركز الأمان بطريقة تستدعي SafetyCenterManager عندما تتغير بياناته. لأسباب تتعلق بسلامة النظام، نوصي بالاستجابة فقط لإشارة إعادة المسح (عندما ينقر المستخدم على زر المسح)، وليس عندما يفتح المستخدم مركز الأمان. إذا كانت هذه الوظيفة مطلوبة، فيجب تعيين الحقل refreshOnPageOpenAllowed="true" في ملف التكوين حتى يتمكن المصدر من استقبال البث الذي يتم تسليمه في هذه الحالات.

قم بالرد على مركز الأمان عند تمكينه أو تعطيله

يمكنك الاستجابة عندما يتم تمكين مركز الأمان أو تعطيله باستخدام إجراء النية هذا:

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • قيمة السلسلة: android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • يتم تشغيله عند تمكين مركز الأمان أو تعطيله أثناء تشغيل الجهاز
    • لم يتم استدعاؤه عند التمهيد (استخدم ACTION_BOOT_COMPLETED لذلك)
    • نية محمية لا يمكن إرسالها إلا عن طريق النظام
    • يتم إرساله إلى جميع مصادر الأمان في ملف التكوين كهدف صريح، ويتطلب إذن SEND_SAFETY_CENTER_UPDATE
    • تم إرساله كهدف ضمني يتطلب إذن READ_SAFETY_CENTER_STATUS

يعد إجراء النية هذا مفيدًا لتمكين أو تعطيل الميزات المرتبطة بمركز الأمان على الجهاز.

تنفيذ إجراءات الحل

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

لتنفيذ إجراءات الحل، يمكن لمصدر مركز الأمان استخدام خدمة إذا كان من المتوقع أن تستغرق العملية بعض الوقت ( PendingIntent.getService ) أو جهاز استقبال البث ( PendingIntent.getBroadcast ).

استخدم هذا الرمز لإرسال مشكلة يتم حلها إلى مركز الأمان:

Intent resolveIssueBroadcastIntent =
    new Intent("my.package.name.MY_RESOLVING_ACTION").setClass(ResolveActionReceiver.class);
PendingIntent resolveIssue =
    PendingIntent.getBroadcast(
        context, requestCode, resolveIssueBroadcastIntent, PendingIntent.FLAG_IMMUTABLE);
SafetySourceData safetySourceData =
    new SafetySourceData.Builder()
        .setStatus(
            new SafetySourceStatus.Builder(
                    "title", "summary", SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION)
                .setPendingIntent(redirectToMyScreen)
                .build())
        .addIssue(
            new SafetySourceIssue.Builder(
                    "MyIssueId",
                    "title",
                    "summary",
                    SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
                    "MyIssueTypeId")
                .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
                .addAction(
                    new SafetySourceIssue.Action.Builder(
                            "MyIssueActionId", "label", resolveIssue)
                        .setWillResolve(true)
                        .build())
                .build())
        .build();
SafetyEvent safetyEvent = new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
safetyCenterManager.setSafetySourceData("MySourceId", safetySourceData, safetyEvent);

يقوم BroadcastReceiver بحل الإجراء:

public final class ResolveActionReceiver extends BroadcastReceiver {
  private static final String MY_RESOLVING_ACTION = "my.package.name.MY_RESOLVING_ACTION";
  @Override
  public void onReceive(Context context, Intent intent) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
      // Must be on T or above to interact with Safety Center.
      return;
    }
    String action = intent.getAction();
    if (!MY_RESOLVING_ACTION.equals(action)) {
      return;
    }
    SafetyCenterManager safetyCenterManager = context.getSystemService(SafetyCenterManager.class);
    if (safetyCenterManager == null) {
      // Should not be null on T.
      return;
    }
    if (!safetyCenterManager.isSafetyCenterEnabled()) {
      // Preferably, no Safety Source code should be run if Safety Center is disabled.
      return;
    }
    resolveTheIssue();
    SafetyEvent resolveActionSafetyEvent =
        new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
            .setSafetySourceIssueId("MyIssueId")
            .setSafetySourceIssueActionId("MyIssueActionId")
            .build();
    SafetySourceData dataWithoutTheIssue = …;
    // Set the data (or report an error with reportSafetySourceError and
    // SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED, if something went wrong).
    safetyCenterManager.setSafetySourceData("MySourceId", dataWithoutTheIssue, resolveActionSafetyEvent);
  }

  private void resolveTheIssue() {
    // Resolves the issue for the user. Given this a BroadcastReceiver, this should be a fast action.
    // Otherwise, a foreground service and PendingIntent.getService should be used instead (or a job
    // could be scheduled here, too).
  }
}

تم الإعلان عن نفس مثيل BroadcastReceiver في المثال أعلاه في AndroidManifest.xml :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="…">
    <application>
    <!-- … -->
        <receiver android:name=".ResolveActionReceiver"
            android:exported="false">
            <intent-filter>
                <action android:name="my.package.name.MY_RESOLVING_ACTION"/>
            </intent-filter>
        </receiver>
    <!-- … -->
    </application>
</manifest>

الرد على اصدارات الفصل

يمكنك تحديد مثيل PendingIntent الذي يمكن تشغيله عند رفض مثيل SafetySourceIssue . يتعامل مركز الأمان مع حالات الرفض هذه:

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

لا يجب أن يحتاج المصدر إلى سلوكيات إضافية إلا إذا:

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

توفير بيانات لمستخدمين/ملفات تعريف متعددة

يمكن استخدام واجهة برمجة تطبيقات SafetyCenterManager عبر المستخدمين والملفات الشخصية. لمزيد من المعلومات، راجع إنشاء تطبيقات متعددة المستخدمين . يرتبط كائن Context الذي يوفر SafetyCenterManager بمثيل UserHandle ، لذلك يتفاعل مثيل SafetyCenterManager الذي تم إرجاعه مع مركز الأمان لمثيل UserHandle هذا. افتراضيًا، يرتبط Context بالمستخدم قيد التشغيل، ولكن من الممكن إنشاء مثيل لمستخدم آخر إذا كان التطبيق يحمل أذونات INTERACT_ACROSS_USERS و INTERACT_ACROSS_USERS_FULL . يوضح هذا المثال إجراء مكالمة بين المستخدمين/الملفات الشخصية:

Context userContext = context.createContextAsUser(userHandle, 0);
SafetyCenterManager userSafetyCenterManager = userContext.getSystemService(SafetyCenterManager.class);
if (userSafetyCenterManager == null) {
  // Should not be null on T.
  return;
}
// Calls to userSafetyCenterManager will provide data for the given userHandle

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

عند تعيين profile="all_profiles" للمصدر في ملف التكوين، يحدث ما يلي:

  • يوجد إدخال لواجهة المستخدم للمستخدم (أصل الملف الشخصي) وجميع الملفات الشخصية المُدارة المرتبطة به (والتي تستخدم مثيلات titleForWork ).
  • يتم إرسال إشارة التحديث أو إعادة الفحص إلى أصل ملف التعريف وجميع ملفات التعريف المُدارة المرتبطة به. يتم تشغيل جهاز الاستقبال المرتبط لكل ملف تعريف ويمكنه تقديم البيانات المرتبطة مباشرةً إلى SafetyCenterManager دون الحاجة إلى إجراء مكالمة عبر ملفات التعريف ما لم يكن جهاز الاستقبال أو التطبيق singleUser .

  • ومن المتوقع أن يوفر المصدر بيانات للمستخدم وجميع ملفات التعريف المُدارة الخاصة به. قد تختلف البيانات الخاصة بكل إدخال في واجهة المستخدم وفقًا لملف التعريف.

اختبارات

يمكنك الوصول إلى ShadowSafetyCenterManager واستخدامه في اختبار Robolectric.

private static final String MY_SOURCE_ID = "MySourceId";

private final MyClass myClass = …;
private final SafetyCenterManager safetyCenterManager = getApplicationContext().getSystemService(SafetyCenterManager.class);

@Test
public void whenRefreshingData_providesDataToSafetyCenterForMySourceId() {
    shadowOf(safetyCenterManager).setSafetyCenterEnabled(true);
    setupDataForMyClass(…);

    myClass.refreshData();

    SafetySourceData expectedSafetySourceData = …;
    assertThat(safetyCenterManager.getSafetySourceData(MY_SOURCE_ID)).isEqualTo(expectedSafetySourceData);
    SafetyEvent expectedSafetyEvent = …;
    assertThat(shadowOf(safetyCenterManager).getLastSafetyEvent(MY_SOURCE_ID)).isEqualTo(expectedSafetyEvent);
}

يمكنك كتابة المزيد من الاختبارات الشاملة (E2E)، لكن هذا خارج نطاق هذا الدليل. لمزيد من المعلومات حول كتابة اختبارات E2E هذه، راجع اختبارات CTS (CtsSafetyCenterTestCases)

الاختبار وواجهات برمجة التطبيقات الداخلية

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

الأذونات

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • يُستخدم لواجهات برمجة التطبيقات لمركز الأمان الداخلي
    • يُمنح فقط لـ PermissionController وShell

تطبيق الإعدادات

إعادة توجيه مركز الأمان

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

عند تمكين مركز الأمان:

  • إدخال الخصوصية القديمة هو رمز مخفي
  • إدخال Legacy Security هو رمز مخفي
  • تمت إضافة رمز جديد للأمان والخصوصية
  • يُعيد إدخال الأمان والخصوصية الجديد التوجيه إلى رمز مركز الأمان
  • تتم إعادة توجيه إجراءات android.settings.PRIVACY_SETTINGS و android.settings.SECURITY_SETTINGS إلى مركز الأمان المفتوح (الرمز: الأمان والخصوصية )

صفحات الأمان والخصوصية المتقدمة

يحتوي تطبيق الإعدادات على إعدادات إضافية ضمن المزيد من إعدادات الأمان وعناوين المزيد من إعدادات الخصوصية ، المتوفرة من مركز الأمان:

مصادر السلامة

يتكامل مركز الأمان مع مجموعة محددة من مصادر الأمان التي يوفرها تطبيق الإعدادات:

  • يتحقق مصدر أمان شاشة القفل من إعداد شاشة القفل برمز مرور (أو أي أمان آخر)، لضمان الحفاظ على معلومات المستخدم الخاصة آمنة من الوصول الخارجي.
  • مصدر أمان للقياسات الحيوية (مخفي افتراضيًا) يتكامل مع بصمة الإصبع أو مستشعر الوجه.

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

حول PendingIntent

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

عندما تكون متأكدًا من عدم وجود الخطأ، قم بتعيين قيمة تكوين مورد منطقي XML في تطبيق الإعدادات config_isSafetyCenterLockScreenPendingIntentFixed على true لإيقاف تشغيل الحل البديل داخل مركز الأمان.

الحل البديل PendingIntent

يحدث هذا الخطأ بسبب الإعدادات التي تستخدم إضافات مثيل Intent لتحديد الجزء الذي سيتم فتحه. نظرًا لأن Intent#equals لا يأخذ إضافات مثيل Intent في الاعتبار، فإن مثيل PendingIntent لرمز قائمة الترس والإدخال يعتبران متساويين وينتقلان إلى نفس واجهة المستخدم (على الرغم من أنهما مصممان للانتقال إلى واجهة مستخدم مختلفة). تم إصلاح هذه المشكلة في إصدار QPR عن طريق التمييز بين مثيلات PendingIntent عن طريق رمز الطلب. وبدلاً من ذلك، يمكن التمييز بين ذلك باستخدام Intent#setId .

مصادر السلامة الداخلية

بعض مصادر مركز الأمان داخلية ويتم تنفيذها في تطبيق نظام PermissionController داخل وحدة PermissionController. تعمل هذه المصادر مثل مصادر مركز الأمان العادية ولا تتلقى أي معاملة خاصة. الكود الخاص بهذه المصادر متاح من خلال البحث عن الكود في Android .

هذه إشارات خصوصية بشكل أساسي، على سبيل المثال:

  • إمكانية الوصول
  • الإلغاء التلقائي للتطبيقات غير المستخدمة
  • الوصول إلى الموقع
  • مستمع الإخطار
  • معلومات سياسة العمل