הפניה אוטומטית למרכז הבטיחות
כל אפליקציה יכולה לפתוח את מרכז הבטיחות באמצעות הפעולה android.content.Intent.ACTION_SAFETY_CENTER
(ערך המחרוזת android.intent.action.SAFETY_CENTER
).
כדי לפתוח את מרכז הבטיחות, צריך לבצע שיחה מתוך מופע של Activity
:
Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);
startActivity(openSafetyCenterIntent);
הפניה אוטומטית לבעיה ספציפית
אפשר גם להפנות לכרטיס אזהרה ספציפי במרכז הבטיחות באמצעות תוספות Intent ספציפיות. התוספות האלה לא נועדו לשימוש על ידי צדדים שלישיים, ולכן הן חלק מ-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
type: מציין את הערך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);
שימוש בממשקי ה-API של המקור במרכז הבטיחות
ממשקי ה-API המקוריים של מרכז הבטיחות זמינים באמצעות SafetyCenterManager
(שהוא @SystemApi
). הקוד לפלטפורמת ה-API זמין ב-Code Search.
קוד ההטמעה של ממשקי ה-API זמין בחיפוש קוד.
הרשאות
רק לאפליקציות מערכת שמופיעות ברשימת ההיתרים יש גישה לממשקי ה-API של מקור מרכז הבטיחות, באמצעות ההרשאות שמפורטות בהמשך. מידע נוסף זמין במאמר הוספת הרשאות להרשאה.
READ_SAFETY_CENTER_STATUS
signature|privileged
- הוא משמש ל-API של
SafetyCenterManager#isSafetyCenterEnabled()
(לא צריך את המקורות במרכז הבטיחות, הם צריכים רק את ההרשאהSEND_SAFETY_CENTER_UPDATE
) - אפליקציות מערכת שמבדקות אם מרכז הבטיחות מופעל משתמשות בה
- הרשאה שמוענקת רק לאפליקציות מערכת שברשימת ההיתרים
SEND_SAFETY_CENTER_UPDATE
internal|privileged
- משמש את ממשק ה-API המופעל ואת Safety Sources API
- בשימוש במקורות בטיחות בלבד
- מוענק רק לאפליקציות מערכת שכלולות ברשימת ההיתרים
להרשאות האלה יש הרשאות ולכן אפשר לרכוש אותן רק אם מוסיפים אותן
לקובץ הרלוונטי, לדוגמה, לקובץ
com.android.settings.xml
לאפליקציית ההגדרות ולקובץ ה-AndroidManifest.xml
של האפליקציה. מידע נוסף על מודל ההרשאות מופיע ב-protectionLevel
.
הורדה של SafetyCenterManager
SafetyCenterManager
היא סוג של @SystemApi
שאפשר לגשת אליו מאפליקציות מערכת החל מגרסה 13 של Android. הקריאה הזו מדגימה איך לקבל את 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
לשם השיוך (Attribution), זהו טקסט שמציג את המקור של כרטיס האזהרה (החל מ-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
ישירות מהמסך של מרכז הבטיחות. כדי לעקוב אחרי הבעיה שלSafetySourceIssue.Action
, צריך להשתמש במשתנה הזה במקום ב-SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
במרכז הבטיחות.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
: ניסינו לפתור את הבעיהSafetySourceIssue.Action
ישירות מהמסך של מרכז הבטיחות, אבל לא הצלחנו. כדי לעקוב אחרי כשל שלSafetySourceIssue.Action
, השתמשו באפשרות הזו במקום ב-SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
.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
).
אפשר להשתמש בקוד הזה כדי לשלוח ל-Safety Center דיווח על בעיה שהושלמה:
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 יום, אלא אם המשתמש סגר אותם כמה פעמים.
לא אמורה להיות למקור צורך בהתנהגויות נוספות, אלא אם:
- המקור מנסה להטמיע את ההתנהגות הזו בצורה שונה, למשל, לא להציג שוב את הבעיה.
- המקור מנסה להשתמש בזה כקריאה חוזרת (callback), למשל כדי לתעד את המידע ביומן.
מתן נתונים למספר משתמשים/פרופילים
ניתן להשתמש ב-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 פנימיים כדי לאפשר ליצרני ציוד מקורי לבנות ממשק משתמש משלהם, ונעדכן את המדריך הזה כדי לספק הדרכה לשימוש בהם.
הרשאות
MANAGE_SAFETY_CENTER
internal|installer|role
- משמש לממשקי ה-API הפנימיים של מרכז הבטיחות
- מוענק רק ל-PermissionsController ולמעטפת
אפליקציית ההגדרות
הפניה אוטומטית למרכז הבטיחות
כברירת מחדל, אפשר לגשת למרכז הבטיחות דרך אפליקציית ההגדרות, עם רשומה חדשה של אבטחה ופרטיות. אם אתם משתמשים באפליקציית הגדרות אחרת או שיניתם את אפליקציית ההגדרות, יכול להיות שתצטרכו להתאים אישית את הגישה למרכז הבטיחות.
כשמפעילים את מרכז הבטיחות:
- הערך הישן של Privacy (פרטיות) מוסתר בקוד
- רשומת אבטחה מדור קודם מוסתרת על ידי קוד
- נוספה רשומה חדשה בנושא אבטחה ופרטיות קוד
- הוספת האפשרות אבטחה ופרטיות שתעביר אוטומטית לדף קוד של מרכז הבטיחות
- הפעולות של
android.settings.PRIVACY_SETTINGS
ו-android.settings.SECURITY_SETTINGS
מופנות למרכז הבטיחות הפתוח (קוד: אבטחה, פרטיות)
דפי אבטחה ופרטיות מתקדמים
אפליקציית ההגדרות כוללת הגדרות נוספות בקטעים הגדרות אבטחה נוספות והגדרות פרטיות נוספות, שזמינות במרכז הבטיחות:
קוד אבטחה מתקדם
קוד פרטיות מתקדם
החל מ-Android 14, דף ההגדרות המתקדמות של האבטחה והפרטיות ימוזג לדף אחד בשם 'עוד אבטחה ופרטיות' עם פעולת כוונה (intent)
"com.android.settings.MORE_SECURITY_PRIVACY_SETTINGS"
מקורות בטיחות
מרכז הבטיחות משתלב עם קבוצה ספציפית של מקורות בטיחות שמספקת אפליקציית ההגדרות:
- מקור אבטחה של מסך נעילה מאמת שמסך הנעילה מוגדר עם סיסמה (או אמצעי אבטחה אחר), כדי לוודא שהמידע הפרטי של המשתמש מוגן מפני גישה חיצונית.
- מקור בטיחות ביומטרי (מוסתר כברירת מחדל) משתלב כדי לשלב עם חיישן טביעות האצבע או עם חיישן הפנים.
אפשר לגשת לקוד המקור של המקורות האלה במרכז הבטיחות דרך Android code search. אם לא בוצעו שינויים באפליקציית ההגדרות (לא מתבצעים שינויים בשם החבילה, בקוד המקור או בקוד המקור שמטפל במסך נעילה ובמידע ביומטרי), השילוב הזה צריך לפעול מחוץ לאריזה. אחרת, יכול להיות שיהיה צורך לבצע שינויים מסוימים, כמו שינוי קובץ התצורה כדי לשנות את שם החבילה של אפליקציית ההגדרות והמקורות שמשולבים עם מרכז הבטיחות, וגם את השילוב. למידע נוסף, תוכלו לקרוא את המאמר עדכון קובץ התצורה והגדרות השילוב.
מידע על PendingIntent
אם אתם מסתמכים על השילוב הקיים של מרכז הבטיחות באפליקציית ההגדרות ב-Android מגרסה 14 ואילך, הבאג שמתואר בהמשך תוקן. במקרה הזה אין צורך לקרוא את הקטע הזה.
כשתהיו בטוחים שהבאג לא קיים, תוכלו להגדיר ערך של הגדרת משאב בוליאני ב-XML באפליקציית ההגדרות config_isSafetyCenterLockScreenPendingIntentFixed
לערך true
כדי להשבית את הפתרון החלופי במרכז הבטיחות.
פתרון עקיף של PendingIntent
הבאג הזה נגרם על ידי 'הגדרות' באמצעות תוספות למכונה של Intent
כדי לקבוע איזה מקטע לפתוח. מכיוון ש-Intent#equals
לא לוקח בחשבון את התוספות של מופע Intent
, המכונה PendingIntent
של סמל תפריט גלגל השיניים והרשומה נחשבות שוות ומנווטים לאותו ממשק משתמש (למרות שהן מיועדות לנווט לממשק משתמש אחר). הבעיה הזו תוקנה במהדורת QPR, על ידי הבחנה בין המכונות של PendingIntent
לפי קוד הבקשה. לחלופין, אפשר להבדיל בין זה באמצעות הפקודה Intent#setId
.
מקורות בטיחות פנימיים
חלק מהמקורות של מרכז הבטיחות הם פנימיים, והם מיושמים באפליקציית המערכת PermissionController בתוך המודול PermissionController. המקורות האלה מתנהגים כמו מקורות רגילים של מרכז הבטיחות ולא מקבלים טיפול מיוחד. הקוד של המקורות האלה זמין דרך חיפוש קוד ב-Android.
אלה בעיקר אותות פרטיות, למשל:
- נגישות
- ביטול אוטומטי של אפליקציות שלא נמצאות בשימוש
- גישה למיקום
- מאזין להתראות
- פרטים על המדיניות של מקום העבודה