Interagieren Sie mit dem Safety Center

Weiterleitung zum Safety Center

Jede App kann Safety Center mit der Aktion android.content.Intent.ACTION_SAFETY_CENTER (Stringwert android.intent.action.SAFETY_CENTER ) öffnen.

Um das Safety Center zu öffnen, rufen Sie innerhalb einer Activity auf:

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Leiten Sie zu einem bestimmten Problem weiter

Es ist auch möglich, mit bestimmten Absichts-Extras zu einer bestimmten Safety Center-Warnkarte weiterzuleiten. Diese Extras sind nicht für die Verwendung durch Dritte gedacht und daher Teil von SafetyCenterManager , das Teil von @SystemApi ist. Nur System-Apps können auf diese Extras zugreifen.

Absichts-Extras, die eine bestimmte Warnkarte umleiten:

  • EXTRA_SAFETY_SOURCE_ID
    • String-Wert: android.safetycenter.extra.SAFETY_SOURCE_ID
    • String-Typ: Gibt die ID der Sicherheitsquelle der zugehörigen Warnkarte an
    • Erforderlich , damit die Weiterleitung zum Problem funktioniert
  • EXTRA_SAFETY_SOURCE_ISSUE_ID
    • String-Wert: android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
    • String-Typ: Gibt die Warnkarten-ID an
    • Erforderlich , damit die Weiterleitung zum Problem funktioniert
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • String-Wert: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • UserHandle Typ: Gibt UserHandle für die zugehörige Warnkarte an
    • Optional (Standard ist aktueller Benutzer)

Der folgende Codeausschnitt kann innerhalb einer Activity verwendet werden, um den Safety Center-Bildschirm für ein bestimmtes Problem zu öffnen:

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);

Auf eine bestimmte Unterseite umleiten (ab Android 14)

In Android 14 oder höher ist die Safety Center-Seite in mehrere Unterseiten aufgeteilt, die die verschiedenen SafetySourcesGroup darstellen (in Android 13 werden dies als reduzierbare Einträge angezeigt).

Mit diesem Intent-Extra ist es möglich, auf eine bestimmte Unterseite umzuleiten:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • String-Wert: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • String-Typ: Gibt die ID der SafetySourcesGroup an
    • Erforderlich , damit die Weiterleitung auf die Unterseite funktioniert

Der folgende Codeausschnitt kann innerhalb einer Activity verwendet werden, um den Safety Center-Bildschirm auf einer bestimmten Unterseite zu öffnen:

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

startActivity(openSafetyCenterIntent);

Verwenden Sie die Safety Center-Quell-APIs

Die Safety Center-Quell-APIs sind über SafetyCenterManager (ein @SystemApi ) verfügbar. Code für die API-Oberfläche ist in der Codesuche verfügbar. Der Implementierungscode der APIs ist in der Codesuche verfügbar.

Berechtigungen

Auf die Safety Center-Quell-APIs kann nur von System-Apps auf der Zulassungsliste mit den unten aufgeführten Berechtigungen zugegriffen werden. Weitere Informationen finden Sie unter Zulassungsliste für privilegierte Berechtigungen .

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Wird für die SafetyCenterManager#isSafetyCenterEnabled() -API verwendet (nicht erforderlich für Safety Center-Quellen, sie benötigen nur die Berechtigung SEND_SAFETY_CENTER_UPDATE )
    • Wird von System-Apps verwendet, die prüfen, ob das Safety Center aktiviert ist
    • Wird nur System-Apps gewährt, die auf der Zulassungsliste stehen
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Wird für die aktivierte API und die Safety Sources API verwendet
    • Wird nur von Sicherheitsquellen verwendet
    • Wird nur System-Apps gewährt, die auf der Zulassungsliste stehen

Diese Berechtigungen sind privilegiert und Sie können sie nur erwerben, indem Sie sie der entsprechenden Datei hinzufügen, beispielsweise der Datei com.android.settings.xml für die Einstellungen-App und der Datei AndroidManifest.xml der App. Weitere Informationen zum Berechtigungsmodell finden Sie unter protectionLevel .

Holen Sie sich den SafetyCenterManager

SafetyCenterManager ist eine @SystemApi Klasse, auf die über System-Apps ab Android 13 zugegriffen werden kann. Dieser Aufruf zeigt, wie Sie SafetyCenterManager erhalten:

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;
}

Überprüfen Sie, ob Safety Center aktiviert ist

Dieser Aufruf prüft, ob Safety Center aktiviert ist. Der Aufruf erfordert entweder die Berechtigung READ_SAFETY_CENTER_STATUS oder die Berechtigung SEND_SAFETY_CENTER_UPDATE :

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

Daten bereitstellen

Safety Center-Quelldaten mit der angegebenen String sourceId werden Safety Center mit dem SafetySourceData Objekt bereitgestellt, das einen UI-Eintrag und eine Liste von Problemen (Warnkarten) darstellt. Der UI-Eintrag und die Warnkarten können unterschiedliche Schweregrade haben, die in der SafetySourceData Klasse angegeben sind:

  • SEVERITY_LEVEL_UNSPECIFIED
    • Kein Schweregrad angegeben
    • Farbe: Grau oder transparent (abhängig von der SafetySourcesGroup des Eintrags)
    • Wird für dynamische Daten verwendet, die sich als statischer Eintrag in der Benutzeroberfläche ausgeben oder um einen nicht spezifizierten Eintrag anzuzeigen
    • Darf nicht für Warnkarten verwendet werden
  • SEVERITY_LEVEL_INFORMATION
    • Grundlegende Informationen oder kleiner Vorschlag
    • Farbe grün
  • SEVERITY_LEVEL_RECOMMENDATION
    • Empfehlung an den Benutzer, in dieser Angelegenheit Maßnahmen zu ergreifen, da er dadurch gefährdet werden könnte
    • Farbe Gelb
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • Kritische Warnung, dass der Benutzer bei diesem Problem Maßnahmen ergreifen muss, da es ein Risiko darstellt
    • Farbe Rot

SafetySourceData

Das SafetySourceData Objekt besteht aus einem UI-Eintrag, Warnkarten und Invarianten.

  • Optionale SafetySourceStatus Instanz (UI-Eintrag)
  • Liste der SafetySourceIssue Instanzen (Warnkarten)
  • Optionale Bundle Extras (ab 14)
  • Invarianten:
    • Die SafetySourceIssue -Liste muss aus Problemen mit eindeutigen Kennungen bestehen.
    • Die SafetySourceIssue Instanz darf nicht wichtiger sein als SafetySourceStatus , falls vorhanden (es sei denn, SafetySourceStatus ist SEVERITY_LEVEL_UNSPECIFIED , in diesem Fall sind SEVERITY_LEVEL_INFORMATION Probleme zulässig).
    • Zusätzliche Anforderungen, die durch die API-Konfiguration auferlegt werden, müssen erfüllt sein. Wenn es sich beispielsweise um eine reine Issue-Quelle handelt, darf sie keine SafetySourceStatus Instanz bereitstellen.

SafetySourceStatus

  • Erforderlicher CharSequence Titel
  • Erforderliche CharSequence Zusammenfassung
  • Erforderlicher Schweregrad
  • Optionale PendingIntent Instanz, um den Benutzer auf die richtige Seite umzuleiten (standardmäßig wird intentAction aus der Konfiguration verwendet, falls vorhanden)
  • Optionale IconAction (angezeigt als Seitensymbol im Eintrag), bestehend aus:
    • Erforderlicher Symboltyp, der einer der folgenden Typen sein muss:
      • ICON_TYPE_GEAR : Wird als Zahnrad neben dem UI-Eintrag angezeigt
      • ICON_TYPE_INFO : Wird als Informationssymbol neben dem UI-Eintrag angezeigt
    • Erforderlicher PendingIntent , um den Benutzer auf eine andere Seite umzuleiten
  • Optionaler boolescher enabled Wert, der es ermöglicht, den UI-Eintrag als deaktiviert zu markieren, sodass er nicht anklickbar ist (Standard ist true )
  • Invarianten:
    • PendingIntent Instanzen müssen eine Activity öffnen.
    • Wenn der Eintrag deaktiviert ist, muss er SEVERITY_LEVEL_UNSPECIFIED bezeichnet werden.
    • Zusätzliche Anforderungen durch die API-Konfiguration.

SafetySourceIssue

  • Erforderlicher eindeutiger String Bezeichner
  • Erforderlicher CharSequence Titel
  • Optionaler CharSequence -Untertitel
  • Erforderliche CharSequence Zusammenfassung
  • Erforderlicher Schweregrad
  • Optionale Problemkategorie, die eine der folgenden sein muss:
    • ISSUE_CATEGORY_DEVICE : Das Problem betrifft das Gerät des Benutzers.
    • ISSUE_CATEGORY_ACCOUNT : Das Problem betrifft die Konten des Benutzers.
    • ISSUE_CATEGORY_GENERAL : Das Problem beeinträchtigt die allgemeine Sicherheit des Benutzers. Dies ist die Standardeinstellung.
    • ISSUE_CATEGORY_DATA (ab Android 14): Das Problem betrifft die Daten des Benutzers.
    • ISSUE_CATEGORY_PASSWORDS (ab Android 14): Das Problem betrifft die Passwörter des Benutzers.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (ab Android 14): Das Problem betrifft die persönliche Sicherheit des Benutzers.
  • Liste der Action , die der Benutzer für dieses Problem ergreifen kann. Jede Action besteht aus:
    • Erforderlicher eindeutiger String Bezeichner
    • Erforderliches CharSequence -Label
    • Erforderlicher PendingIntent , um den Benutzer auf eine andere Seite umzuleiten oder die Aktion direkt vom Safety Center-Bildschirm aus zu verarbeiten
    • Optionaler boolescher Wert, um anzugeben, ob dieses Problem direkt über den Safety Center-Bildschirm behoben werden kann (Standard ist false ).
    • Optionale CharSequence Erfolgsmeldung, die dem Benutzer angezeigt wird, wenn das Problem direkt über den Safety Center-Bildschirm erfolgreich gelöst wurde
  • Optionaler PendingIntent , der aufgerufen wird, wenn der Benutzer das Problem verwirft (Standard ist, dass nichts aufgerufen wird).
  • Erforderliche String , Bezeichner des Problemtyps; Dies ähnelt der Problemkennung, muss jedoch nicht eindeutig sein und wird zur Protokollierung verwendet
  • Optionaler String für die Deduplizierungs-ID. Dies ermöglicht das Posten desselben SafetySourceIssue aus verschiedenen Quellen und die einmalige Anzeige in der Benutzeroberfläche, vorausgesetzt, sie haben dieselbe deduplicationGroup (ab Android 14). Wenn nicht angegeben, wird das Problem nie dedupliziert
  • Optionale CharSequence für den Attributionstitel. Dies ist ein Text, der angibt, woher die Warnkarte stammt (ab Android 14). Wenn nicht angegeben, wird der Titel der SafetySourcesGroup verwendet
  • Optionale Problemumsetzbarkeit (ab Android 14), die einer der folgenden sein muss:
    • ISSUE_ACTIONABILITY_MANUAL : Der Benutzer muss dieses Problem manuell beheben. Dies ist die Standardeinstellung.
    • ISSUE_ACTIONABILITY_TIP : Dieses Problem ist nur ein Tipp und erfordert möglicherweise keine Benutzereingabe.
    • ISSUE_ACTIONABILITY_AUTOMATIC : Dieses Problem wurde bereits behoben und erfordert möglicherweise keine Benutzereingabe.
  • Optionales Benachrichtigungsverhalten (ab Android 14), das eines der folgenden sein muss:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED : Safety Center entscheidet, ob eine Benachrichtigung für die Warnkarte erforderlich ist. Dies ist die Standardeinstellung.
    • NOTIFICATION_BEHAVIOR_NEVER : Es wird keine Benachrichtigung gepostet.
    • NOTIFICATION_BEHAVIOR_DELAYED : Eine Benachrichtigung wird einige Zeit nach der ersten Meldung des Problems veröffentlicht.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY : Eine Benachrichtigung wird veröffentlicht, sobald das Problem gemeldet wird.
  • Optionale Notification , um eine benutzerdefinierte Benachrichtigung mit der Warnkarte anzuzeigen (ab Android 14). Wenn nicht angegeben, wird die Notification von der Warnkarte abgeleitet. Zusammengesetzt aus:
    • Erforderlicher CharSequence Titel
    • Erforderliche CharSequence Zusammenfassung
    • Liste der Action , die der Benutzer für diese Benachrichtigung ausführen kann
  • Invarianten:
    • Die Liste der Action muss aus Aktionen mit eindeutigen Bezeichnern bestehen
    • Die Liste der Action Instanzen muss entweder ein oder zwei Action Elemente enthalten. Wenn die Umsetzbarkeit nicht ISSUE_ACTIONABILITY_MANUAL ist, ist eine Action zulässig.
    • Der OnDismiss PendingIntent darf keine Activity öffnen
    • Zusätzliche Anforderungen durch die API-Konfiguration

Daten werden bei bestimmten Ereignissen an das Safety Center bereitgestellt. Daher muss angegeben werden, was die Quelle dazu veranlasst hat, SafetySourceData eine SafetyEvent Instanz bereitzustellen.

SafetyEvent

  • Erforderlicher Typ, der einer der folgenden sein muss:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED : Der Status der Quelle hat sich geändert.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED : Reagiert auf ein Aktualisierungs-/Neuscan-Signal vom Safety Center; Verwenden Sie dies anstelle von SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED , damit Safety Center die Aktualisierungs-/Neuscan-Anforderung verfolgen kann.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED : Wir haben SafetySourceIssue.Action direkt über den Safety Center-Bildschirm gelöst. Verwenden Sie dies anstelle von SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED , damit Safety Center die aufgelöste SafetySourceIssue.Action verfolgen kann.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : Wir haben versucht, SafetySourceIssue.Action direkt über den Safety Center-Bildschirm zu lösen, konnten dies jedoch nicht tun. Verwenden Sie dies anstelle von SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED , damit Safety Center nachverfolgen kann, ob SafetySourceIssue.Action fehlgeschlagen ist.
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : Die Sprache des Geräts hat sich geändert, daher aktualisieren wir den Text der bereitgestellten Daten; Es ist erlaubt, hierfür SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED zu verwenden.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED : Wir stellen diese Daten als Teil eines ersten Starts bereit, da die Safety Center-Daten nicht über Neustarts hinweg bestehen bleiben; Es ist erlaubt, hierfür SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED zu verwenden.
  • Optionaler String Bezeichner für die Aktualisierungs-Broadcast-ID.
  • Optionaler String Bezeichner für die SafetySourceIssue Instanz, die aufgelöst wird.
  • Optionaler String Bezeichner für die SafetySourceIssue.Action Instanz, die aufgelöst wird.
  • Invarianten:
    • Die Aktualisierungs-Broadcast-ID muss angegeben werden, wenn der Typ SAFETY_EVENT_TYPE_REFRESH_REQUESTED ist
    • Die Problem- und Aktions-IDs müssen angegeben werden, wenn der Typ entweder SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED oder SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED ist

Nachfolgend finden Sie ein Beispiel dafür, wie eine Quelle Daten an Safety Center bereitstellen könnte (in diesem Fall stellt sie einen Eintrag mit einer einzelnen Warnkarte bereit):

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);

Rufen Sie die zuletzt bereitgestellten Daten ab

Sie können die letzten an Safety Center bereitgestellten Daten für eine Quelle abrufen, die Ihrer App gehört. Sie können dies verwenden, um etwas in Ihrer eigenen Benutzeroberfläche anzuzeigen, um zu überprüfen, ob die Daten aktualisiert werden müssen, bevor Sie einen teuren Vorgang durchführen, oder um Safety Center dieselbe SafetySourceData Instanz mit einigen Änderungen oder mit einer neuen SafetyEvent Instanz bereitzustellen. Es ist auch zum Testen nützlich.

Verwenden Sie diesen Code, um die letzten an Safety Center übermittelten Daten abzurufen:

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

Melden Sie einen Fehler

Wenn Sie keine SafetySourceData Daten erfassen können, können Sie den Fehler an Safety Center melden, das den Eintrag in Grau ändert, die zwischengespeicherten Daten löscht und eine Meldung wie „Einstellung konnte nicht überprüft werden“ ausgibt. Sie können auch einen Fehler melden, wenn eine Instanz von SafetySourceIssue.Action nicht aufgelöst werden kann. In diesem Fall werden die zwischengespeicherten Daten nicht gelöscht und der UI-Eintrag wird nicht geändert. Dem Benutzer wird jedoch eine Nachricht angezeigt, die ihn darüber informiert, dass ein Fehler aufgetreten ist.

Sie können den Fehler mithilfe von SafetySourceErrorDetails bereitstellen, das aus Folgendem besteht:

  • SafetySourceErrorDetails : Erforderliche SafetyEvent Instanz:
// 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);

Reagieren Sie auf eine Aktualisierungs- oder Neuscan-Anfrage

Sie können vom Safety Center ein Signal erhalten, um neue Daten bereitzustellen. Durch die Reaktion auf eine Aktualisierungs- oder Neuscan-Anfrage wird sichergestellt, dass der Benutzer den aktuellen Status sieht, wenn er Safety Center öffnet und auf die Scan-Schaltfläche tippt.

Dies geschieht durch den Empfang einer Sendung mit der folgenden Aktion:

  • ACTION_REFRESH_SAFETY_SOURCES
    • String-Wert: android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • Wird ausgelöst, wenn Safety Center eine Anfrage zum Aktualisieren der Daten der Sicherheitsquelle für eine bestimmte App sendet
    • Geschützte Absicht, die nur vom System gesendet werden kann
    • Wird als explizite Absicht an alle Sicherheitsquellen in der Konfigurationsdatei gesendet und erfordert die Berechtigung SEND_SAFETY_CENTER_UPDATE

Im Rahmen dieser Sendung werden folgende Extras bereitgestellt:

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • String-Wert: android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • Der String-Array-Typ ( String[] ) stellt die Quell-IDs dar, die für die angegebene App aktualisiert werden sollen
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • String-Wert: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Ganzzahliger Typ, stellt einen Anforderungstyp @IntDef dar
    • Muss einer von Folgendem sein:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA : Fordert die Quelle auf, Daten relativ schnell bereitzustellen, normalerweise wenn der Benutzer die Seite öffnet
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA : Fordert die Quelle auf, möglichst aktuelle Daten bereitzustellen, normalerweise, wenn der Benutzer die Schaltfläche „Neu scannen“ drückt
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

    • String-Wert: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
    • Der String-Typ stellt eine eindeutige Kennung für die angeforderte Aktualisierung dar

Um ein Signal vom Safety Center zu erhalten, implementieren Sie eine BroadcastReceiver Instanz. Der Broadcast wird mit speziellen BroadcastOptions gesendet, die es dem Empfänger ermöglichen, einen Vordergrunddienst zu starten.

BroadcastReceiver antwortet auf eine Aktualisierungsanforderung:

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;
  }
}

Die gleiche Instanz von BroadcastReceiver im obigen Beispiel ist in AndroidManifest.xml deklariert:

<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>

Idealerweise ist eine Safety Center-Quelle so implementiert, dass sie SafetyCenterManager aufruft, wenn sich ihre Daten ändern. Aus Gründen der Systemgesundheit empfehlen wir, nur auf das Signal zum erneuten Scannen zu reagieren (wenn der Benutzer auf die Scan-Schaltfläche tippt) und nicht, wenn der Benutzer das Sicherheitscenter öffnet. Wenn diese Funktionalität erforderlich ist, muss das Feld refreshOnPageOpenAllowed="true" in der Konfigurationsdatei festgelegt werden, damit die Quelle in diesen Fällen die zugestellte Übertragung empfängt.

Reagieren Sie auf das Safety Center, wenn es aktiviert oder deaktiviert ist

Sie können darauf reagieren, wenn das Safety Center aktiviert oder deaktiviert ist, indem Sie diese Absichtsaktion verwenden:

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • String-Wert: android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • Wird ausgelöst, wenn das Safety Center aktiviert oder deaktiviert ist, während das Gerät läuft
    • Wird beim Booten nicht aufgerufen (verwenden Sie dazu ACTION_BOOT_COMPLETED )
    • Geschützte Absicht, die nur vom System gesendet werden kann
    • Wird als explizite Absicht an alle Sicherheitsquellen in der Konfigurationsdatei gesendet und erfordert die Berechtigung SEND_SAFETY_CENTER_UPDATE
    • Wird als implizite Absicht gesendet, die die Berechtigung READ_SAFETY_CENTER_STATUS erfordert

Diese Absichtsaktion ist nützlich, um Funktionen zu aktivieren oder zu deaktivieren, die sich auf das Safety Center auf dem Gerät beziehen.

Implementieren Sie Lösungsmaßnahmen

Eine Lösungsaktion ist eine SafetySourceIssue.Action Instanz, die ein Benutzer direkt über den Safety Center-Bildschirm auflösen kann. Der Benutzer tippt auf eine Aktionsschaltfläche und die von der Sicherheitsquelle gesendete PendingIntent Instanz auf SafetySourceIssue.Action wird ausgelöst, wodurch das Problem im Hintergrund behoben und das Safety Center benachrichtigt wird, wenn es erledigt ist.

Um Lösungsaktionen zu implementieren, kann die Safety Center-Quelle einen Dienst verwenden, wenn der Vorgang voraussichtlich einige Zeit in Anspruch nehmen wird ( PendingIntent.getService ), oder einen Broadcast-Empfänger ( PendingIntent.getBroadcast ).

Verwenden Sie diesen Code, um ein gelöstes Problem an Safety Center zu senden:

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 löst die Aktion auf:

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).
  }
}

Die gleiche Instanz von BroadcastReceiver im obigen Beispiel ist in AndroidManifest.xml deklariert:

<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>

Reagieren Sie auf sachliche Entlassungen

Sie können eine PendingIntent Instanz angeben, die ausgelöst werden kann, wenn eine SafetySourceIssue Instanz verworfen wird. Das Safety Center kümmert sich um die folgenden Problementlassungen:

  • Wenn eine Quelle ein Problem anstößt, kann ein Benutzer es auf dem Safety Center-Bildschirm verwerfen, indem er auf die Schaltfläche „Verwerfen“ (eine X- Schaltfläche auf der Warnkarte) tippt.
  • Wenn ein Benutzer ein Problem ablehnt und das Problem weiterhin besteht, wird es nicht erneut in der Benutzeroberfläche angezeigt.
  • Permanente Entlassungen auf einer Festplatte bleiben während Geräteneustarts bestehen.
  • Wenn die Safety Center-Quelle ein Problem nicht mehr bereitstellt und das Problem zu einem späteren Zeitpunkt erneut bereitstellt, tritt das Problem erneut auf. Dies dient dazu, Situationen zu ermöglichen, in denen ein Benutzer eine Warnung sieht, sie verwirft und dann Maßnahmen ergreift, die das Problem beheben sollten, der Benutzer dann jedoch erneut etwas unternimmt, das ein ähnliches Problem verursacht. An diesem Punkt sollte die Warnkarte wieder auftauchen.
  • Gelbe und rote Warnkarten werden alle 180 Tage erneut angezeigt, es sei denn, der Benutzer hat sie mehrmals abgelehnt.

Zusätzliche Verhaltensweisen sollten von der Quelle nicht benötigt werden, es sei denn:

  • Die Quelle versucht, dieses Verhalten anders zu implementieren, z. B. indem sie das Problem nie wieder auftauchen lässt.
  • Die Quelle versucht dies als Rückruf zu nutzen, um beispielsweise die Informationen zu protokollieren.

Stellen Sie Daten für mehrere Benutzer/Profile bereit

Die SafetyCenterManager API kann benutzer- und profilübergreifend verwendet werden. Weitere Informationen finden Sie unter Erstellen von Multiuser-fähigen Apps . Das Context , das SafetyCenterManager bereitstellt, ist einer UserHandle Instanz zugeordnet, sodass die zurückgegebene SafetyCenterManager Instanz mit dem Safety Center für diese UserHandle Instanz interagiert. Standardmäßig ist Context dem aktuellen Benutzer zugeordnet, es ist jedoch möglich, eine Instanz für einen anderen Benutzer zu erstellen, wenn die App über die Berechtigungen INTERACT_ACROSS_USERS und INTERACT_ACROSS_USERS_FULL verfügt. Dieses Beispiel zeigt das Tätigen eines Anrufs über Benutzer/Profile hinweg:

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

Jeder Benutzer auf dem Gerät kann mehrere verwaltete Profile haben. Das Safety Center stellt für jeden Benutzer unterschiedliche Daten bereit, führt jedoch die Daten aller verwalteten Profile zusammen, die einem bestimmten Benutzer zugeordnet sind.

Wenn in der Konfigurationsdatei für die Quelle profile="all_profiles" festgelegt ist, geschieht Folgendes:

  • Es gibt einen UI-Eintrag für den Benutzer (übergeordnetes Profil) und alle zugehörigen verwalteten Profile (die titleForWork Instanzen verwenden).
  • Das Aktualisierungs- oder Neuscan-Signal wird für das übergeordnete Profil und alle zugehörigen verwalteten Profile gesendet. Der zugehörige Empfänger wird für jedes Profil gestartet und kann die zugehörigen Daten direkt an SafetyCenterManager bereitstellen, ohne dass ein profilübergreifender Aufruf durchgeführt werden muss, es sei denn, der Empfänger oder die App ist singleUser .

  • Von der Quelle wird erwartet, dass sie Daten für den Benutzer und alle seine verwalteten Profile bereitstellt. Die Daten für jeden UI-Eintrag können je nach Profil unterschiedlich sein.

Testen

Sie können auf ShadowSafetyCenterManager zugreifen und ihn in einem Robolectric-Test verwenden.

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);
}

Sie können weitere End-to-End-Tests (E2E) schreiben, aber das würde den Rahmen dieses Leitfadens sprengen. Weitere Informationen zum Schreiben dieser E2E-Tests finden Sie unter CTS-Tests (CtsSafetyCenterTestCases).

Test- und interne APIs

Die internen APIs und Test-APIs sind für den internen Gebrauch bestimmt und werden daher in diesem Handbuch nicht ausführlich beschrieben. Möglicherweise werden wir jedoch in Zukunft einige interne APIs erweitern, um OEMs die Erstellung ihrer eigenen Benutzeroberfläche zu ermöglichen. Wir werden diesen Leitfaden aktualisieren, um Hinweise zu deren Verwendung zu geben.

Berechtigungen

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Wird für die internen Safety Center-APIs verwendet
    • Wird nur PermissionController und Shell gewährt

Einstellungen-App

Weiterleitung des Safety Centers

Der Zugriff auf das Safety Center erfolgt standardmäßig über die Einstellungen-App mit einem neuen Eintrag für Sicherheit und Datenschutz . Wenn Sie eine andere Einstellungen-App verwenden oder die Einstellungen-App geändert haben, müssen Sie möglicherweise anpassen, wie auf das Safety Center zugegriffen wird.

Wenn Safety Center aktiviert ist:

  • Der Legacy- Datenschutzeintrag ist versteckter Code
  • Der Legacy- Sicherheitseintrag ist versteckter Code
  • Neuer Sicherheits- und Datenschutzeintrag ist hinzugefügter Code
  • Der neue Eintrag „Sicherheit und Datenschutz“ leitet zum Safety Center- Code weiter
  • Die Absichtsaktionen android.settings.PRIVACY_SETTINGS und android.settings.SECURITY_SETTINGS werden zum Öffnen des Safety Centers umgeleitet (Code: security , Privacy )

Erweiterte Sicherheits- und Datenschutzseiten

Die App „Einstellungen“ enthält unter den Titeln „Weitere Sicherheitseinstellungen“ und „Weitere Datenschutzeinstellungen“ zusätzliche Einstellungen, die im Safety Center verfügbar sind:

Sicherheitsquellen

Safety Center lässt sich in einen bestimmten Satz von Sicherheitsquellen integrieren, die von der Einstellungen-App bereitgestellt werden:

  • Eine Sicherheitsquelle für den Sperrbildschirm überprüft, ob ein Sperrbildschirm mit einem Passcode (oder einer anderen Sicherheit) eingerichtet ist, um sicherzustellen, dass die privaten Daten des Benutzers vor externem Zugriff geschützt sind.
  • Eine biometrische Sicherheitsquelle (standardmäßig ausgeblendet) wird angezeigt, die in einen Fingerabdruck- oder Gesichtssensor integriert werden kann.

Der Quellcode für diese Safety Center-Quellen ist über die Android-Codesuche zugänglich. Wenn die Einstellungen-App nicht geändert wird (es werden keine Änderungen am Paketnamen, am Quellcode oder am Quellcode vorgenommen, der sich mit einem Sperrbildschirm und biometrischen Daten befasst), sollte diese Integration sofort funktionieren. Andernfalls sind möglicherweise einige Änderungen erforderlich, z. B. die Änderung der Konfigurationsdatei, um den Paketnamen der App „Einstellungen“ und die in Safety Center integrierten Quellen sowie die Integration zu ändern. Weitere Informationen finden Sie unter Aktualisieren der Konfigurationsdatei und der Integrationseinstellungen .

Über PendingIntent

Wenn Sie sich auf die bestehende Safety Center-Integration der Einstellungen-App in Android 14 oder höher verlassen, wurde der unten beschriebene Fehler behoben. Das Lesen dieses Abschnitts ist in diesem Fall nicht erforderlich.

Wenn Sie sicher sind, dass der Fehler nicht vorliegt, legen Sie in der App „Einstellungen“ config_isSafetyCenterLockScreenPendingIntentFixed einen XML-Booleschen Ressourcenkonfigurationswert auf „ true fest, um die Problemumgehung im Safety Center zu deaktivieren.

PendingIntent-Problemumgehung

Dieser Fehler wird dadurch verursacht, dass Einstellungen Intent Instanzextras verwenden, um zu bestimmen, welches Fragment geöffnet werden soll. Da Intent#equals die Extras der Intent Instanz nicht berücksichtigt, werden die PendingIntent Instanz für das Zahnradmenüsymbol und der Eintrag als gleich betrachtet und navigieren zur gleichen Benutzeroberfläche (obwohl sie für die Navigation zu einer anderen Benutzeroberfläche gedacht sind). Dieses Problem wurde in einer QPR-Version behoben, indem die PendingIntent Instanzen nach Anforderungscode unterschieden wurden. Alternativ könnte dies durch die Verwendung von Intent#setId unterschieden werden.

Interne Sicherheitsquellen

Einige Safety Center-Quellen sind intern und werden in der PermissionController-System-App im PermissionController-Modul implementiert. Diese Quellen verhalten sich wie normale Safety Center-Quellen und erhalten keine Sonderbehandlung. Code für diese Quellen ist über die Android-Codesuche verfügbar.

Dabei handelt es sich vor allem um Datenschutzsignale, zum Beispiel:

  • Barrierefreiheit
  • Nicht verwendete Apps automatisch widerrufen
  • Standortzugriff
  • Benachrichtigungs-Listener
  • Informationen zur Arbeitsrichtlinie