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 znaków 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żesz też przekierować użytkownika na konkretną kartę ostrzeżenia w Centrum bezpieczeństwa, korzystając z dodatków o konkretnych zamiarach. Te dodatki nie są przeznaczone do użytku przez osoby trzecie, dlatego są częścią usługi SafetyCenterManager, która jest częścią @SystemApi. Dostęp do tych dodatków mają tylko aplikacje systemowe.

Dodatkowe intencje przekierowujące konkretną kartę 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 z ostrzeżeniem
    • Wymagane do działania przekierowania do problemu
  • 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 z ostrzeżeniem
    • Wymagane do działania przekierowania do problemu
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Wartość ciągu znaków: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Typ UserHandle: określa UserHandle na powiązanej karcie ostrzeżenia.
    • Opcjonalne (domyślnie bieżący użytkownik)

Za pomocą poniższego fragmentu kodu z poziomu instancji Activity możesz wyświetlić ekran Centrum bezpieczeństwa w przypadku 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.

Za pomocą poniższego fragmentu kodu z poziomu instancji Activity możesz otworzyć ekran Centrum bezpieczeństwa i konkretną podstronę:

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

startActivity(openSafetyCenterIntent);

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

Źródłowe interfejsy API Centrum bezpieczeństwa są dostępne za pomocą języka SafetyCenterManager (czyli @SystemApi). Kod platformy interfejsu API jest dostępny w Code Search. Kod implementacji interfejsów API jest dostępny w wyszukiwarce kodu.

Uprawnienia

Interfejsy API źródła Safety Center są dostępne tylko dla aplikacji systemowych z listy dozwolonych, które mają uprawnienia wymienione poniżej. Więcej informacji znajdziesz w artykule na temat listy dozwolonych uprawnień z uprawnieniami z podwyższonymi uprawnieniami.

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Używany do interfejsu API SafetyCenterManager#isSafetyCenterEnabled() (nie jest wymagany w przypadku źródeł Centrum bezpieczeństwa, które potrzebują tylko uprawnień SEND_SAFETY_CENTER_UPDATE)
    • Używany przez aplikacje systemowe, które sprawdzają, czy Centrum bezpieczeństwa jest włączone
    • Przyznaje 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żywany tylko przez źródła informacji o bezpieczeństwie
    • 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 rozpoczynających się od Androida 13. To wywołanie pokazuje, jak pobrać 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 {
  // …
}

Podaj dane

Dane źródłowe Centrum bezpieczeństwa z podaną String sourceId są przekazywane do Centrum bezpieczeństwa za pomocą obiektu SafetySourceData, który reprezentuje wpis w interfejsie i listę problemów (kart ostrzeżeń). Wpis w interfejsie 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 wpisu)
    • Służy do danych dynamicznych, które w interfejsie wyglądają jak wpisy statyczne, lub do wyświetlania wpisu nieokreślonego.
    • Nie może być używany w przypadku kart z ostrzeżeniami
  • SEVERITY_LEVEL_INFORMATION
    • Podstawowe informacje lub drobna sugestia
    • 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 bardzo dużym znaczeniu, że użytkownik musi podjąć działania w sprawie tego problemu, ponieważ stwarza on ryzyko;
    • Kolor: czerwony

SafetySourceData

Obiekt SafetySourceData składa się z wpisu w interfejsie, kart ostrzeżeń i zmiennych niezmiennych.

  • Opcjonalna instancja SafetySourceStatus (wpis w interfejsie)
  • Lista wystąpień SafetySourceIssue (karty ostrzegawcze)
  • Opcjonalne Bundle materiały dodatkowe (od 14)
  • Niezmienniki:
    • Lista SafetySourceIssue musi zawierać problemy z unikalnymi identyfikatorami.
    • Jeśli istnieje instancja SafetySourceIssue, nie może ona mieć większego znaczenia niż SafetySourceStatus (chyba że SafetySourceStatus to SEVERITY_LEVEL_UNSPECIFIED, w którym przypadku dozwolone są problemy SEVERITY_LEVEL_INFORMATION).
    • Muszą być spełnione dodatkowe wymagania nałożone przez konfigurację interfejsu API, np. jeśli źródło służy tylko do problemów, nie może 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 – jeden z tych typów:
      • ICON_TYPE_GEAR: ikona koła zębatego widoczna obok pozycji w interfejsie.
      • ICON_TYPE_INFO: wyświetlana jako ikona informacji obok wpisu w interfejsie.
    • Wymagany parametr PendingIntent do przekierowania użytkownika na inną stronę
  • Opcjonalna wartość logiczna enabled, która umożliwia oznaczenie wpisu w interfejsie jako wyłączonego, aby nie można go było kliknąć (domyślnie true)
  • Niezmienniki:
    • Instancje PendingIntent muszą otworzyć 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 podtytuł CharSequence
  • Wymagany CharSequencepodsumowanie
  • Wymagany poziom ważności
  • Opcjonalna kategoria problemu, którą musi być:
    • ISSUE_CATEGORY_DEVICE: problem dotyczy urządzenia użytkownika.
    • ISSUE_CATEGORY_ACCOUNT: problem dotyczy kont użytkownika.
    • ISSUE_CATEGORY_GENERAL: problem wpływa na ogólne bezpieczeństwo użytkownika. Jest to ustawienie domyślne.
    • ISSUE_CATEGORY_DATA (od Androida 14): Ten problem dotyczy danych użytkownika.
    • ISSUE_CATEGORY_PASSWORDS (począwszy od Androida 14): problem wpływa na hasła użytkowników.
    • 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 w celu przekierowania użytkownika na inną stronę lub przetworzenia działania bezpośrednio z ekranu Centrum bezpieczeństwa
    • Opcjonalna wartość logiczna, która określa, czy problem można rozwiązać bezpośrednio na ekranie SafetyCenter (domyślnie jest to false)
    • Opcjonalny komunikat o powodzeniu CharSequence wyświetlany użytkownikowi po rozwiązaniu problemu bezpośrednio na ekranie Centrum bezpieczeństwa
  • Opcjonalny algorytm PendingIntent wywoływany po zamknięciu problemu przez użytkownika (domyślnie jest to puste pole)
  • Wymagany identyfikator typu problemu String. Jest podobny do identyfikatora problemu, ale nie musi być unikalny i służy do logowania
  • Opcjonalny String w przypadku identyfikatora deduplikacji pozwala na publikowanie tego samego elementu SafetySourceIssue z różnych źródeł i wyświetlanie go tylko raz w interfejsie, zakładając, że mają ten sam identyfikator deduplicationGroup (od Androida 14). Jeśli nie podasz tych informacji, duplikaty problemów nie będą usuwane
  • Opcjonalny CharSequence w tytule atrybucji. Ten tekst pokazuje, skąd pochodzi karta z ostrzeżeniem (od Androida 14). Jeśli nie podasz nazwy, zostanie użyty 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: to tylko wskazówka, a użytkownik może nie wymagać żadnych danych od użytkownika.
    • ISSUE_ACTIONABILITY_AUTOMATIC: problem został już rozwiązany, więc użytkownik może nie wymagać żadnych danych od użytkownika.
  • Opcjonalne zachowanie powiadomień (od Androida 14), które musi być jedną z tych opcji:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED: Centrum bezpieczeństwa zdecyduje, czy wymagane jest powiadomienie z karty ostrzeżenia. Jest to ustawienie domyślne.
    • NOTIFICATION_BEHAVIOR_NEVER: brak opublikowanych powiadomień.
    • NOTIFICATION_BEHAVIOR_DELAYED: jakiś czas po zgłoszeniu problemu zostanie wysłane powiadomienie.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY: powiadomienie zostanie opublikowane od razu 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 tytuł (CharSequence)
    • Wymagane podsumowanie: CharSequence
    • Lista elementów Action, które użytkownik może wykonać w przypadku tego powiadomienia
  • Niezmienniki:
    • Lista instancji Action musi zawierać działania o unikalnych identyfikatorach
    • Lista instancji Action musi zawierać 1 lub 2 elementy Action. Jeśli możliwość działania nie jest ISSUE_ACTIONABILITY_MANUAL, można ustawić wartość Action równą 0.
    • Element PendingIntent OnClose nie może otwierać instancji Activity
    • Dodatkowe wymagania narzucone przez konfigurację interfejsu API

Dane są przekazywane do Centrum Bezpieczeństwa w przypadku określonych zdarzeń, dlatego musisz określić, co spowodowało, że źródło przekazało SafetySourceData instancję 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. Użyj tej opcji zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED, 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 nie udało nam się to zrobić. Użyj tej opcji zamiast SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED, aby móc śledzić błąd SafetySourceIssue.Action.
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED: język urządzenia zmienił się, dlatego aktualizujemy tekst podanych danych. Dozwolone jest użycie do tego celu SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED: Udostępniamy te dane w ramach początkowego uruchamiania, ponieważ dane z Centrum bezpieczeństwa nie są zachowywane po ponownym uruchomieniu. Można do tego wykorzystać 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 ma zostać rozwiązana.
  • Niezmienniki:
    • Jeśli typ to SAFETY_EVENT_TYPE_REFRESH_REQUESTED, należy 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 użyć tych danych, 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 to też przydatne podczas testowania.

Użyj tego kodu, aby uzyskać ostatnie dane przekazane 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 Safety Center. 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ą parametru 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 skanowanie

Możesz otrzymać sygnał z Centrum bezpieczeństwa, aby podać nowe dane. W odpowiedzi na prośbę o odświeżenie lub ponowne przeskanowanie użytkownik ma pewność, że po otwarciu Centrum bezpieczeństwa i kliknięciu przycisku skanowania użytkownik widzi bieżący stan.

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 dla 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 funkcje:

  • 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, reprezentuje typ żądania @IntDef
    • Musi to być jeden z tych elementów:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA: prosi źródło o względnie szybkie dostarczanie danych, zwykle gdy użytkownik otwiera stronę.
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA: prosi źródło o jak najświeższe dane – zwykle wtedy, 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 ciąg znaków, który reprezentuje unikalny identyfikator żądanego odświeżenia.

Aby otrzymywać sygnał z Centrum bezpieczeństwa, zaimplementuj instancję BroadcastReceiver. Transmisja jest wysyłana za pomocą specjalnego 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 stan systemu zalecamy odpowiadanie 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 pliku konfiguracji musisz ustawić pole refreshOnPageOpenAllowed="true", aby źródło mogło odbierać transmisję w takich przypadkach.

Reagowanie w 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ływane, gdy Centrum bezpieczeństwa jest włączone lub wyłączone, gdy urządzenie jest uruchomione
    • Funkcja nie jest wywoływana podczas uruchamiania (do tego użyj 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
    • Wysyłana jako intencja niejawna, która 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.

Wdrożenie działań umożliwiających rozwiązanie problemu

Działaniem rozwiązania jest instancja SafetySourceIssue.Action, którą użytkownik może rozwiązać bezpośrednio na ekranie Centrum bezpieczeństwa. Użytkownik klika przycisk polecenia i uruchamia wystąpienie PendingIntent na SafetySourceIssue.Action wysłane przez źródło zabezpieczeń, które rozwiązuje problem w tle i powiadamia Centrum bezpieczeństwa po zakończeniu.

Aby wdrożyć działania związane z rozwiązywaniem problemu, źródło w Centrum bezpieczeństwa może użyć usługi, która ma zająć trochę czasu (PendingIntent.getService) lub odbiornika (PendingIntent.getBroadcast).

Użyj tego kodu, aby przesłać rozwiązanie problemu 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 kończy działanie:

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

To samo wystąpienie BroadcastReceiver w przykładzie powyżej jest zadeklarowane 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>

Odpowiadanie na odrzucenie problemów

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.
  • Podczas ponownego uruchamiania urządzenia trwałe zamknięcia dysku pozostają na dysku.
  • Jeśli źródło w Centrum Bezpieczeństwa przestanie przekazywać problem, a potem znowu zacznie, problem powróci. Ma to na celu dopuszczenie sytuacji, w których użytkownik zobaczy ostrzeżenie i zamknie je, a następnie podejmie działanie, które powinno złagodzić problem, a potem użytkownik wykona ponownie działanie, które wywołuje podobny problem. W tym momencie karta z ostrzeżeniem powinna wyświetlić się ponownie.
  • Żółte i czerwone karty ostrzegawcze powracają co 180 dni, chyba że użytkownik zamknie je kilka razy.

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

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

Podaj dane wielu użytkowników/profili

Interfejsu SafetyCenterManager API można używać na różnych kontach użytkowników i profilach. Więcej informacji znajdziesz w artykule Tworzenie aplikacji obsługujących wielu użytkowników. Obiekt Context udostępniający SafetyCenterManager jest powiązany z instancją UserHandle, dlatego zwrócona instancja SafetyCenterManager wchodzi w interakcję z Centrum bezpieczeństwa tej instancji UserHandle. Domyślnie interfejs Context jest powiązany z uruchomionym użytkownikiem, ale jeśli aplikacja ma uprawnienia INTERACT_ACROSS_USERS i INTERACT_ACROSS_USERS_FULL, można utworzyć instancję dla innego użytkownika. Ten przykład pokazuje wykonywanie połączenia z różnymi 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 profili zarządzanych. Centrum bezpieczeństwa dostarcza innych danych każdego użytkownika, ale łączy dane wszystkich zarządzanych profili powiązanych z konkretnym użytkownikiem.

Gdy ustawisz profile="all_profiles" dla źródła w pliku konfiguracji:

  • Istnieje wpis UIentry dla użytkownika (elementu nadrzędnego profilu) i wszystkich powiązanych z nim profili zarządzanych (które korzystają z titleForWork instancji).
  • Sygnał odświeżania lub ponownego skanowania jest wysyłany do elementu nadrzędnego i wszystkich powiązanych z nim 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 jestsingleUser.

  • Źródło powinno dostarczać dane użytkownika i wszystkich jego profili zarządzanych. Dane w poszczególnych elementach interfejsu mogą się różnić w zależności od profilu.

Testowanie

możesz uzyskać dostęp do usługi ShadowSafetyCenterManager i użyć jej 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 rozszerzyć część wewnętrznych interfejsów API, aby umożliwić producentom OEM tworzenie własnych interfejsów API. Zaktualizujemy ten przewodnik, by podać wskazówki na temat tego, jak z nich korzystać.

Uprawnienia

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Używany 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:

  • Stary wpis Prywatność jest ukryty kod
  • Starszy wpis Bezpieczeństwo jest ukryty kod
  • Dodany nowy wpis Bezpieczeństwo i prywatność: kod
  • Nowy wpis Prywatność i bezpieczeństwo 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 dostępne w Centrum bezpieczeństwa w sekcjach Więcej ustawień bezpieczeństwa i Więcej ustawień prywatności:

Źródła bezpieczeństwa

Centrum bezpieczeństwa integruje się z określonym zestawem źródeł bezpieczeństwa dostępnych w aplikacji Ustawienia:

  • Źródło zabezpieczeń ekranu blokady sprawdza, czy na ekranie blokady ustawiono kod dostępu (lub inne zabezpieczenia), i zapewnia, że prywatne informacje użytkownika są chronione przed dostępem z zewnątrz.
  • Źródło bezpieczeństwa biometrycznego (ukryte domyślnie) jest wyświetlane w celu integracji z czujnikiem odcisków palców 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 ani 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ł zintegrowanych z Centrum bezpieczeństwa, a także integracji. Więcej informacji znajdziesz w pliku konfiguracjiustawieniach integracji.

Informacje o intencji PendingIntent

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

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

Obejście intencji PendingIntent

Ten błąd jest spowodowany tym, że ustawienia używające dodatków do instancji Intent w celu określenia, który fragment należy otworzyć. Funkcja Intent#equals nie uwzględnia wystąpienia Intent, dlatego wystąpienie PendingIntent ikony menu z kołem zębatym i wpisy są uznawane za równe i przechodzą do tego samego interfejsu użytkownika (chociaż ich przeznaczeniem jest przechodzenie do innego interfejsu). Ten problem rozwiązuje się w wersji QPR przez rozróżnienie instancji 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 zaimplementowane w aplikacji systemowej PermissionController w module PermissionController. Te źródła zachowują się jak zwykłe źródła w Centrum bezpieczeństwa i nie są traktowane w żaden specjalny sposób. Kod dla tych źródeł jest dostępny w wyszukiwarce kodu dla Androida.

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

  • Ułatwienia dostępu
  • Automatycznie unieważnij nieużywane aplikacje
  • Dostęp do lokalizacji
  • Odbiornik powiadomień
  • Informacje o zasadach służbowych