אינטראקציה עם מרכז הבטיחות

הפנה מחדש למרכז הבטיחות

כל אפליקציה יכולה לפתוח את מרכז הבטיחות באמצעות הפעולה 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)

באנדרואיד 14 ומעלה, דף מרכז הבטיחות מחולק לדפי משנה מרובים המייצגים את SafetySourcesGroup השונות (באנדרואיד 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);

השתמש בממשקי API של מקור מרכז הבטיחות

ממשקי ה-API של מקור הבטיחות זמינים באמצעות SafetyCenterManager (שהוא @SystemApi ). קוד עבור משטח ה-API זמין ב- Code Search . קוד יישום של ממשקי ה-API זמין ב- Code Search .

הרשאות

ממשקי ה-API של המקור של מרכז הבטיחות נגישים רק על ידי אפליקציות מערכת הרשומות ברשימה באמצעות ההרשאות המפורטות למטה. למידע נוסף, ראה רישום הרשאות מורשות .

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • משמש עבור ה-API SafetyCenterManager#isSafetyCenterEnabled() (לא נחוץ עבור מקורות מרכז הבטיחות, הם זקוקים רק להרשאת SEND_SAFETY_CENTER_UPDATE )
    • בשימוש על ידי אפליקציות מערכת שבודקות אם מרכז הבטיחות מופעל
    • מוענק רק לאפליקציות מערכת המורשות
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • משמש עבור ה-API המופעל וממשק ה-API של מקורות בטיחות
    • בשימוש על ידי מקורות בטיחות בלבד
    • מוענק רק לאפליקציות מערכת המורשות

הרשאות אלו הינן פריבילגיות וניתן לרכוש אותן רק על ידי הוספתן לקובץ הרלוונטי, למשל, הקובץ 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 אופציונלי עבור כותרת הייחוס, זהו טקסט שמראה מהיכן מקורו של כרטיס האזהרה (החל באנדרואיד 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 יום, אלא אם המשתמש פטר אותם מספר פעמים.

התנהגויות נוספות לא אמורות להידרש למקור אלא אם:

  • המקור מנסה ליישם את ההתנהגות הזו אחרת, למשל, לעולם לא להעלות את הבעיה מחדש.
  • המקור מנסה להשתמש בזה כהתקשרות חוזרת, למשל, כדי לרשום את המידע.

ספק נתונים עבור משתמשים/פרופילים מרובים

ניתן להשתמש ב-API 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)

בדיקה ו-API פנימיים

ממשקי ה-API הפנימיים וממשקי ה-API לבדיקה מיועדים לשימוש פנימי ולכן הם אינם מתוארים בפירוט במדריך זה. עם זאת, ייתכן שנרחיב כמה ממשקי API פנימיים בעתיד כדי לאפשר ליצרני OEM לבנות ממנו ממשק משתמש משלהם, ואנו נעדכן את המדריך הזה כדי לספק הנחיות כיצד להשתמש בהם.

הרשאות

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • משמש עבור ממשקי API של מרכז הבטיחות הפנימיים
    • ניתן רק ל- PermissionController ולמעטפת

אפליקציית הגדרות

הפנייה מחדש של מרכז הבטיחות

כברירת מחדל, ניתן לגשת למרכז הבטיחות דרך אפליקציית ההגדרות עם ערך אבטחה ופרטיות חדש. אם אתה משתמש באפליקציית הגדרות אחרת או אם שינית את אפליקציית ההגדרות, ייתכן שיהיה עליך להתאים אישית את אופן הגישה למרכז הבטיחות.

כאשר מרכז הבטיחות מופעל:

  • הזנת פרטיות מדור קודם היא קוד נסתר
  • ערך אבטחה מדור קודם הוא קוד מוסתר
  • קוד חדש נוסף בנושא אבטחה ופרטיות
  • ערך אבטחה ופרטיות חדש מפנה לקוד של מרכז הבטיחות
  • פעולות הכוונה android.settings.PRIVACY_SETTINGS ו- android.settings.SECURITY_SETTINGS מנותבות מחדש לפתיחת מרכז הבטיחות (קוד: אבטחה , פרטיות )

דפי אבטחה ופרטיות מתקדמים

אפליקציית ההגדרות מכילה הגדרות נוספות תחת הגדרות אבטחה נוספות וכותרות הגדרות פרטיות נוספות , הזמינות ממרכז הבטיחות:

מקורות בטיחות

מרכז הבטיחות משתלב עם סט ספציפי של מקורות בטיחות שמסופקים על ידי אפליקציית ההגדרות:

  • מקור בטיחות מסך נעילה מוודא שמסך נעילה מוגדר עם קוד סיסמה (או אבטחה אחרת), כדי להבטיח שהמידע הפרטי של המשתמש נשמר מגישה חיצונית.
  • מקור בטיחות ביומטרי (מוסתר כברירת מחדל) משטח לשילוב עם טביעת אצבע או חיישן פנים.

קוד המקור של מקורות אלו של מרכז הבטיחות נגיש באמצעות חיפוש קודים של Android . אם אפליקציית ההגדרות לא משתנה (לא בוצעו שינויים בשם החבילה, קוד המקור או קוד המקור העוסק במסך נעילה וביומטריה), אזי האינטגרציה הזו אמורה לפעול מחוץ לקופסה. אחרת, ייתכן שיידרשו שינויים מסוימים, כגון שינוי קובץ התצורה כדי לשנות את שם החבילה של אפליקציית ההגדרות והמקורות המשתלבים עם מרכז הבטיחות, כמו גם האינטגרציה. למידע נוסף, ראה עדכון קובץ התצורה והגדרות האינטגרציה .

על PendingIntent

אם אתה מסתמך על השילוב הקיים של אפליקציית הגדרות מרכז הבטיחות באנדרואיד 14 ומעלה, הבאג המתואר להלן תוקן. קריאת סעיף זה אינה הכרחית במקרה זה.

כאשר אתה בטוח שהבאג לא קיים, הגדר ערך תצורת משאב בוליאני של XML באפליקציית ההגדרות config_isSafetyCenterLockScreenPendingIntentFixed ל- true כדי לבטל את הפתרון לעקיפה בתוך מרכז הבטיחות.

פתרון לעקוף כוונות בהמתנה

באג זה נגרם על ידי הגדרות המשתמשות בתוספות של מופע Intent כדי לקבוע איזה קטע לפתוח. מכיוון ש- Intent#equals לא לוקח בחשבון את התוספות של מופע Intent , מופע PendingIntent עבור סמל תפריט גלגל השיניים והערך נחשבים שווים ומנווטים לאותו ממשק משתמש (למרות שהם נועדו לנווט לממשק משתמש אחר). בעיה זו תוקנה במהדורת QPR על ידי הבחנה בין מופעי PendingIntent לפי קוד בקשה. לחלופין, ניתן להבדיל זאת באמצעות Intent#setId .

מקורות בטיחות פנימיים

חלק ממקורות מרכז הבטיחות הם פנימיים ומיושמים באפליקציית המערכת PermissionController בתוך מודול PermissionController. מקורות אלו מתנהגים כמו מקורות רגילים של מרכז הבטיחות ואינם זוכים לטיפול מיוחד. קוד עבור מקורות אלה זמין באמצעות חיפוש קוד אנדרואיד .

אלו הם בעיקר אותות פרטיות, למשל:

  • נְגִישׁוּת
  • ביטול אוטומטי של אפליקציות שאינן בשימוש
  • גישה למיקום
  • מאזין התראות
  • מידע על מדיניות עבודה