Interakcja z Centrum bezpieczeństwa

Przekierowanie do Centrum bezpieczeństwa

Każda aplikacja może otworzyć Centrum bezpieczeństwa za pomocą działania android.content.Intent.ACTION_SAFETY_CENTER (wartość ciągu tekstowego android.intent.action.SAFETY_CENTER).

Aby otworzyć Centrum bezpieczeństwa, zadzwoń z instancji Activity:

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Przekierowanie do konkretnego problemu

Można też przekierowywać użytkowników do konkretnej karty ostrzeżenia w Centrum bezpieczeństwa za pomocą określonych dodatków do intencji. Te dodatkowe funkcje nie są przeznaczone do użytku przez osoby trzecie, dlatego są częścią SafetyCenterManager, która jest częścią @SystemApi. Dostęp do tych funkcji mają tylko aplikacje systemowe.

Elementy dodatkowe intencji, które przekierowują do konkretnej karty ostrzeżenia:

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

W ramach instancji Activity można użyć poniższego fragmentu kodu, aby otworzyć ekran Centrum bezpieczeństwa dla 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);

przekierowanie na konkretną podstronę (od Androida 14),

W Androidzie 14 lub nowszym strona Centrum bezpieczeństwa jest podzielona na kilka podstron, które reprezentują różne SafetySourcesGroup (w Androidzie 13 są one wyświetlane jako elementy z możliwością zwijania).

Za pomocą tego dodatku możesz przekierować użytkowników na konkretną podstronę:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • Wartość ciągu znaków: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • Typ ciąg znaków: określa identyfikator SafetySourcesGroup.
    • Wymagane, aby przekierowanie do podstrony działało.

Ten fragment kodu możesz użyć w instancji Activity, aby otworzyć ekran Centrum bezpieczeństwa na konkretnej podstronie:

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

startActivity(openSafetyCenterIntent);

Korzystanie z interfejsów API źródłowych Centrum bezpieczeństwa

Interfejsy API źródłowe Safety Center są dostępne za pomocą interfejsu SafetyCenterManager (który jest interfejsem @SystemApi). Kod interfejsu API jest dostępny w wyszukiwarce kodu. Kod implementacji interfejsów API jest dostępny w wyszukiwarce kodu.

Uprawnienia

Interfejsy API źródła Centrum bezpieczeństwa są dostępne tylko dla aplikacji systemowych z listy dozwolonych, które mają uprawnienia wymienione poniżej. Więcej informacji znajdziesz w artykule Uprawnienia z poziomu uprawnień.

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Używany do interfejsu API SafetyCenterManager#isSafetyCenterEnabled() (nie jest wymagany w przypadku źródeł Safety Center, które potrzebują tylko uprawnień SEND_SAFETY_CENTER_UPDATE)
    • Używany przez aplikacje systemowe, które sprawdzają, czy Centrum bezpieczeństwa jest włączone
    • przyznawane tylko aplikacjom systemowym z listy dozwolonych;
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Używany do włączonego interfejsu API i interfejsu API źródeł bezpieczeństwa
    • Używane tylko przez źródła bezpieczeństwa
    • przyznawane tylko aplikacjom systemowym z listy dozwolonych;

Te uprawnienia są uprawnieniami uprzywilejowanymi i można je uzyskać tylko przez dodanie ich do odpowiedniego pliku, na przykład pliku com.android.settings.xml aplikacji Ustawienia i pliku AndroidManifest.xml aplikacji. Więcej informacji o modelu uprawnień znajdziesz w artykule protectionLevel.

Pobieranie SafetyCenterManager

SafetyCenterManager to klasa @SystemApi, która jest dostępna w aplikacjach systemowych od Androida 13. Ten wywołanie pokazuje, jak uzyskać obiekt 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;
}

Sprawdzanie, czy Centrum bezpieczeństwa jest włączone

Ta wywołania sprawdza, czy Centrum bezpieczeństwa jest włączone. Wywołanie wymaga uprawnienia READ_SAFETY_CENTER_STATUS lub SEND_SAFETY_CENTER_UPDATE:

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

Przekazywanie danych

Dane źródłowe Centrum bezpieczeństwa z podanym String sourceId są przekazywane do Centrum bezpieczeństwa za pomocą obiektu SafetySourceData, który reprezentuje wpis interfejsu użytkownika i listę problemów (karty z ostrzeżeniem). Element interfejsu i karty ostrzegawcze mogą mieć różne poziomy ważności określone w klasie SafetySourceData:

  • SEVERITY_LEVEL_UNSPECIFIED
    • Nie określono poziomu ważności
    • Kolor: szary lub przezroczysty (w zależności od SafetySourcesGroup pozycji)
    • Służy do danych dynamicznych, które są wyświetlane jako wpisy statyczne w interfejsie lub do wyświetlania nieokreślonego wpisu.
    • Nie można ich używać w przypadku kart z ostrzeżeniem.
  • SEVERITY_LEVEL_INFORMATION
    • podstawowe informacje lub drobne sugestie,
    • Kolor: zielony
  • SEVERITY_LEVEL_RECOMMENDATION
    • zalecenie, aby użytkownik podjął działania w sprawie tego problemu, ponieważ może on stanowić zagrożenie;
    • Kolor: żółty
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • ostrzeżenie o krytycznym problemie, który wymaga od użytkownika podjęcia działań, ponieważ stwarza ono ryzyko;
    • Kolor: czerwony

SafetySourceData

Obiekt SafetySourceData składa się z elementu interfejsu, kart z ostrzeżeniem i invariantów.

  • Opcjonalny przykład SafetySourceStatus (element interfejsu użytkownika)
  • Lista wystąpień (kart) SafetySourceIssue
  • Opcjonalne Bundle dodatki (od wersji 14)
  • Niezmienniki:
    • Lista SafetySourceIssue musi składać się z problemów o unikalnych identyfikatorach.
    • Instancja SafetySourceIssue nie może mieć większego znaczenia niż SafetySourceStatus, jeśli taka istnieje (chyba że SafetySourceStatus to SEVERITY_LEVEL_UNSPECIFIED, w którym przypadku dozwolone są problemy SEVERITY_LEVEL_INFORMATION).
    • Należy spełnić dodatkowe wymagania narzucone przez konfigurację interfejsu API. Jeśli na przykład źródło jest przeznaczone tylko do rozwiązywania problemów, nie może ono udostępniać instancji SafetySourceStatus.

SafetySourceStatus

  • Wymagany CharSequence tytuł
  • Wymagany CharSequencepodsumowanie
  • Wymagany poziom ważności
  • Opcjonalny PendingIntent: instancja przekierowująca użytkownika na odpowiednią stronę (domyślnie używana jest instancja intentAction z konfiguracji, jeśli taka istnieje)
  • Opcjonalnie IconAction (wyświetlany jako ikona obok wpisu) składający się z:
    • Wymagany typ ikony:
      • ICON_TYPE_GEAR: widoczne jako kółko obok wpisu w interfejsie
      • ICON_TYPE_INFO: wyświetlana jako ikona informacji obok wpisu w interfejsie
    • Wymagane PendingIntent do przekierowania użytkownika na inną stronę
  • Opcjonalna wartość logiczna enabled, która umożliwia oznaczenie elementu interfejsu jako wyłączonego, aby nie można było go kliknąć (wartość domyślna to true).
  • Niezmienniki:
    • Instancje PendingIntent muszą otwierać instancję Activity.
    • Jeśli wpis jest wyłączony, musi być oznaczony jako SEVERITY_LEVEL_UNSPECIFIED.
    • dodatkowe wymagania narzucone przez konfigurację interfejsu API;

SafetySourceIssue

  • Wymagany unikalny identyfikator String
  • Wymagany CharSequence tytuł
  • Opcjonalny CharSequence
  • Wymagany CharSequencepodsumowanie
  • Wymagany poziom ważności
  • Opcjonalna kategoria problemu, która musi być jedną z tych kategorii:
    • ISSUE_CATEGORY_DEVICE: problem dotyczy urządzenia użytkownika.
    • ISSUE_CATEGORY_ACCOUNT: problem dotyczy kont użytkownika.
    • ISSUE_CATEGORY_GENERAL: problem dotyczy ogólnego bezpieczeństwa użytkownika. Jest to ustawienie domyślne.
    • ISSUE_CATEGORY_DATA (od Androida 14): Ten problem wpływa na dane użytkownika.
    • ISSUE_CATEGORY_PASSWORDS (Od Androida 14): problem dotyczy haseł użytkownika.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (od wersji Androida 14): problem dotyczy osobistego bezpieczeństwa użytkownika.
  • Lista elementów Action, które użytkownik może wykonać w przypadku tego problemu. Każdy element Action składa się z:
    • Wymagany unikalny identyfikator String
    • Wymagana etykieta CharSequence
    • Wymagane PendingIntent do przekierowania użytkownika na inną stronę lub przetworzenia działania bezpośrednio na ekranie Centrum bezpieczeństwa.
    • Opcjonalna wartość logiczna określająca, czy ten problem można rozwiązać bezpośrednio na ekranie Centrum bezpieczeństwa (wartość domyślna to false).
    • Opcjonalny CharSequence komunikat o pomyślnym rozwiązaniu problemu, który wyświetla się użytkownikowi, gdy problem zostanie rozwiązany bezpośrednio na ekranie Centrum bezpieczeństwa
  • Opcjonalna funkcja PendingIntent, która jest wywoływana, gdy użytkownik zamknie problem (domyślnie nie jest wywoływana żadna funkcja).
  • Wymagany identyfikator typu problemu String; jest podobny do identyfikatora problemu, ale nie musi być unikalny i jest używany do rejestrowania
  • Opcjonalnie String dla identyfikatora deduplikacji. Umożliwia to publikowanie tego samego SafetySourceIssue z różnych źródeł i wyświetlanie go tylko raz w interfejsie użytkownika, o ile ma on ten sam identyfikator deduplicationGroup (od Androida 14). Jeśli nie podasz tej wartości, problem nigdy nie zostanie odduplikowany.
  • Opcjonalnie CharSequence dla tytułu informacji o pochodzeniu. Jest to tekst, który wskazuje, skąd pochodzi karta z ostrzeżeniem (od Androida 14). Jeśli nie określono inaczej, używany jest tytuł SafetySourcesGroup
  • Opcjonalna możliwość działania w przypadku problemu (od Androida 14), która musi być jedną z tych opcji:
    • ISSUE_ACTIONABILITY_MANUAL: użytkownik musi rozwiązać ten problem ręcznie. Jest to ustawienie domyślne.
    • ISSUE_ACTIONABILITY_TIP: ten problem jest tylko wskazówką i nie wymaga podania przez użytkownika żadnych danych.
    • ISSUE_ACTIONABILITY_AUTOMATIC: to zgłoszenie zostało już rozpatrzone i być może nie wymaga żadnych działań ze strony użytkownika.
  • Opcjonalne zachowanie powiadomienia (od Androida 14), które musi być jednym z tych:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED: Centrum bezpieczeństwa zdecyduje, czy powiadomienie jest potrzebne do wyświetlenia karty ostrzegawczej. Jest to ustawienie domyślne.
    • NOTIFICATION_BEHAVIOR_NEVER: nie jest publikowane żadne powiadomienie.
    • NOTIFICATION_BEHAVIOR_DELAYED: powiadomienie jest publikowane po pewnym czasie od zgłoszenia problemu.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY: powiadomienie jest publikowane natychmiast po zgłoszeniu problemu.
  • Opcjonalnie Notification, aby wyświetlić powiadomienie niestandardowe z kartą ostrzegawczą (od Androida 14). Jeśli nie podasz żadnej wartości, Notification zostanie utworzona na podstawie karty z ostrzeżeniem. Skład:
    • Wymagany CharSequence tytuł
    • Wymagany CharSequencepodsumowanie
    • Lista elementów Action, które użytkownik może wykonać w przypadku tego powiadomienia
  • Niezmienniki:
    • Lista instancji Action musi składać się z działań o unikalnych identyfikatorach.
    • Lista instancji Action musi zawierać co najmniej 1 lub 2 elementy Action. Jeśli możliwość działania nie jest ISSUE_ACTIONABILITY_MANUAL, można ustawić wartość Action równą 0.
    • Obsługa OnDismiss PendingIntent nie może otwierać instancji Activity.
    • Dodatkowe wymagania narzucone przez konfigurację interfejsu API

Dane są przekazywane do Centrum Bezpieczeństwa po wystąpieniu określonych zdarzeń, dlatego należy określić, co spowodowało, że źródło przekazało SafetySourceData wystąpienie SafetyEvent.

SafetyEvent

  • Wymagany typ, który musi być jednym z tych typów:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED: stan źródła uległ zmianie.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED: odpowiadanie na sygnał od Centrum bezpieczeństwa dotyczący odświeżenia lub ponownego skanowania; użyj tego polecenia zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED, aby Centrum bezpieczeństwa mogło śledzić prośbę o odświeżenie lub ponowne skanowanie.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED: rozwiązaliśmy problem SafetySourceIssue.Action bezpośrednio na ekranie Centrum bezpieczeństwa. Zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED użyj tej opcji, aby Centrum bezpieczeństwa mogło śledzić rozwiązanie problemu SafetySourceIssue.Action.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED: próbowaliśmy rozwiązać problem SafetySourceIssue.Action bezpośrednio na ekranie Centrum bezpieczeństwa, ale się nie udało. Zamiast opcji SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED użyj opcji SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED, aby Centrum bezpieczeństwa mogło śledzić problem SafetySourceIssue.Action.
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED: język urządzenia uległ zmianie, dlatego aktualizujemy tekst podanych danych. Do tego celu można użyć SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED: te dane są udostępniane podczas uruchamiania urządzenia, ponieważ dane Centrum bezpieczeństwa nie są zachowywane po ponownym uruchomieniu. Do tego celu można użyć SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED.
  • Opcjonalny identyfikator String dla identyfikatora transmisji odświeżania.
  • Opcjonalny identyfikator String instancji SafetySourceIssue, która została rozwiązana.
  • Opcjonalny identyfikator String instancji SafetySourceIssue.Action, która jest rozwiązywana.
  • Niezmienniki:
    • Jeśli typ to SAFETY_EVENT_TYPE_REFRESH_REQUESTED, musisz podać identyfikator transmisji odświeżania.
    • Musisz podać identyfikatory problemu i działania, jeśli ich typ to SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED lub SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED.

Poniżej przedstawiamy przykład tego, jak źródło może przekazywać dane do Centrum bezpieczeństwa (w tym przypadku jest to wpis z jedną 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);

Pobieranie ostatnich danych

Możesz pobrać ostatnie dane przesłane do Centrum Bezpieczeństwa dla źródła należącego do Twojej aplikacji. Możesz to wykorzystać, aby wyświetlić coś w interfejsie, sprawdzić, czy dane wymagają aktualizacji przed wykonaniem kosztownej operacji, lub przesłać do Centrum Bezpieczeństwa tę samą instancję SafetySourceData z niektórymi zmianami lub nową instancję SafetyEvent. Jest też przydatny podczas testowania.

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

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

Zgłaszanie błędu

Jeśli nie możesz zebrać danych SafetySourceData, możesz zgłosić błąd do Centrum bezpieczeństwa. Spowoduje to zaznaczenie wpisu na szaro, wyczyszczenie danych z poziomu pamięci podręcznej i wyświetlenie komunikatu podobnego do Nie udało się sprawdzić ustawień. Możesz też zgłosić błąd, jeśli instancja SafetySourceIssue.Action nie zostanie rozwiązana. W takim przypadku dane w pamięci podręcznej nie zostaną usunięte, a element w interfejsie nie zmieni się, ale użytkownik otrzyma wiadomość z informacją, że coś poszło nie tak.

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

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

Odpowiedź na prośbę o odświeżenie lub ponowne zeskanowanie

Możesz otrzymać sygnał z Centrum bezpieczeństwa, aby podać nowe dane. Odpowiedź na żądanie odświeżenia lub ponownego skanowania zapewnia, że użytkownik zobaczy aktualny stan po otwarciu Centrum bezpieczeństwa i kliknięciu przycisku skanowania.

Aby to zrobić, musisz otrzymać transmisję z tymi działaniami:

  • ACTION_REFRESH_SAFETY_SOURCES
    • Wartość ciągu znaków: android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • Wywoływane, gdy Centrum bezpieczeństwa wysyła żądanie odświeżenia danych źródła bezpieczeństwa w przypadku danej aplikacji.
    • Chroniony zamiar, który może być wysyłany tylko przez system
    • Wysyłane do wszystkich źródeł zabezpieczeń w pliku konfiguracji jako jawne intencje i wymagające uprawnienia SEND_SAFETY_CENTER_UPDATE

W ramach tej transmisji dostępne są te dodatkowe materiały:

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

    • Wartość ciągu znaków:android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Typ liczba całkowita, który reprezentuje typ żądania @IntDef
    • Musi to być jeden z tych elementów:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA: żądanie przesłania danych przez źródło w względnie krótkim czasie, zwykle po otwarciu strony przez użytkownika.
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA: żądanie, aby źródło dostarczyło jak najświeższe dane, zwykle gdy użytkownik naciśnie przycisk ponownego skanowania.
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

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

Aby otrzymać sygnał z Centrum bezpieczeństwa, zaimplementuj instancję BroadcastReceiver. Transmisja jest wysyłana ze specjalnym BroadcastOptions, który umożliwia odbiornikowi uruchomienie usługi na pierwszym planie.

BroadcastReceiver odpowiada na prośbę o odświeżenie:

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

W przykładzie powyżej ta sama instancja BroadcastReceiver jest zadeklarowana w funkcji 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 idealnej sytuacji źródło Centrum bezpieczeństwa jest zaimplementowane w taki sposób, że wywołuje funkcję SafetyCenterManager, gdy zmieniają się jego dane. Ze względu na stabilność systemu zalecamy reagowanie tylko na sygnał ponownego skanowania (gdy użytkownik kliknie przycisk skanowania), a nie na otwarcie Centrum bezpieczeństwa. Jeśli ta funkcja jest wymagana, w źródle należy ustawić pole refreshOnPageOpenAllowed="true" w pliku konfiguracji, aby mogło ono odbierać transmisję w takich przypadkach.

Odpowiedź na Centrum bezpieczeństwa po włączeniu lub wyłączeniu

Możesz odpowiedzieć na to, czy Centrum bezpieczeństwa jest włączone czy wyłączone, używając tej czynności:

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • Wartość ciągu znaków:android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • Wywoływany, gdy Centrum bezpieczeństwa jest włączone lub wyłączone, a urządzenie jest włączone.
    • Nie jest wywoływany podczas uruchamiania (użyj do tego funkcji ACTION_BOOT_COMPLETED).
    • Chroniony zamiar, który może być wysyłany tylko przez system
    • Wysyłane do wszystkich źródeł zabezpieczeń w pliku konfiguracyjnym jako jawne intencje. Wymaga uprawnienia SEND_SAFETY_CENTER_UPDATE
    • Wysłane jako niejawny zamiar, który wymaga uprawnienia READ_SAFETY_CENTER_STATUS

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

Wdrażanie działań naprawczych

Rozwiązywanie to działanie dotyczące SafetySourceIssue.Action, które użytkownik może wykonać bezpośrednio na ekranie Centrum bezpieczeństwa. Użytkownik klika przycisk polecenia, a następnie uruchamia się instancja PendingIntent na SafetySourceIssue.Action przesłana przez źródło bezpieczeństwa. Rozwiązuje ona problem w tle i powiadamia Centrum bezpieczeństwa po zakończeniu działania.

Aby wdrożyć działania rozwiązujące, źródło Centrum bezpieczeństwa może użyć usługi, jeśli operacja ma potrwać pewien czas (PendingIntent.getService), lub odbiornika transmisji (PendingIntent.getBroadcast).

Aby wysłać do Centrum bezpieczeństwa problem, który został rozwiązany, użyj tego kodu:

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

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

W przykładzie powyżej ta sama instancja BroadcastReceiver jest zadeklarowana w funkcji 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>

Odpowiadanie na odrzucenie zgłoszenia

Możesz określić instancję PendingIntent, która może zostać uruchomiona po odrzuceniu instancji SafetySourceIssue. Centrum bezpieczeństwa obsługuje te problemy:

  • Jeśli źródło przesyła problem, użytkownik może go zamknąć na ekranie Centrum bezpieczeństwa, klikając przycisk zamknięcia (przycisk X na karcie ostrzeżenia).
  • Jeśli użytkownik zamknie problem, ale ten nadal występuje, nie będzie on ponownie wyświetlany w interfejsie.
  • Trwałe zamknięcia na dysku pozostają po ponownym uruchomieniu urządzenia.
  • Jeśli źródło w Centrum bezpieczeństwa przestanie przekazywać problem, a potem znowu zacznie, problem powróci. Ma to na celu umożliwienie łagodzenia sytuacji, w której użytkownik widzi ostrzeżenie, odrzuca je, a następnie podejmuje działanie, które powinno rozwiązać problem, ale potem ponownie robi coś, co powoduje podobny problem. W tym momencie karta z ostrzeżeniem powinna się ponownie wyświetlić.
  • Żółte i czerwone karty z ostrzeżeniem pojawiają się co 180 dni, chyba że użytkownik odrzuci je kilka razy.

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

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

Przesyłanie danych wielu użytkowników/profili

Interfejsu SafetyCenterManager API można używać w przypadku różnych użytkowników i profili. Więcej informacji znajdziesz w artykule Tworzenie aplikacji obsługujących wielu użytkowników. Obiekt Context, który udostępnia SafetyCenterManager, jest powiązany z instancją UserHandle, więc zwracana instancja SafetyCenterManager wchodzi w interakcję z Centrum Bezpieczeństwa w przypadku tej instancji UserHandle. Domyślnie Context jest powiązana z bieżącym użytkownikiem, ale można utworzyć instancję dla innego użytkownika, jeśli aplikacja ma uprawnienia INTERACT_ACROSS_USERSINTERACT_ACROSS_USERS_FULL. Ten przykład pokazuje nawiązywanie połączenia przez różnych użytkowników/profile:

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ć kilka profili zarządzanych. Centrum bezpieczeństwa udostępnia różne dane dla każdego użytkownika, ale łączy dane ze wszystkich zarządzanych profili powiązanych z danym użytkownikiem.

Gdy w pliku konfiguracji dla źródła ustawisz wartość profile="all_profiles", nastąpi:

  • W interfejsie użytkownika (nadrzędny profil) i wszystkich powiązanych z nim profili zarządzanych (które korzystają z instancji titleForWork) jest widoczny odpowiedni wpis.
  • Sygnał odświeżania lub ponownego skanowania jest wysyłany do nadrzędnego profilu i wszystkich powiązanych profili zarządzanych. Powiązany odbiornik jest uruchamiany dla każdego profilu i może przekazywać powiązane dane bezpośrednio do SafetyCenterManager bez konieczności wywoływania funkcji na różnych profilach, chyba że odbiornik lub aplikacja to singleUser.

  • Źródło powinno udostępniać dane o użytkowniku i wszystkich zarządzanych przez niego profilach. Dane w poszczególnych elementach interfejsu 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 end-to-end (E2E), ale nie jest to tematem tego przewodnika. Więcej informacji o pisaniu testów E2E znajdziesz w artykule Testy CTS (CtsSafetyCenterTestCases).

Interfejsy API testowe i wewnętrzne

Interfejsy API wewnętrzne i testowe są przeznaczone do użytku wewnętrznego, dlatego nie są szczegółowo opisane w tym przewodniku. W przyszłości możemy jednak udostępnić niektóre wewnętrzne interfejsy API, aby umożliwić producentom urządzeń OEM tworzenie własnych interfejsów użytkownika. W tym celu zaktualizujemy ten przewodnik.

Uprawnienia

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • używane do wewnętrznych interfejsów API Centrum Bezpieczeństwa;
    • Dozwolone tylko w komponencie PermissionController i w powłoce

Aplikacja Ustawienia

Przekierowanie do Centrum bezpieczeństwa

Domyślnie Centrum bezpieczeństwa jest dostępne w aplikacji Ustawienia w nowej sekcji Bezpieczeństwo i prywatność. Jeśli używasz innej aplikacji Ustawienia lub zmodyfikowałeś aplikację Ustawienia, konieczne może być dostosowanie sposobu otwierania Centrum bezpieczeństwa.

Gdy Centrum bezpieczeństwa jest włączone:

  • Starszy wpis Prywatność jest ukryty w pliku kodu.
  • Starszy wpis Bezpieczeństwo jest ukryty kod
  • Dodano nowy wpis Bezpieczeństwo i prywatność code
  • Nowy wpis Bezpieczeństwo i prywatność przekierowuje do kodu Centrum bezpieczeństwa
  • android.settings.PRIVACY_SETTINGSandroid.settings.SECURITY_SETTINGS działania intencyjne są przekierowywane do Centrum bezpieczeństwa (kod: bezpieczeństwo, prywatność)

Zaawansowane strony dotyczące bezpieczeństwa i prywatności

Aplikacja Ustawienia zawiera dodatkowe ustawienia w sekcjach Więcej ustawień zabezpieczeńWięcej ustawień prywatności, które są dostępne 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:

  • Bezpieczeństwo ekranu blokady: źródło weryfikujące, czy ekran blokady jest chroniony kodem dostępu (lub innym zabezpieczeniem), aby prywatne informacje użytkownika były chronione przed dostępem z zewnątrz.
  • Źródło danych biometrycznych (ukryte domyślnie) jest wyświetlane w celu integracji z czujnikiem odcisku palca lub twarzy.

Kod źródłowy tych źródeł Centrum bezpieczeństwa jest dostępny w wyszukiwarce kodu Androida. Jeśli aplikacja Ustawienia nie została zmodyfikowana (nie wprowadzono zmian w nazwie pakietu, kodzie źródłowym lub kodzie źródłowym, który dotyczy ekranu blokady i funkcji biometrycznej), integracja powinna działać od razu po zainstalowaniu. W przeciwnym razie mogą być wymagane pewne modyfikacje, takie jak zmiana pliku konfiguracji w celu zmiany nazwy pakietu aplikacji Ustawienia i źródeł, które integrują się z Centrum bezpieczeństwa, a także integracja. Więcej informacji znajdziesz w pliku konfiguracjiustawieniach integracji.

Informacje o oczekującej intencji

Jeśli korzystasz z obecnej integracji Centrum bezpieczeństwa z aplikacją Ustawienia w Androidzie 14 lub nowszym, błąd opisany poniżej został już naprawiony. W tym przypadku nie musisz czytać tej sekcji.

Gdy będziesz mieć 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.

Rozwiązanie dotyczące PendingIntent

Ten błąd jest spowodowany tym, że Ustawienia używają dodatkowych elementów instancji Intent do określenia, który fragment otworzyć. Ponieważ Intent#equals nie uwzględnia dodatkowych informacji w Intent, instancja PendingIntent dla ikony menu koła zębatego i wejścia są traktowane jako równe i przechodzą do tego samego interfejsu użytkownika (nawet jeśli są przeznaczone do przechodzenia do innego interfejsu). Ten problem został rozwiązany w wersji QPR przez rozróżnienie wystąpień PendingIntent według kodu żądania. Można też odróżnić je za pomocą atrybutu Intent#setId.

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

Niektóre źródła Centrum bezpieczeństwa są wewnętrzne i są wdrażane w aplikacji systemowej PermissionController w ramach modułu PermissionController. Te źródła działają jak zwykłe źródła w Centrum bezpieczeństwa i nie są traktowane w żaden szczególny sposób. Kod tych źródeł jest dostępny w wyszukiwarce kodu na Androida.

Są to głównie sygnały dotyczące prywatności, takie jak:

  • Ułatwienia dostępu
  • Automatyczne odbieranie uprawnień nieużywanym aplikacjom
  • Dostęp do lokalizacji
  • Odbiornik powiadomień
  • Informacje o zasadach służbowych