Interagisci con il Centro sicurezza

Reindirizzamento al Centro sicurezza

Qualsiasi app può aprire Safety Center utilizzando l'azione android.content.Intent.ACTION_SAFETY_CENTER (valore stringa android.intent.action.SAFETY_CENTER ).

Per aprire Safety Center, effettua una chiamata dall'interno di un'istanza Activity :

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Reindirizzamento a un problema specifico

È anche possibile reindirizzare a una specifica scheda di avviso di Safety Center utilizzando specifici extra per intenti. Questi extra non sono destinati a essere utilizzati da terze parti, quindi fanno parte di SafetyCenterManager , che fa parte di @SystemApi . Solo le app di sistema possono accedere a questi extra.

Extra di intenti che reindirizzano una specifica scheda di avviso:

  • EXTRA_SAFETY_SOURCE_ID
    • Valore stringa: android.safetycenter.extra.SAFETY_SOURCE_ID
    • Tipo stringa: specifica l'ID della fonte di sicurezza della scheda di avvertenza associata
    • Necessario affinché il reindirizzamento al problema funzioni
  • EXTRA_SAFETY_SOURCE_ISSUE_ID
    • Valore stringa: android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
    • Tipo di stringa: specifica l'ID della scheda di avviso
    • Necessario affinché il reindirizzamento al problema funzioni
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Valore stringa: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Tipo UserHandle : specifica UserHandle per la scheda di avviso associata
    • Facoltativo (l'impostazione predefinita è l'utente corrente)

Lo snippet di codice riportato di seguito può essere utilizzato dall'interno di un'istanza Activity per aprire la schermata del Centro sicurezza su un problema specifico:

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

Reindirizzamento a una pagina secondaria specifica (a partire da Android 14)

In Android 14 o versioni successive, la pagina Safety Center è suddivisa in più sottopagine che rappresentano i diversi SafetySourcesGroup (in Android 13, questo viene visualizzato come voci comprimibili).

È possibile reindirizzare a una sottopagina specifica utilizzando questo intento extra:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • Valore stringa: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • Tipo di stringa: specifica l'ID di SafetySourcesGroup
    • Necessario affinché il reindirizzamento alla sottopagina funzioni

Lo snippet di codice riportato di seguito può essere utilizzato dall'interno di un'istanza Activity per aprire la schermata del Centro sicurezza su una pagina secondaria specifica:

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

startActivity(openSafetyCenterIntent);

Utilizza le API di origine del Centro sicurezza

Le API di origine di Safety Center sono disponibili utilizzando SafetyCenterManager (che è un @SystemApi ). Il codice per la superficie API è disponibile in Ricerca codice . Il codice di implementazione delle API è disponibile in Ricerca codice .

Autorizzazioni

Le API di origine del Centro sicurezza sono accessibili solo dalle app di sistema autorizzate utilizzando le autorizzazioni elencate di seguito. Per ulteriori informazioni, consulta Elenco consentito delle autorizzazioni privilegiate .

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Utilizzato per l'API SafetyCenterManager#isSafetyCenterEnabled() (non necessario per le origini Safety Center, richiedono solo l'autorizzazione SEND_SAFETY_CENTER_UPDATE )
    • Utilizzato dalle app di sistema che controllano se il Centro sicurezza è abilitato
    • Concesso solo alle app di sistema incluse nella lista consentita
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Utilizzato per l'API abilitata e l'API Safety Sources
    • Utilizzato solo da fonti di sicurezza
    • Concesso solo alle app di sistema incluse nella lista consentita

Queste autorizzazioni sono privilegiate e puoi acquisirle solo aggiungendole al file pertinente, ad esempio il file com.android.settings.xml per l'app Impostazioni e al file AndroidManifest.xml dell'app. Vedi protectionLevel per ulteriori informazioni sul modello di autorizzazione.

Ottieni SafetyCenterManager

SafetyCenterManager è una classe @SystemApi accessibile dalle app di sistema a partire da Android 13. Questa chiamata mostra come ottenere 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;
}

Controlla se il Centro sicurezza è abilitato

Questa chiamata controlla se Safety Center è abilitato. La chiamata richiede l'autorizzazione READ_SAFETY_CENTER_STATUS o SEND_SAFETY_CENTER_UPDATE :

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

Fornire dati

I dati di origine di Safety Center con la String sourceId specificata vengono forniti a Safety Center con l'oggetto SafetySourceData , che rappresenta una voce dell'interfaccia utente e un elenco di problemi (schede di avviso). La voce dell'interfaccia utente e le schede di avvertenza possono avere diversi livelli di gravità specificati nella classe SafetySourceData :

  • SEVERITY_LEVEL_UNSPECIFIED
    • Nessuna gravità specificata
    • Colore: grigio o trasparente (a seconda del SafetySourcesGroup della voce)
    • Utilizzato per dati dinamici che si presentano come una voce statica nell'interfaccia utente o per mostrare una voce non specificata
    • Non deve essere utilizzato per le carte di avvertimento
  • SEVERITY_LEVEL_INFORMATION
    • Informazioni di base o suggerimenti minori
    • Colore: verde
  • SEVERITY_LEVEL_RECOMMENDATION
    • Raccomandazione che l'utente intervenga in merito a questo problema, poiché potrebbe metterlo a rischio
    • Colore: giallo
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • Avvertimento critico che invita l'utente a prendere provvedimenti in merito a questo problema, poiché presenta un rischio
    • Colore rosso

SafetySourceData

L'oggetto SafetySourceData è composto da una voce dell'interfaccia utente, schede di avviso e invarianti.

  • Istanza SafetySourceStatus opzionale (voce dell'interfaccia utente)
  • Elenco delle istanze SafetySourceIssue (schede di avvertenza)
  • Extra Bundle opzionale (a partire da 14)
  • Invarianti:
    • L'elenco SafetySourceIssue deve essere composto da problemi con identificatori univoci.
    • L'istanza SafetySourceIssue non deve essere di maggiore importanza rispetto a SafetySourceStatus se presente (a meno che SafetySourceStatus non sia SEVERITY_LEVEL_UNSPECIFIED , nel qual caso sono consentiti problemi SEVERITY_LEVEL_INFORMATION ).
    • È necessario soddisfare ulteriori requisiti imposti dalla configurazione API, ad esempio, se l'origine è solo problema, non deve fornire un'istanza SafetySourceStatus .

SafetySourceStatus

  • Titolo CharSequence obbligatorio
  • Riepilogo CharSequence obbligatorio
  • Livello di gravità richiesto
  • Istanza PendingIntent opzionale per reindirizzare l'utente alla pagina giusta (l'impostazione predefinita utilizza intentAction dalla configurazione, se presente)
  • IconAction opzionale (mostrata come icona laterale sulla voce) composta da:
    • Tipo di icona obbligatorio, che deve essere uno dei seguenti tipi:
      • ICON_TYPE_GEAR : mostrato come un ingranaggio accanto alla voce dell'interfaccia utente
      • ICON_TYPE_INFO : mostrato come icona di informazioni accanto alla voce dell'interfaccia utente
    • Obbligatorio PendingIntent per reindirizzare l'utente a un'altra pagina
  • Valore booleano enabled facoltativo che consente di contrassegnare la voce dell'interfaccia utente come disabilitata, quindi non è selezionabile (l'impostazione predefinita è true )
  • Invarianti:
    • Le istanze PendingIntent devono aprire un'istanza Activity .
    • Se la voce è disabilitata, deve essere designata SEVERITY_LEVEL_UNSPECIFIED .
    • Requisiti aggiuntivi imposti dalla configurazione API.

SafetySourceIssue

  • Identificatore String univoco obbligatorio
  • Titolo CharSequence obbligatorio
  • Sottotitolo CharSequence opzionale
  • Riepilogo CharSequence obbligatorio
  • Livello di gravità richiesto
  • Categoria di problema facoltativa, che deve essere una delle seguenti:
    • ISSUE_CATEGORY_DEVICE : il problema riguarda il dispositivo dell'utente.
    • ISSUE_CATEGORY_ACCOUNT : il problema riguarda gli account dell'utente.
    • ISSUE_CATEGORY_GENERAL : il problema influisce sulla sicurezza generale dell'utente. Questa è l'impostazione predefinita.
    • ISSUE_CATEGORY_DATA (a partire da Android 14): il problema riguarda i dati dell'utente.
    • ISSUE_CATEGORY_PASSWORDS (a partire da Android 14): il problema riguarda le password dell'utente.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (a partire da Android 14): il problema influisce sulla sicurezza personale dell'utente.
  • Elenco di elementi Action che l'utente può intraprendere per questo problema, ciascuna istanza Action è composta da:
    • Identificatore String univoco obbligatorio
    • Etichetta CharSequence obbligatoria
    • Obbligatorio PendingIntent per reindirizzare l'utente a un'altra pagina o elaborare l'azione direttamente dalla schermata Safety Center
    • Valore booleano facoltativo per specificare se questo problema può essere risolto direttamente dalla schermata Safety Center (l'impostazione predefinita è false )
    • Messaggio di successo CharSequence facoltativo, da visualizzare all'utente quando il problema viene risolto correttamente direttamente dalla schermata Safety Center
  • PendingIntent facoltativo che viene chiamato quando l'utente ignora il problema (per impostazione predefinita non viene chiamato nulla)
  • Obbligatorio Identificatore del tipo di problema String ; questo è simile all'identificatore del problema ma non deve essere univoco e viene utilizzato per la registrazione
  • String facoltativa per l'ID di deduplicazione, consente di pubblicare lo stesso SafetySourceIssue da fonti diverse e di mostrarlo solo una volta nell'interfaccia utente presupponendo che abbiano lo stesso deduplicationGroup (a partire da Android 14). Se non specificato, il problema non viene mai deduplicato
  • CharSequence facoltativa per il titolo di attribuzione, si tratta di un testo che mostra l'origine della scheda di avviso (a partire da Android 14). Se non specificato utilizza il titolo di SafetySourcesGroup
  • Azione facoltativa per il problema (a partire da Android 14), che deve essere uno dei seguenti:
    • ISSUE_ACTIONABILITY_MANUAL : l'utente deve risolvere questo problema manualmente. Questa è l'impostazione predefinita.
    • ISSUE_ACTIONABILITY_TIP : questo problema è solo un suggerimento e potrebbe non richiedere alcun input da parte dell'utente.
    • ISSUE_ACTIONABILITY_AUTOMATIC : questo problema è già stato risolto e potrebbe non richiedere alcun input da parte dell'utente.
  • Comportamento di notifica facoltativo (a partire da Android 14), che deve essere uno dei seguenti:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED : Safety Center deciderà se è necessaria una notifica per la scheda di avvertenza. Questa è l'impostazione predefinita.
    • NOTIFICATION_BEHAVIOR_NEVER : nessuna notifica pubblicata.
    • NOTIFICATION_BEHAVIOR_DELAYED : viene pubblicata una notifica qualche tempo dopo la prima segnalazione del problema.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY : viene pubblicata una notifica non appena viene segnalato il problema.
  • Notification opzionale, per mostrare una notifica personalizzata con la scheda di avviso (a partire da Android 14). Se non specificato, la Notification è derivata dalla scheda di avvertimento. Composto da:
    • Titolo CharSequence obbligatorio
    • Riepilogo CharSequence obbligatorio
    • Elenco di elementi Action che l'utente può intraprendere per questa notifica
  • Invarianti:
    • L'elenco delle istanze Action deve essere composto da azioni con identificatori univoci
    • L'elenco delle istanze Action deve contenere uno o due elementi Action . Se l'azione non è ISSUE_ACTIONABILITY_MANUAL , è consentita l'assenza Action .
    • OnDismiss PendingIntent non deve aprire un'istanza Activity
    • Requisiti aggiuntivi imposti dalla configurazione API

I dati vengono forniti al Safety Center in seguito a determinati eventi, quindi è necessario specificare cosa ha causato la fornitura da parte dell'origine a SafetySourceData di un'istanza SafetyEvent .

SafetyEvent

  • Tipo obbligatorio, che deve essere uno tra:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED : lo stato della fonte è cambiato.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED : risposta a un segnale di aggiornamento/nuova scansione da Safety Center; utilizzare questo invece di SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED per Safety Center per poter monitorare la richiesta di aggiornamento/nuova scansione.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED : abbiamo risolto SafetySourceIssue.Action direttamente dalla schermata Safety Center; utilizzare questo invece di SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED per Safety Center per poter tenere traccia del SafetySourceIssue.Action in fase di risoluzione.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : abbiamo tentato di risolvere SafetySourceIssue.Action direttamente dalla schermata Safety Center, ma non siamo riusciti a farlo; utilizzare questo invece di SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED per Safety Center per poter monitorare SafetySourceIssue.Action in caso di errore.
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : la lingua del dispositivo è cambiata, quindi aggiorniamo il testo dei dati forniti; è consentito utilizzare SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED per questo.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED : forniamo questi dati come parte di un avvio iniziale poiché i dati di Safety Center non vengono mantenuti dopo i riavvii; è consentito utilizzare SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED per questo.
  • Identificatore String facoltativo per l'ID di trasmissione di aggiornamento.
  • Identificatore String facoltativo per l'istanza SafetySourceIssue in fase di risoluzione.
  • Identificatore String facoltativo per l'istanza SafetySourceIssue.Action in fase di risoluzione.
  • Invarianti:
    • È necessario fornire l'ID broadcast di aggiornamento se il tipo è SAFETY_EVENT_TYPE_REFRESH_REQUESTED
    • È necessario fornire gli ID del problema e dell'azione se il tipo è SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED o SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED

Di seguito è riportato un esempio di come una fonte potrebbe fornire dati a Safety Center (in questo caso fornisce una voce con un'unica scheda di avviso):

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

Ottieni gli ultimi dati forniti

Puoi ottenere gli ultimi dati forniti al Centro sicurezza per un'origine di proprietà della tua app. Puoi usarlo per far emergere qualcosa nella tua interfaccia utente, per verificare se i dati devono essere aggiornati prima di eseguire un'operazione costosa o per fornire la stessa istanza SafetySourceData a Safety Center con alcune modifiche o con una nuova istanza SafetyEvent . È utile anche per fare delle prove.

Utilizza questo codice per ottenere gli ultimi dati forniti a Safety Center:

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

Segnala un errore

Se non riesci a raccogliere i dati SafetySourceData , puoi segnalare l'errore a Safety Center, che modifica la voce in grigio, cancella i dati memorizzati nella cache e fornisce un messaggio simile a Impossibile controllare l'impostazione . Puoi anche segnalare un errore se un'istanza di SafetySourceIssue.Action non viene risolta, nel qual caso i dati memorizzati nella cache non vengono cancellati e la voce dell'interfaccia utente non viene modificata; ma viene visualizzato un messaggio all'utente per informarlo che qualcosa è andato storto.

Puoi fornire l'errore utilizzando SafetySourceErrorDetails , che è composto da:

  • SafetySourceErrorDetails : istanza SafetyEvent obbligatoria :
// 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);

Rispondere a una richiesta di aggiornamento o nuova scansione

Puoi ricevere un segnale dal Centro sicurezza per fornire nuovi dati. La risposta a una richiesta di aggiornamento o nuova scansione garantisce che l'utente visualizzi lo stato corrente quando apre Safety Center e quando tocca il pulsante di scansione.

Questo viene fatto ricevendo una trasmissione con la seguente azione:

  • ACTION_REFRESH_SAFETY_SOURCES
    • Valore stringa: android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • Attivato quando Safety Center invia una richiesta di aggiornamento dei dati dell'origine di sicurezza per una determinata app
    • Intento protetto che può essere inviato solo dal sistema
    • Inviato a tutte le origini di sicurezza nel file di configurazione come intento esplicito e richiede l'autorizzazione SEND_SAFETY_CENTER_UPDATE

I seguenti extra sono forniti come parte di questa trasmissione:

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • Valore stringa: android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • Il tipo di array di stringhe ( String[] ) rappresenta gli ID di origine da aggiornare per l'app specificata
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • Valore stringa: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Tipo intero, rappresenta un tipo di richiesta @IntDef
    • Deve essere uno di:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA : richiede all'origine di fornire dati in modo relativamente veloce, in genere quando l'utente apre la pagina
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA : richiede all'origine di fornire dati quanto più aggiornati possibile, in genere quando l'utente preme il pulsante di nuova scansione
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

    • Valore stringa: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
    • Tipo stringa, rappresenta un identificatore univoco per l'aggiornamento richiesto

Per ottenere un segnale dal Safety Center, implementa un'istanza BroadcastReceiver . La trasmissione viene inviata con speciali BroadcastOptions che consentono al ricevitore di avviare un servizio in primo piano.

BroadcastReceiver risponde a una richiesta di aggiornamento:

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

La stessa istanza di BroadcastReceiver nell'esempio precedente è dichiarata in 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>

Idealmente, un'origine Safety Center viene implementata in modo tale da richiamare SafetyCenterManager quando i relativi dati cambiano. Per motivi di integrità del sistema, consigliamo di rispondere solo al segnale di nuova scansione (quando l'utente tocca il pulsante di scansione) e non quando l'utente apre il Centro sicurezza. Se questa funzionalità è richiesta, il campo refreshOnPageOpenAllowed="true" nel file di configurazione deve essere impostato affinché l'origine riceva la trasmissione trasmessa in questi casi.

Rispondi al Centro sicurezza quando abilitato o disabilitato

Puoi rispondere a quando il Centro sicurezza è abilitato o disabilitato utilizzando questa azione di intento:

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • Valore stringa: android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • Si attiva quando Safety Center è abilitato o disabilitato mentre il dispositivo è in esecuzione
    • Non richiamato all'avvio (utilizza ACTION_BOOT_COMPLETED per questo)
    • Intento protetto che può essere inviato solo dal sistema
    • Inviato a tutte le origini di sicurezza nel file di configurazione come intento esplicito, richiede l'autorizzazione SEND_SAFETY_CENTER_UPDATE
    • Inviato come intento implicito che richiede l'autorizzazione READ_SAFETY_CENTER_STATUS

Questa azione intent è utile per abilitare o disabilitare le funzionalità correlate a Safety Center sul dispositivo.

Implementare azioni risolutive

Un'azione di risoluzione è un'istanza SafetySourceIssue.Action che un utente può risolvere direttamente dalla schermata Safety Center. L'utente tocca un pulsante di azione e viene attivata l'istanza PendingIntent su SafetySourceIssue.Action inviata dall'origine di sicurezza, che risolve il problema in background e avvisa il Centro sicurezza al termine.

Per implementare le azioni di risoluzione, l'origine di Safety Center può utilizzare un servizio se si prevede che l'operazione richieda del tempo ( PendingIntent.getService ) o un ricevitore di trasmissione ( PendingIntent.getBroadcast ).

Utilizza questo codice per inviare un problema di risoluzione al Centro sicurezza:

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 risolve l'azione:

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

La stessa istanza di BroadcastReceiver nell'esempio precedente è dichiarata in 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>

Rispondere ai licenziamenti

È possibile specificare un'istanza PendingIntent che può essere attivata quando un'istanza SafetySourceIssue viene ignorata. Il Centro sicurezza gestisce i licenziamenti di questi problemi:

  • Se una fonte segnala un problema, un utente può ignorarlo nella schermata Safety Center toccando il pulsante Ignora (un pulsante X sulla scheda di avviso).
  • Quando un utente ignora un problema, se il problema persiste, non verrà più visualizzato nell'interfaccia utente.
  • I licenziamenti persistenti su un disco rimangono durante i riavvii del dispositivo.
  • Se l'origine del Centro sicurezza smette di fornire un problema e lo fornisce nuovamente in un secondo momento, il problema si ripresenta. Questo per consentire situazioni in cui un utente vede un avviso, lo ignora, quindi intraprende un'azione che dovrebbe alleviare il problema, ma poi l'utente fa di nuovo qualcosa che causa un problema simile. A questo punto, la carta di avvertimento dovrebbe riaffiorare.
  • Le schede di avviso gialle e rosse riappaiono ogni 180 giorni, a meno che l'utente non le abbia ignorate più volte.

La fonte non dovrebbe richiedere comportamenti aggiuntivi a meno che:

  • La fonte tenta di implementare questo comportamento in modo diverso, ad esempio, senza mai far riemergere il problema.
  • La fonte tenta di utilizzarlo come callback, ad esempio, per registrare le informazioni.

Fornire dati per più utenti/profili

L'API SafetyCenterManager può essere utilizzata tra utenti e profili diversi. Per ulteriori informazioni, consulta Creazione di app multiutente . L'oggetto Context che fornisce SafetyCenterManager è associato a un'istanza UserHandle , quindi l'istanza SafetyCenterManager restituita interagisce con il Safety Center per quell'istanza UserHandle . Per impostazione predefinita, Context è associato all'utente in esecuzione, ma è possibile creare un'istanza per un altro utente se l'app dispone delle autorizzazioni INTERACT_ACROSS_USERS e INTERACT_ACROSS_USERS_FULL . Questo esempio mostra come effettuare una chiamata tra utenti/profili:

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

Ciascun utente del dispositivo può avere più profili gestiti. Il Centro Sicurezza fornisce dati diversi per ciascun utente, ma unisce i dati di tutti i profili gestiti associati a un determinato utente.

Quando profile="all_profiles" è impostato per l'origine nel file di configurazione, si verifica quanto segue:

  • È presente una voce dell'interfaccia utente per l'utente (profilo principale) e tutti i relativi profili gestiti associati (che utilizzano istanze titleForWork ).
  • Il segnale di aggiornamento o nuova scansione viene inviato per il profilo principale e tutti i profili gestiti associati. Il ricevitore associato viene avviato per ciascun profilo e può fornire i dati associati direttamente a SafetyCenterManager senza dover effettuare una chiamata tra profili, a meno che il ricevitore o l'app non siano singleUser .

  • Si prevede che la fonte fornisca dati per l'utente e tutti i suoi profili gestiti. I dati per ciascuna voce dell'interfaccia utente potrebbero essere diversi a seconda del profilo.

Test

puoi accedere ShadowSafetyCenterManager e utilizzarlo in un test 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);
}

È possibile scrivere più test end-to-end (E2E), ma ciò non rientra nell'ambito di questa guida. Per ulteriori informazioni sulla scrittura di questi test E2E, vedere test CTS (CtsSafetyCenterTestCases)

Test e API interne

Le API interne e le API di test sono per uso interno, pertanto non sono descritte in dettaglio in questa guida. Tuttavia, in futuro potremmo estendere alcune API interne per consentire agli OEM di creare la propria interfaccia utente e aggiorneremo questa guida per fornire indicazioni su come utilizzarle.

Autorizzazioni

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Utilizzato per le API interne del Centro sicurezza
    • Concesso solo a PermissionController e shell

Applicazione Impostazioni

Reindirizzamento del Centro sicurezza

Per impostazione predefinita, è possibile accedere al Centro sicurezza tramite l'app Impostazioni con una nuova voce Sicurezza e privacy . Se utilizzi un'app Impostazioni diversa o se hai modificato l'app Impostazioni, potrebbe essere necessario personalizzare la modalità di accesso al Centro sicurezza.

Quando Safety Center è abilitato:

  • La voce Legacy Privacy è un codice nascosto
  • La voce Legacy Security è un codice nascosto
  • Viene aggiunto un codice alla nuova voce Sicurezza e privacy
  • La nuova voce Sicurezza e privacy reindirizza al codice del Centro sicurezza
  • Le azioni intent android.settings.PRIVACY_SETTINGS e android.settings.SECURITY_SETTINGS vengono reindirizzate all'apertura del Centro sicurezza (codice: security , privacy )

Pagine di sicurezza e privacy avanzate

L'app Impostazioni contiene impostazioni aggiuntive nei titoli Altre impostazioni di sicurezza e Altre impostazioni sulla privacy , disponibili nel Centro sicurezza:

Fonti di sicurezza

Safety Center si integra con un set specifico di fonti di sicurezza fornite dall'app Impostazioni:

  • Un'origine di sicurezza della schermata di blocco verifica che una schermata di blocco sia configurata con un passcode (o altra sicurezza), per garantire che le informazioni private dell'utente siano protette da accessi esterni.
  • Una fonte di sicurezza biometrica (nascosta per impostazione predefinita) emerge per l'integrazione con un sensore di impronte digitali o facciale.

Il codice sorgente di queste fonti del Centro sicurezza è accessibile tramite la ricerca del codice Android . Se l'app Impostazioni non viene modificata (non vengono apportate modifiche al nome del pacchetto, al codice sorgente o al codice sorgente che gestisce una schermata di blocco e dati biometrici), questa integrazione dovrebbe funzionare immediatamente. In caso contrario, potrebbero essere necessarie alcune modifiche, ad esempio la modifica del file di configurazione per modificare il nome del pacchetto dell'app Impostazioni e le origini che si integrano con Safety Center, nonché l'integrazione. Per ulteriori informazioni, consulta Aggiornamento del file di configurazione e delle impostazioni di integrazione .

Informazioni su PendingIntent

Se ti affidi all'integrazione esistente dell'app Impostazioni Safety Center in Android 14 o versioni successive, il bug descritto di seguito è stato corretto. In questo caso non è necessario leggere questa sezione.

Quando sei sicuro che il bug non esista, imposta un valore di configurazione della risorsa booleana XML nell'app Impostazioni config_isSafetyCenterLockScreenPendingIntentFixed su true per disattivare la soluzione alternativa all'interno di Safety Center.

Soluzione alternativa PendingIntent

Questo bug è causato dalle Impostazioni che utilizzano gli extra dell'istanza Intent per determinare quale frammento aprire. Poiché Intent#equals non tiene conto degli extra dell'istanza Intent , l'istanza PendingIntent per l'icona del menu a forma di ingranaggio e la voce sono considerate uguali e passano alla stessa interfaccia utente (anche se sono destinate a passare a un'interfaccia utente diversa). Questo problema viene risolto in una versione QPR differenziando le istanze PendingIntent in base al codice di richiesta. In alternativa, questo potrebbe essere differenziato utilizzando Intent#setId .

Fonti interne di sicurezza

Alcune origini di Safety Center sono interne e sono implementate nell'app di sistema PermissionController all'interno del modulo PermissionController. Queste origini si comportano come le normali origini del Centro sicurezza e non ricevono alcun trattamento speciale. Il codice per queste origini è disponibile tramite la ricerca del codice Android .

Si tratta principalmente di segnali relativi alla privacy, ad esempio:

  • Accessibilità
  • Revoca automaticamente le app inutilizzate
  • Accesso alla posizione
  • Ascoltatore di notifiche
  • Informazioni sulla politica del lavoro