Wejdź w interakcję z Centrum bezpieczeństwa

Przekieruj do Centrum bezpieczeństwa

Dowolna aplikacja może otworzyć Centrum bezpieczeństwa za pomocą akcji android.content.Intent.ACTION_SAFETY_CENTER (wartość ciągu android.intent.action.SAFETY_CENTER ).

Aby otworzyć Centrum bezpieczeństwa, wykonaj połączenie z instancji Activity :

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Przekieruj do konkretnego problemu

Możliwe jest również przekierowanie do konkretnej karty ostrzegawczej w Centrum bezpieczeństwa przy użyciu określonych dodatków. Dodatki te nie są przeznaczone do użytku przez strony trzecie, dlatego stanowią część SafetyCenterManager , która jest częścią @SystemApi . Dostęp do tych dodatków mają tylko aplikacje systemowe.

Dodatki intencji, które przekierowują określoną kartę ostrzegawczą:

  • EXTRA_SAFETY_SOURCE_ID
    • Wartość ciągu: android.safetycenter.extra.SAFETY_SOURCE_ID
    • Typ ciągu: Określa identyfikator źródła bezpieczeństwa powiązanej karty ostrzegawczej
    • Wymagane , aby przekierowanie do problemu zadziałało
  • EXTRA_SAFETY_SOURCE_ISSUE_ID
    • Wartość ciągu: android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
    • Typ ciągu: Określa identyfikator karty ostrzegawczej
    • Wymagane , aby przekierowanie do problemu zadziałało
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Wartość ciągu: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Typ UserHandle : Określa UserHandle dla powiązanej karty ostrzeżenia
    • Opcjonalne (domyślnie jest to bieżący użytkownik)

Poniższego fragmentu kodu można użyć z poziomu instancji Activity , aby otworzyć ekran Centrum bezpieczeństwa dotyczący konkretnego problemu:

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

Przekieruj na konkretną podstronę (od Androida 14)

W systemie Android 14 lub nowszym strona Centrum bezpieczeństwa jest podzielona na wiele podstron reprezentujących różne SafetySourcesGroup (w systemie Android 13 jest to wyświetlane jako zwijane wpisy).

Możliwe jest przekierowanie na konkretną podstronę za pomocą tej dodatkowej intencji:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • Wartość ciągu: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • Typ ciągu: Określa identyfikator SafetySourcesGroup
    • Wymagane do działania przekierowania na podstronę

Poniższy fragment kodu można wykorzystać z poziomu instancji Activity , aby otworzyć ekran Centrum bezpieczeństwa do określonej podstrony:

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

startActivity(openSafetyCenterIntent);

Użyj źródłowych interfejsów API Centrum bezpieczeństwa

Źródłowe interfejsy API Centrum bezpieczeństwa są dostępne za pomocą SafetyCenterManager (który jest @SystemApi ). Kod powierzchni API jest dostępny w wyszukiwarce kodu . Kod implementacji interfejsów API jest dostępny w wyszukiwarce kodu .

Uprawnienia

Źródłowe interfejsy API Centrum bezpieczeństwa są dostępne tylko dla aplikacji systemowych znajdujących się na liście dozwolonych i korzystających z uprawnień wymienionych poniżej. Aby uzyskać dodatkowe informacje, zobacz Lista dozwolonych uprawnień uprzywilejowanych .

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Używane w interfejsie API SafetyCenterManager#isSafetyCenterEnabled() (nie są potrzebne w przypadku źródeł Centrum bezpieczeństwa, wymagają jedynie uprawnienia SEND_SAFETY_CENTER_UPDATE )
    • Używany przez aplikacje systemowe, które sprawdzają, czy Centrum bezpieczeństwa jest włączone
    • Przyznawany tylko aplikacjom systemowym znajdującym się na liście dozwolonych
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Używany w przypadku włączonego interfejsu API i interfejsu API Safety Sources
    • Używane wyłącznie przez bezpieczne źródła
    • Przyznawany tylko aplikacjom systemowym znajdującym się na liście dozwolonych

Uprawnienia te są uprzywilejowane i można je uzyskać jedynie poprzez dodanie ich do odpowiedniego pliku, na przykład pliku com.android.settings.xml dla aplikacji Ustawienia i pliku AndroidManifest.xml aplikacji. Aby uzyskać więcej informacji na temat modelu uprawnień, zobacz protectionLevel .

Pobierz SafetyCenterManager

SafetyCenterManager to klasa @SystemApi dostępna z aplikacji systemowych począwszy od Androida 13. To wywołanie pokazuje, jak uzyskać 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;
}

Sprawdź, czy Centrum bezpieczeństwa jest włączone

To wywołanie sprawdza, czy Centrum bezpieczeństwa jest włączone. Połączenie wymaga uprawnienia READ_SAFETY_CENTER_STATUS lub SEND_SAFETY_CENTER_UPDATE :

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

Podaj dane

Dane źródłowe Safety Center o podanym String sourceId są dostarczane do Safety Center za pomocą obiektu SafetySourceData , który reprezentuje wpis interfejsu użytkownika i listę problemów (karty ostrzeżeń). Wpis interfejsu użytkownika i karty ostrzeżeń mogą mieć różne poziomy ważności określone w klasie SafetySourceData :

  • SEVERITY_LEVEL_UNSPECIFIED
    • Nie określono wagi
    • Kolor: Szary lub przezroczysty (w zależności od SafetySourcesGroup wpisu)
    • Używany do danych dynamicznych, które udają statyczny wpis w interfejsie użytkownika lub do pokazania nieokreślonego wpisu
    • Nie wolno używać do kart ostrzegawczych
  • SEVERITY_LEVEL_INFORMATION
    • Podstawowe informacje lub drobna sugestia
    • Zielony kolor
  • SEVERITY_LEVEL_RECOMMENDATION
    • Zalecenie, aby użytkownik podjął działania w tej sprawie, ponieważ może to narazić go na ryzyko
    • Kolor żółty
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • Krytyczne ostrzeżenie, że użytkownik musi podjąć działania w tej sprawie, ponieważ stwarza ona ryzyko
    • Kolor czerwony

SafetySourceData

Obiekt SafetySourceData składa się z wpisu interfejsu użytkownika, kart ostrzeżeń i niezmienników.

  • Opcjonalna instancja SafetySourceStatus (wpis interfejsu użytkownika)
  • Lista instancji SafetySourceIssue (karty ostrzegawcze)
  • Opcjonalne dodatki Bundle (od 14)
  • Niezmienniki:
    • Lista SafetySourceIssue musi składać się ze spraw o unikalnych identyfikatorach.
    • Instancja SafetySourceIssue nie może mieć większego znaczenia niż SafetySourceStatus , jeśli taka istnieje (chyba że SafetySourceStatus ma SEVERITY_LEVEL_UNSPECIFIED , w którym to przypadku dozwolone są problemy SEVERITY_LEVEL_INFORMATION ).
    • Muszą zostać spełnione dodatkowe wymagania nałożone przez konfigurację API, na przykład jeśli źródło ma charakter wyłącznie problemowy, nie może udostępniać instancji SafetySourceStatus .

SafetySourceStatus

  • Wymagany tytuł CharSequence
  • Wymagane podsumowanie CharSequence
  • Wymagany poziom ważności
  • Opcjonalna instancja PendingIntent do przekierowania użytkownika na właściwą stronę (domyślnie używa intentAction z konfiguracji, jeśli istnieje)
  • Opcjonalna IconAction (pokazana jako ikona boczna na wpisie) składająca się z:
    • Wymagany typ ikony, który musi należeć do jednego z następujących typów:
      • ICON_TYPE_GEAR : Pokazany jako koło zębate obok wpisu interfejsu użytkownika
      • ICON_TYPE_INFO : Wyświetlana jako ikona informacji obok wpisu interfejsu użytkownika
    • Wymagany PendingIntent , aby przekierować użytkownika na inną stronę
  • Opcjonalna enabled wartość logiczna, która umożliwia oznaczenie wpisu interfejsu użytkownika jako wyłączonego, więc nie można go kliknąć (wartość domyślna to true )
  • Niezmienniki:
    • Instancje PendingIntent muszą otwierać instancję Activity .
    • Jeśli wpis jest wyłączony, musi być oznaczony SEVERITY_LEVEL_UNSPECIFIED .
    • Dodatkowe wymagania nałożone przez konfigurację API.

SafetySourceIssue

  • Wymagany unikalny identyfikator String
  • Wymagany tytuł CharSequence
  • Opcjonalne podtytuły CharSequence
  • Wymagane podsumowanie CharSequence
  • Wymagany poziom ważności
  • Opcjonalna kategoria problemu, która musi być jedną z:
    • ISSUE_CATEGORY_DEVICE : Problem dotyczy urządzenia użytkownika.
    • ISSUE_CATEGORY_ACCOUNT : Problem dotyczy kont użytkowników.
    • ISSUE_CATEGORY_GENERAL : Problem wpływa na ogólne bezpieczeństwo użytkownika. To jest ustawienie domyślne.
    • ISSUE_CATEGORY_DATA (począwszy od Androida 14): problem dotyczy danych użytkownika.
    • ISSUE_CATEGORY_PASSWORDS (począwszy od Androida 14): problem dotyczy haseł użytkowników.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (począwszy od Androida 14): Problem wpływa na bezpieczeństwo osobiste użytkownika.
  • Lista elementów Action , które użytkownik może podjąć w związku z tym problemem, przy czym każda instancja Action składa się z:
    • Wymagany unikalny identyfikator String
    • Wymagana etykieta CharSequence
    • Wymagany PendingIntent , aby przekierować użytkownika na inną stronę lub przetworzyć akcję bezpośrednio z ekranu Centrum bezpieczeństwa
    • Opcjonalna wartość logiczna określająca, czy problem można rozwiązać bezpośrednio z ekranu Centrum bezpieczeństwa (wartość domyślna to false )
    • Opcjonalny komunikat o powodzeniu CharSequence , który będzie wyświetlany użytkownikowi po pomyślnym rozwiązaniu problemu bezpośrednio z ekranu Centrum bezpieczeństwa
  • Opcjonalny PendingIntent wywoływany, gdy użytkownik odrzuci problem (domyślnie nic nie jest wywoływane)
  • Wymagany identyfikator typu problemu typu String ; jest on podobny do identyfikatora problemu, ale nie musi być unikalny i służy do rejestrowania
  • Opcjonalny String dla identyfikatora deduplikacji umożliwia opublikowanie tego samego SafetySourceIssue z różnych źródeł i pokazanie go tylko raz w interfejsie użytkownika, zakładając, że mają tę samą deduplicationGroup (począwszy od Androida 14). Jeśli nie określono, problem nigdy nie jest deduplikowany
  • Opcjonalna CharSequence dla tytułu przypisania. Jest to tekst pokazujący, skąd pochodzi karta ostrzegawcza (począwszy od wersji Androida 14). Jeśli nie określono, używany jest tytuł SafetySourcesGroup
  • Opcjonalna możliwość podjęcia działań w przypadku problemu (począwszy od Androida 14), która musi być jedną z:
    • ISSUE_ACTIONABILITY_MANUAL : Użytkownik musi rozwiązać ten problem ręcznie. To jest ustawienie domyślne.
    • ISSUE_ACTIONABILITY_TIP : Ten problem to tylko wskazówka i może nie wymagać żadnej interwencji użytkownika.
    • ISSUE_ACTIONABILITY_AUTOMATIC : Podjęto już działania w tym problemie i może nie być wymagane żadne działanie ze strony użytkownika.
  • Opcjonalne zachowanie powiadomień (począwszy od Androida 14), które musi być jednym z:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED : Centrum Bezpieczeństwa podejmie decyzję, czy konieczne jest powiadomienie w przypadku karty ostrzegawczej. To jest ustawienie domyślne.
    • NOTIFICATION_BEHAVIOR_NEVER : Żadne powiadomienie nie jest publikowane.
    • NOTIFICATION_BEHAVIOR_DELAYED : Powiadomienie jest wysyłane jakiś czas po pierwszym zgłoszeniu problemu.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY : Powiadomienie jest wysyłane natychmiast po zgłoszeniu problemu.
  • Opcjonalne Notification , aby wyświetlić niestandardowe powiadomienie z kartą ostrzegawczą (począwszy od Androida 14). Jeśli nie określono, Notification pochodzi z karty ostrzegawczej. Złożony z:
    • Wymagany tytuł CharSequence
    • Wymagane podsumowanie CharSequence
    • Lista elementów Action , które użytkownik może podjąć w związku z tym powiadomieniem
  • Niezmienniki:
    • Lista instancji Action musi składać się z akcji o unikalnych identyfikatorach
    • Lista instancji Action musi zawierać jeden lub dwa elementy Action . Jeśli wykonalność nie jest ISSUE_ACTIONABILITY_MANUAL , dozwolone jest posiadanie zerowej Action .
    • Intencja OnDismiss PendingIntent nie może otwierać instancji Activity
    • Dodatkowe wymagania nałożone przez konfigurację API

Dane są dostarczane w przypadku określonych zdarzeń do Centrum bezpieczeństwa, dlatego konieczne jest określenie, co spowodowało, że źródło udostępniło SafetySourceData instancję SafetyEvent .

SafetyEvent

  • Wymagany typ, który musi być jednym z:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED : Stan źródła uległ zmianie.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED : Odpowiadanie na sygnał odświeżenia/ponownego skanowania z Centrum bezpieczeństwa; użyj tego zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED dla Centrum bezpieczeństwa, aby móc śledzić żądanie odświeżenia/ponownego skanowania.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED : Rozwiązaliśmy SafetySourceIssue.Action bezpośrednio z ekranu Centrum bezpieczeństwa; użyj tego zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED dla Centrum bezpieczeństwa, aby móc śledzić rozwiązywany problem SafetySourceIssue.Action .
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : Próbowaliśmy rozwiązać SafetySourceIssue.Action bezpośrednio z ekranu Centrum bezpieczeństwa, ale nie udało nam się to zrobić. użyj tego zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED dla Centrum bezpieczeństwa, aby móc śledzić niepowodzenie SafetySourceIssue.Action .
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : Zmienił się język urządzenia, dlatego aktualizujemy tekst podanych danych; dozwolone jest w tym celu użycie SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED .
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED : Udostępniamy te dane w ramach początkowego rozruchu, ponieważ dane Centrum bezpieczeństwa nie są zachowywane po ponownym uruchomieniu; dozwolone jest w tym celu użycie SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED .
  • Opcjonalny identyfikator String dla identyfikatora transmisji odświeżania.
  • Opcjonalny identyfikator String dla instancji SafetySourceIssue , która jest rozwiązywana.
  • Opcjonalny identyfikator String dla rozpoznawanej instancji SafetySourceIssue.Action .
  • Niezmienniki:
    • Należy podać identyfikator transmisji odświeżającej, jeśli typ to SAFETY_EVENT_TYPE_REFRESH_REQUESTED
    • Należy podać identyfikatory problemu i działania, jeśli typ to SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED lub SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED

Poniżej znajduje się przykład tego, jak źródło może dostarczyć dane do Centrum bezpieczeństwa (w tym przypadku jest to wpis z pojedynczą kartą ostrzegawczą):

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

Uzyskaj ostatnie dostarczone dane

Możesz pobrać ostatnie dane przesłane do Centrum bezpieczeństwa dla źródła, którego właścicielem jest Twoja aplikacja. Możesz użyć tej opcji, aby wyświetlić coś we własnym interfejsie użytkownika, sprawdzić, czy dane wymagają aktualizacji przed wykonaniem kosztownej operacji, lub udostępnić tę samą instancję SafetySourceData do Safety Center z pewnymi zmianami lub z nową instancją SafetyEvent . Przydaje się także do testowania.

Użyj tego kodu, aby uzyskać ostatnie dane przekazane do Centrum bezpieczeństwa:

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

Zgłoś błąd

Jeśli nie możesz zebrać danych SafetySourceData , możesz zgłosić błąd do Centrum bezpieczeństwa, które zmieni kolor wpisu na szary, wyczyści dane w pamięci podręcznej i wyświetli komunikat podobny do : Nie można sprawdzić ustawienia . Możesz także zgłosić błąd, jeśli nie uda się rozwiązać instancji SafetySourceIssue.Action . W takim przypadku dane w pamięci podręcznej nie zostaną wyczyszczone, a wpis interfejsu użytkownika nie zostanie zmieniony; ale użytkownikowi zostaje wyświetlony komunikat informujący, że coś poszło nie tak.

Możesz podać błąd za pomocą SafetySourceErrorDetails , który składa się z:

  • SafetySourceErrorDetails : Wymagana instancja 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);

Odpowiedz na żądanie odświeżenia lub ponownego skanowania

Możesz uzyskać sygnał z Centrum bezpieczeństwa w celu dostarczenia nowych danych. Odpowiadanie na żądanie odświeżenia lub ponownego skanowania gwarantuje, że użytkownik wyświetli bieżący stan podczas otwierania Centrum bezpieczeństwa i dotknięcia przycisku skanowania.

Odbywa się to poprzez odebranie transmisji z następującą akcją:

  • ACTION_REFRESH_SAFETY_SOURCES
    • Wartość ciągu: android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • Wywoływane, gdy Centrum bezpieczeństwa wysyła żądanie odświeżenia danych źródła bezpieczeństwa dla danej aplikacji
    • Intencja chroniona, którą może wysłać tylko system
    • Wysyłane do wszystkich źródeł bezpieczeństwa w pliku konfiguracyjnym jako wyraźny zamiar i wymaga pozwolenia SEND_SAFETY_CENTER_UPDATE

W ramach tej transmisji dostępne są następujące dodatki:

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • Wartość ciągu: android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • Typ tablicy ciągów ( String[] ) reprezentuje identyfikatory źródłowe do odświeżenia dla danej aplikacji
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • Wartość ciągu: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Typ całkowity reprezentuje typ żądania @IntDef
    • Musi być jednym z:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA : Żąda od źródła stosunkowo szybkiego dostarczenia danych, zazwyczaj gdy użytkownik otwiera stronę
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA : Żąda od źródła dostarczenia możliwie najświeższych danych, zazwyczaj gdy użytkownik naciśnie przycisk ponownego skanowania
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

    • Wartość ciągu: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
    • Typ ciągu reprezentuje unikalny identyfikator żądanego odświeżenia

Aby uzyskać sygnał z Centrum bezpieczeństwa, zaimplementuj instancję BroadcastReceiver . Transmisja jest wysyłana ze specjalnymi BroadcastOptions , które umożliwiają odbiornikowi uruchomienie usługi na pierwszym planie.

BroadcastReceiver odpowiada na żądanie odświeżenia:

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

Ta sama instancja BroadcastReceiver w powyższym przykładzie jest zadeklarowana w 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>

W idealnym przypadku źródło Safety Center jest zaimplementowane w taki sposób, że wywołuje SafetyCenterManager w przypadku zmiany jego danych. Ze względu na stan systemu zalecamy reagowanie tylko na sygnał ponownego skanowania (gdy użytkownik dotknie przycisku skanowania), a nie wtedy, gdy użytkownik otworzy Centrum bezpieczeństwa. Jeśli ta funkcjonalność jest wymagana, należy ustawić pole refreshOnPageOpenAllowed="true" w pliku konfiguracyjnym, aby źródło mogło w takim przypadku odbierać dostarczaną transmisję.

Odpowiedz w Centrum bezpieczeństwa, jeśli jest włączony lub wyłączony

Możesz zareagować na to, czy Centrum bezpieczeństwa jest włączone, czy wyłączone, korzystając z tej akcji:

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • Wartość ciągu: android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • Wywoływane, gdy Centrum bezpieczeństwa jest włączone lub wyłączone podczas działania urządzenia
    • Nie wywoływane przy starcie (w tym celu użyj ACTION_BOOT_COMPLETED )
    • Intencja chroniona, którą może wysłać tylko system
    • Wysłane do wszystkich źródeł bezpieczeństwa w pliku konfiguracyjnym jako wyraźny zamiar, wymaga pozwolenia SEND_SAFETY_CENTER_UPDATE
    • Wysyłane jako ukryty zamiar wymagający uprawnienia READ_SAFETY_CENTER_STATUS

To zamierzone działanie jest przydatne do włączania lub wyłączania funkcji związanych z Centrum bezpieczeństwa na urządzeniu.

Wdrażaj działania rozwiązujące

Akcja rozwiązująca to instancja SafetySourceIssue.Action , którą użytkownik może rozwiązać bezpośrednio z ekranu Centrum bezpieczeństwa. Użytkownik naciska przycisk akcji i instancja PendingIntent w SafetySourceIssue.Action wysłana przez źródło bezpieczeństwa zostaje wyzwolona, ​​co rozwiązuje problem w tle i powiadamia Centrum bezpieczeństwa, gdy to nastąpi.

Aby zaimplementować działania rozwiązujące, źródło Centrum bezpieczeństwa może skorzystać z usługi, jeśli operacja ma zająć trochę czasu ( PendingIntent.getService ) lub odbiornika rozgłoszeniowego ( PendingIntent.getBroadcast ).

Użyj tego kodu, aby wysłać problem do rozwiązania do Centrum bezpieczeństwa:

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 rozwiązuje akcję:

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

Ta sama instancja BroadcastReceiver w powyższym przykładzie jest zadeklarowana w 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>

Odpowiadaj na zwolnienia

Można określić instancję PendingIntent , która może zostać wyzwolona po odrzuceniu instancji SafetySourceIssue . Centrum bezpieczeństwa zajmuje się zwolnieniami w następujących przypadkach:

  • Jeśli źródło zgłosi problem, użytkownik może go odrzucić na ekranie Centrum bezpieczeństwa, dotykając przycisku odrzucania (przycisk X na karcie ostrzeżenia).
  • Jeśli użytkownik odrzuci problem, jeśli będzie on nadal występował, nie pojawi się on ponownie w interfejsie użytkownika.
  • Trwałe zwolnienia na dysku pozostają podczas ponownego uruchamiania urządzenia.
  • Jeśli źródło Centrum bezpieczeństwa przestanie zgłaszać problem, a następnie zgłosi go ponownie w późniejszym czasie, problem powróci. Ma to na celu umożliwienie sytuacji, w których użytkownik zobaczy ostrzeżenie, odrzuci je, następnie podejmie działania, które powinny złagodzić problem, ale następnie użytkownik ponownie zrobi coś, co powoduje podobny problem. W tym momencie karta ostrzegawcza powinna pojawić się ponownie.
  • Żółte i czerwone kartki ostrzegawcze pojawiają się co 180 dni, chyba że użytkownik wielokrotnie je odrzucił.

Źródło nie powinno potrzebować dodatkowych zachowań, chyba że:

  • Źródło próbuje zaimplementować to zachowanie w inny sposób, na przykład nigdy nie powracać do problemu.
  • Źródło próbuje użyć tego jako wywołania zwrotnego, na przykład do zarejestrowania informacji.

Podaj dane dla wielu użytkowników/profili

Interfejs API SafetyCenterManager może być używany pomiędzy użytkownikami i profilami. Aby uzyskać więcej informacji, zobacz Tworzenie aplikacji obsługujących wielu użytkowników . Obiekt Context udostępniający SafetyCenterManager jest powiązany z instancją UserHandle , więc zwrócona instancja SafetyCenterManager współdziała z Centrum bezpieczeństwa dla tej instancji UserHandle . Domyślnie Context jest powiązany z działającym użytkownikiem, ale możliwe jest utworzenie instancji dla innego użytkownika, jeśli aplikacja posiada uprawnienia INTERACT_ACROSS_USERS i INTERACT_ACROSS_USERS_FULL . Ten przykład pokazuje wykonywanie połączeń między użytkownikami/profilami:

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

Każdy użytkownik na urządzeniu może mieć wiele zarządzanych profili. Centrum Bezpieczeństwa udostępnia różne dane dla każdego użytkownika, ale łączy dane wszystkich zarządzanych profili powiązanych z danym użytkownikiem.

Gdy w pliku konfiguracyjnym jako źródło ustawiono profile="all_profiles" , następuje następująca sytuacja:

  • Istnieje wpis interfejsu użytkownika dla użytkownika (nadrzędnego profilu) i wszystkich powiązanych z nim profili zarządzanych (które korzystają z instancji titleForWork ).
  • Sygnał odświeżenia lub ponownego skanowania jest wysyłany do profilu nadrzędnego i wszystkich powiązanych profili zarządzanych. Powiązany odbiornik jest uruchamiany dla każdego profilu i może dostarczać powiązane dane bezpośrednio do SafetyCenterManager bez konieczności wykonywania połączenia między profilami, chyba że odbiornik lub aplikacja to singleUser .

  • Oczekuje się, że źródło będzie dostarczać dane dla użytkownika i wszystkich zarządzanych przez niego profili. Dane dla każdego wpisu interfejsu użytkownika mogą się różnić w zależności od profilu.

Testowanie

możesz uzyskać dostęp do ShadowSafetyCenterManager i użyć go w teście 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);
}

Możesz napisać więcej testów typu end-to-end (E2E), ale nie jest to objęte zakresem tego przewodnika. Aby uzyskać więcej informacji na temat pisania testów E2E, zobacz Testy CTS (CtsSafetyCenterTestCases)

Testowe i wewnętrzne API

Wewnętrzne interfejsy API i testowe interfejsy API są przeznaczone do użytku wewnętrznego, dlatego nie są szczegółowo opisane w tym przewodniku. Jednak w przyszłości możemy rozszerzyć niektóre wewnętrzne interfejsy API, aby umożliwić producentom OEM tworzenie własnych interfejsów użytkownika, a także zaktualizujemy ten przewodnik, aby zapewnić wskazówki dotyczące ich używania.

Uprawnienia

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Używany w wewnętrznych interfejsach API Centrum bezpieczeństwa
    • Przyznane tylko PermissionController i Shell

Aplikacja Ustawienia

Przekierowanie Centrum bezpieczeństwa

Domyślnie dostęp do Centrum bezpieczeństwa jest możliwy poprzez aplikację Ustawienia z nowym wpisem Bezpieczeństwo i prywatność . Jeśli używasz innej aplikacji Ustawienia lub zmodyfikowałeś aplikację Ustawienia, konieczne może być dostosowanie sposobu dostępu do Centrum bezpieczeństwa.

Gdy Centrum bezpieczeństwa jest włączone:

  • Wpis dotyczący starszej wersji prywatności to ukryty kod
  • Wpis starszej wersji zabezpieczeń to ukryty kod
  • Dodano kod do nowego wpisu Bezpieczeństwo i prywatność
  • Nowy wpis Bezpieczeństwo i prywatność przekierowuje do kodu Centrum bezpieczeństwa
  • działania intencji android.settings.PRIVACY_SETTINGS i android.settings.SECURITY_SETTINGS są przekierowywane do otwarcia Centrum bezpieczeństwa (kod: bezpieczeństwo , prywatność )

Zaawansowane strony bezpieczeństwa i prywatności

Aplikacja Ustawienia zawiera dodatkowe ustawienia w tytułach Więcej ustawień zabezpieczeń i Więcej ustawień prywatności , dostępnych w Centrum bezpieczeństwa:

Źródła bezpieczeństwa

Centrum bezpieczeństwa integruje się z określonym zestawem źródeł bezpieczeństwa udostępnianych przez aplikację Ustawienia:

  • Źródło bezpieczeństwa ekranu blokady sprawdza, czy ekran blokady jest skonfigurowany z hasłem (lub innym zabezpieczeniem), aby mieć pewność, że prywatne informacje użytkownika są chronione przed dostępem z zewnątrz.
  • Źródło bezpieczeństwa biometrycznego (domyślnie ukryte) umożliwia integrację z czujnikiem linii papilarnych lub twarzy.

Kod źródłowy tych źródeł Centrum bezpieczeństwa jest dostępny poprzez wyszukiwanie kodu w systemie Android . Jeśli aplikacja Ustawienia nie została zmodyfikowana (nie wprowadzono zmian w nazwie pakietu, kodzie źródłowym ani kodzie źródłowym obsługującym ekran blokady i dane biometryczne), ta integracja powinna działać od razu po wyjęciu z pudełka. W przeciwnym razie mogą być wymagane pewne modyfikacje, takie jak zmiana pliku konfiguracyjnego w celu zmiany nazwy pakietu aplikacji Ustawienia i źródeł integrujących się z Centrum bezpieczeństwa, a także integracji. Aby uzyskać więcej informacji, zobacz Aktualizacja pliku konfiguracyjnego i ustawień integracji .

Informacje o PendingIntent

Jeśli korzystasz z istniejącej integracji aplikacji Ustawienia z Centrum bezpieczeństwa w systemie Android 14 lub nowszym, błąd opisany poniżej został naprawiony. W tym przypadku czytanie tej sekcji nie jest konieczne.

Jeśli masz pewność, że błąd nie istnieje, ustaw wartość konfiguracji zasobu logicznego XML w aplikacji Ustawienia config_isSafetyCenterLockScreenPendingIntentFixed na true , aby wyłączyć obejście w Centrum bezpieczeństwa.

Obejście oczekujące na intencję

Ten błąd jest spowodowany tym, że Ustawienia korzystają z dodatków instancji Intent w celu określenia, który fragment ma zostać otwarty. Ponieważ Intent#equals nie uwzględnia dodatków instancji Intent , instancja PendingIntent dla ikony menu koła zębatego i wpisu są uznawane za równe i prowadzą do tego samego interfejsu użytkownika (nawet jeśli mają nawigować do innego interfejsu użytkownika). Ten problem został rozwiązany w wersji QPR poprzez rozróżnienie instancji PendingIntent według kodu żądania. Alternatywnie można to rozróżnić, używając Intent#setId .

Wewnętrzne źródła bezpieczeństwa

Niektóre źródła Centrum bezpieczeństwa mają charakter wewnętrzny i są zaimplementowane w aplikacji systemowej PermissionController wewnątrz modułu PermissionController. Źródła te zachowują się jak zwykłe źródła z Centrum bezpieczeństwa i nie są traktowane w żaden sposób. Kod dla tych źródeł jest dostępny poprzez wyszukiwanie kodów Androida .

Są to głównie sygnały dotyczące prywatności, na przykład:

  • Dostępność
  • Automatycznie unieważniaj nieużywane aplikacje
  • Dostęp do lokalizacji
  • Słuchacz powiadomień
  • Informacje o zasadach pracy