Interagissez avec le centre de sécurité

Rediriger vers le centre de sécurité

N'importe quelle application peut ouvrir Safety Center à l'aide de l'action android.content.Intent.ACTION_SAFETY_CENTER (valeur de chaîne android.intent.action.SAFETY_CENTER ).

Pour ouvrir Safety Center, passez un appel depuis une instance Activity :

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Rediriger vers un problème spécifique

Il est également possible de rediriger vers une carte d'avertissement spécifique du Centre de sécurité à l'aide d'extras d'intention spécifiques. Ces extras ne sont pas destinés à être utilisés par des tiers et font donc partie de SafetyCenterManager , qui fait partie de @SystemApi . Seules les applications système peuvent accéder à ces extras.

Extras d'intention qui redirigent une carte d'avertissement spécifique :

  • EXTRA_SAFETY_SOURCE_ID
    • Valeur de chaîne : android.safetycenter.extra.SAFETY_SOURCE_ID
    • Type de chaîne : Spécifie l'ID de la source de sécurité de la carte d'avertissement associée
    • Nécessaire pour que la redirection vers le problème fonctionne
  • EXTRA_SAFETY_SOURCE_ISSUE_ID
    • Valeur de chaîne : android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
    • Type de chaîne : spécifie l'ID de la carte d'avertissement
    • Nécessaire pour que la redirection vers le problème fonctionne
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Valeur de chaîne : android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Type UserHandle : Spécifie UserHandle pour la carte d'avertissement associée.
    • Facultatif (la valeur par défaut est l'utilisateur actuel)

L'extrait de code ci-dessous peut être utilisé à partir d'une instance Activity pour ouvrir l'écran Safety Center pour un problème spécifique :

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

Redirection vers une sous-page spécifique (à partir d'Android 14)

Dans Android 14 ou version ultérieure, la page Safety Center est divisée en plusieurs sous-pages qui représentent les différents SafetySourcesGroup (dans Android 13, cela s'affiche sous forme d'entrées réductibles).

Il est possible de rediriger vers une sous-page spécifique en utilisant cette intention supplémentaire :

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • Valeur de chaîne : android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • Type de chaîne : spécifie l'ID du SafetySourcesGroup
    • Nécessaire pour que la redirection vers la sous-page fonctionne

L'extrait de code ci-dessous peut être utilisé à partir d'une instance Activity pour ouvrir l'écran Safety Center vers une sous-page spécifique :

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

startActivity(openSafetyCenterIntent);

Utiliser les API sources de Safety Center

Les API sources de Safety Center sont disponibles à l'aide SafetyCenterManager (qui est un @SystemApi ). Le code de la surface API est disponible dans Code Search . Le code d'implémentation des API est disponible dans Code Search .

Autorisations

Les API sources de Safety Center ne sont accessibles que par les applications système sur liste blanche utilisant les autorisations répertoriées ci-dessous. Pour plus d’informations, consultez Liste d’autorisation des autorisations privilégiées .

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Utilisé pour l'API SafetyCenterManager#isSafetyCenterEnabled() (non nécessaire pour les sources Safety Center, elles n'ont besoin que de l'autorisation SEND_SAFETY_CENTER_UPDATE )
    • Utilisé par les applications système qui vérifient si le centre de sécurité est activé
    • Accordé uniquement aux applications système sur liste blanche
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Utilisé pour l'API activée et l'API Safety Sources
    • Utilisé uniquement par des sources de sécurité
    • Accordé uniquement aux applications système sur liste blanche

Ces autorisations sont privilégiées et vous ne pouvez les acquérir qu'en les ajoutant au fichier approprié, par exemple, le fichier com.android.settings.xml pour l'application Paramètres et au fichier AndroidManifest.xml de l'application. Voir protectionLevel pour plus d’informations sur le modèle d’autorisation.

Obtenez le SafetyCenterManager

SafetyCenterManager est une classe @SystemApi accessible à partir des applications système à partir d'Android 13. Cet appel montre comment obtenir 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;
}

Vérifiez si le centre de sécurité est activé

Cet appel vérifie si Safety Center est activé. L'appel nécessite l'autorisation READ_SAFETY_CENTER_STATUS ou SEND_SAFETY_CENTER_UPDATE :

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

Fournir des données

Les données source de Safety Center avec la String sourceId donnée sont fournies à Safety Center avec l'objet SafetySourceData , qui représente une entrée d'interface utilisateur et une liste de problèmes (cartes d'avertissement). L'entrée de l'interface utilisateur et les cartes d'avertissement peuvent avoir différents niveaux de gravité spécifiés dans la classe SafetySourceData :

  • SEVERITY_LEVEL_UNSPECIFIED
    • Aucune gravité spécifiée
    • Couleur : Gris ou transparent (selon le SafetySourcesGroup de l'entrée)
    • Utilisé pour les données dynamiques qui se présentent comme une entrée statique dans l'interface utilisateur ou pour afficher une entrée non spécifiée
    • Ne doit pas être utilisé pour les cartes d'avertissement
  • SEVERITY_LEVEL_INFORMATION
    • Informations de base ou suggestion mineure
    • La couleur verte
  • SEVERITY_LEVEL_RECOMMENDATION
    • Recommandation à l'utilisateur d'agir sur ce problème, car cela pourrait le mettre en danger
    • Couleur jaune
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • Avertissement critique indiquant que l'utilisateur doit prendre des mesures face à ce problème, car il présente un risque
    • La couleur rouge

SafetySourceData

L'objet SafetySourceData est composé d'une entrée d'interface utilisateur, de cartes d'avertissement et d'invariants.

  • Instance SafetySourceStatus facultative (entrée d’interface utilisateur)
  • Liste des instances SafetySourceIssue (cartes d'avertissement)
  • Extras Bundle en option (à partir du 14)
  • Invariants :
    • La liste SafetySourceIssue doit être composée de problèmes avec des identifiants uniques.
    • L'instance SafetySourceIssue ne doit pas être plus importante que SafetySourceStatus s'il y en a une (sauf si SafetySourceStatus est SEVERITY_LEVEL_UNSPECIFIED , auquel cas les problèmes SEVERITY_LEVEL_INFORMATION sont autorisés).
    • Des exigences supplémentaires imposées par la configuration de l'API doivent être respectées. Par exemple, si la source concerne uniquement les problèmes, elle ne doit pas fournir d'instance SafetySourceStatus .

SafetySourceStatus

  • Titre CharSequence requis
  • Résumé CharSequence requis
  • Niveau de gravité requis
  • Instance PendingIntent facultative pour rediriger l'utilisateur vers la bonne page (la valeur par défaut utilise intentAction de la configuration, le cas échéant)
  • IconAction facultative (affichée sous la forme d'une icône latérale sur l'entrée) composée de :
    • Type d'icône obligatoire, qui doit être l'un des types suivants :
      • ICON_TYPE_GEAR : affiché sous la forme d'un engrenage à côté de l'entrée de l'interface utilisateur
      • ICON_TYPE_INFO : affiché sous la forme d'une icône d'information à côté de l'entrée de l'interface utilisateur
    • PendingIntent requis pour rediriger l'utilisateur vers une autre page
  • Valeur booléenne enabled facultative qui permet de marquer l'entrée de l'interface utilisateur comme désactivée, afin qu'elle ne soit pas cliquable (la valeur par défaut est true )
  • Invariants :
    • Les instances PendingIntent doivent ouvrir une instance Activity .
    • Si l'entrée est désactivée, elle doit être désignée SEVERITY_LEVEL_UNSPECIFIED .
    • Exigences supplémentaires imposées par la configuration de l'API.

SafetySourceIssue

  • Identificateur String unique requis
  • Titre CharSequence requis
  • Sous-titre CharSequence facultatif
  • Résumé CharSequence requis
  • Niveau de gravité requis
  • Catégorie de problème facultative, qui doit être l’une des suivantes :
    • ISSUE_CATEGORY_DEVICE : le problème affecte l'appareil de l'utilisateur.
    • ISSUE_CATEGORY_ACCOUNT : le problème affecte les comptes de l'utilisateur.
    • ISSUE_CATEGORY_GENERAL : le problème affecte la sécurité générale de l'utilisateur. C'est la valeur par défaut.
    • ISSUE_CATEGORY_DATA (à partir d'Android 14) : le problème affecte les données de l'utilisateur.
    • ISSUE_CATEGORY_PASSWORDS (à partir d’Android 14) : le problème affecte les mots de passe de l’utilisateur.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (à partir d'Android 14) : le problème affecte la sécurité personnelle de l'utilisateur.
  • Liste des éléments Action que l'utilisateur peut prendre pour ce problème, chaque instance Action étant composée de :
    • Identificateur String unique requis
    • Libellé CharSequence requis
    • PendingIntent requis pour rediriger l'utilisateur vers une autre page ou traiter l'action directement à partir de l'écran Safety Center
    • Booléen facultatif pour spécifier si ce problème peut être résolu directement à partir de l'écran Safety Center (la valeur par défaut est false )
    • Message de réussite CharSequence facultatif, à afficher à l'utilisateur lorsque le problème est résolu avec succès directement à partir de l'écran du Centre de sécurité.
  • PendingIntent facultatif appelé lorsque l'utilisateur rejette le problème (par défaut, rien n'est appelé)
  • Identifiant du type de problème String obligatoire ; ceci est similaire à l'identifiant du problème mais ne doit pas nécessairement être unique et est utilisé pour la journalisation
  • String facultative pour l’ID de déduplication, cela permet de publier le même SafetySourceIssue à partir de différentes sources et de l’afficher une seule fois dans l’interface utilisateur en supposant qu’ils ont le même deduplicationGroup (à partir d’Android 14). S'il n'est pas spécifié, le problème n'est jamais dédupliqué
  • CharSequence facultatif pour le titre d'attribution, il s'agit d'un texte qui indique l'origine de la carte d'avertissement (à partir d'Android 14). S’il n’est pas spécifié, utilise le titre du SafetySourcesGroup
  • Possibilité d'action facultative en cas de problème (à partir d'Android 14), qui doit être l'une des suivantes :
    • ISSUE_ACTIONABILITY_MANUAL : l'utilisateur doit résoudre ce problème manuellement. C'est la valeur par défaut.
    • ISSUE_ACTIONABILITY_TIP : ce problème n'est qu'un conseil et ne nécessite aucune intervention de l'utilisateur.
    • ISSUE_ACTIONABILITY_AUTOMATIC : ce problème a déjà été résolu et peut ne nécessiter aucune intervention de l'utilisateur.
  • Comportement de notification facultatif (à partir d'Android 14), qui doit être l'un des suivants :
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED : Safety Center décidera si une notification est nécessaire pour la carte d'avertissement. C'est la valeur par défaut.
    • NOTIFICATION_BEHAVIOR_NEVER : Aucune notification n'est publiée.
    • NOTIFICATION_BEHAVIOR_DELAYED : Une notification est publiée quelque temps après le premier signalement du problème.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY : Une notification est publiée dès que le problème est signalé.
  • Notification facultative, pour afficher une notification personnalisée avec la carte d'avertissement (à partir d'Android 14). Si elle n'est pas spécifiée, la Notification est dérivée de la carte d'avertissement. Composé de:
    • Titre CharSequence requis
    • Résumé CharSequence requis
    • Liste des éléments Action que l'utilisateur peut entreprendre pour cette notification
  • Invariants :
    • La liste des instances Action doit être composée d'actions avec des identifiants uniques
    • La liste des instances Action doit contenir un ou deux éléments Action . Si l'actionnabilité n'est pas ISSUE_ACTIONABILITY_MANUAL , avoir zéro Action est autorisé.
    • Le OnDismiss PendingIntent ne doit pas ouvrir une instance Activity
    • Exigences supplémentaires imposées par la configuration de l'API

Les données sont fournies lors de certains événements au Safety Center. Il est donc nécessaire de spécifier la raison pour laquelle la source a fourni à SafetySourceData une instance SafetyEvent .

SafetyEvent

  • Type requis, qui doit être l'un des suivants :
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED : L'état de la source a changé.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED : réponse à un signal d'actualisation/rescan du centre de sécurité ; utilisez-le au lieu de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED pour que Safety Center puisse suivre la demande d'actualisation/nouvelle analyse.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED : Nous avons résolu SafetySourceIssue.Action directement à partir de l'écran du Centre de sécurité ; utilisez-le au lieu de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED pour que Safety Center puisse suivre le SafetySourceIssue.Action en cours de résolution.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : nous avons tenté de résoudre SafetySourceIssue.Action directement à partir de l'écran Safety Center, mais nous n'y sommes pas parvenus ; utilisez-le au lieu de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED pour que Safety Center puisse suivre l'échec de SafetySourceIssue.Action .
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : La langue de l'appareil a changé, nous mettons donc à jour le texte des données fournies ; il est permis d'utiliser SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED pour cela.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED : nous fournissons ces données dans le cadre d'un démarrage initial, car les données de Safety Center ne sont pas conservées lors des redémarrages ; il est permis d'utiliser SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED pour cela.
  • Identificateur String facultatif pour l’ID de diffusion d’actualisation.
  • Identificateur String facultatif pour l’instance SafetySourceIssue en cours de résolution.
  • Identificateur String facultatif pour l’instance SafetySourceIssue.Action en cours de résolution.
  • Invariants :
    • L'ID de diffusion d'actualisation doit être fourni si le type est SAFETY_EVENT_TYPE_REFRESH_REQUESTED
    • Les ID de problème et d'action doivent être fournis si le type est SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED ou SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED .

Vous trouverez ci-dessous un exemple de la manière dont une source peut fournir des données à Safety Center (dans ce cas, il s'agit de fournir une entrée avec une seule carte d'avertissement) :

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

Obtenir les dernières données fournies

Vous pouvez obtenir les dernières données fournies à Safety Center pour une source appartenant à votre application. Vous pouvez l'utiliser pour afficher quelque chose dans votre propre interface utilisateur, pour vérifier si les données doivent être mises à jour avant d'effectuer une opération coûteuse, ou pour fournir la même instance SafetySourceData à Safety Center avec quelques modifications ou avec une nouvelle instance SafetyEvent . C'est également utile pour les tests.

Utilisez ce code pour obtenir les dernières données fournies à Safety Center :

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

Signaler une erreur

Si vous ne parvenez pas à collecter les données SafetySourceData , vous pouvez signaler l'erreur à Safety Center, qui change l'entrée en gris, efface les données mises en cache et fournit un message du genre Impossible de vérifier les paramètres . Vous pouvez également signaler une erreur si une instance de SafetySourceIssue.Action ne parvient pas à être résolue, auquel cas les données mises en cache ne sont pas effacées et l'entrée de l'interface utilisateur n'est pas modifiée ; mais un message est adressé à l'utilisateur pour lui faire savoir que quelque chose s'est mal passé.

Vous pouvez fournir l'erreur à l'aide de SafetySourceErrorDetails , qui est composé de :

  • SafetySourceErrorDetails : instance SafetyEvent requise :
// 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);

Répondre à une demande d'actualisation ou de nouvelle analyse

Vous pouvez recevoir un signal du centre de sécurité pour fournir de nouvelles données. Répondre à une demande d'actualisation ou de nouvelle analyse garantit que l'utilisateur visualise l'état actuel lors de l'ouverture de Safety Center et lorsqu'il appuie sur le bouton d'analyse.

Cela se fait en recevant une diffusion avec l'action suivante :

  • ACTION_REFRESH_SAFETY_SOURCES
    • Valeur de chaîne : android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • Déclenché lorsque Safety Center envoie une demande d'actualisation des données de la source de sécurité pour une application donnée
    • Intention protégée qui ne peut être envoyée que par le système
    • Envoyé à toutes les sources de sécurité dans le fichier de configuration en tant qu'intention explicite et nécessite l'autorisation SEND_SAFETY_CENTER_UPDATE

Les extras suivants sont fournis dans le cadre de cette diffusion :

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • Valeur de chaîne : android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • Type de tableau de chaînes ( String[] ), représente les ID source à actualiser pour l'application donnée
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • Valeur de chaîne : android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Type entier, représente un type de requête @IntDef
    • Doit être l'un des :
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA : demande à la source de fournir des données relativement rapidement, généralement lorsque l'utilisateur ouvre la page
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA : demande à la source de fournir des données aussi récentes que possible, généralement lorsque l'utilisateur appuie sur le bouton de nouvelle analyse.
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

    • Valeur de chaîne : android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
    • Type de chaîne, représente un identifiant unique pour l'actualisation demandée

Pour obtenir un signal du Safety Center, implémentez une instance BroadcastReceiver . La diffusion est envoyée avec BroadcastOptions spéciales qui permettent au récepteur de démarrer un service de premier plan.

BroadcastReceiver répond à une demande d'actualisation :

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 même instance de BroadcastReceiver dans l'exemple ci-dessus est déclarée dans 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>

Idéalement, une source Safety Center est implémentée de telle manière qu'elle appelle SafetyCenterManager lorsque ses données changent. Pour des raisons de santé du système, nous vous recommandons de répondre uniquement au signal de nouvelle analyse (lorsque l'utilisateur appuie sur le bouton d'analyse), et non lorsque l'utilisateur ouvre le Centre de sécurité. Si cette fonctionnalité est requise, le champ refreshOnPageOpenAllowed="true" dans le fichier de configuration doit être défini pour que la source reçoive la diffusion délivrée dans ces cas.

Répondre au centre de sécurité lorsqu'il est activé ou désactivé

Vous pouvez répondre lorsque le centre de sécurité est activé ou désactivé en utilisant cette action d'intention :

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • Valeur de chaîne : android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • Déclenché lorsque le centre de sécurité est activé ou désactivé pendant que l'appareil est en cours d'exécution
    • Non appelé au démarrage (utilisez ACTION_BOOT_COMPLETED pour cela)
    • Intention protégée qui ne peut être envoyée que par le système
    • Envoyé à toutes les sources de sécurité dans le fichier de configuration en tant qu'intention explicite, nécessite l'autorisation SEND_SAFETY_CENTER_UPDATE
    • Envoyé en tant qu'intention implicite nécessitant l'autorisation READ_SAFETY_CENTER_STATUS

Cette action d'intention est utile pour activer ou désactiver les fonctionnalités liées à Safety Center sur l'appareil.

Mettre en œuvre des actions de résolution

Une action de résolution est une instance SafetySourceIssue.Action qu'un utilisateur peut résoudre directement à partir de l'écran Safety Center. L'utilisateur appuie sur un bouton d'action et l'instance PendingIntent sur SafetySourceIssue.Action envoyée par la source de sécurité est déclenchée, ce qui résout le problème en arrière-plan et informe le centre de sécurité lorsque l'opération est terminée.

Pour implémenter des actions de résolution, la source Safety Center peut utiliser un service si l'opération devrait prendre un certain temps ( PendingIntent.getService ) ou un récepteur de diffusion ( PendingIntent.getBroadcast ).

Utilisez ce code pour envoyer un problème de résolution à Safety Center :

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 résout l’action :

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 même instance de BroadcastReceiver dans l'exemple ci-dessus est déclarée dans 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>

Répondre aux licenciements

Vous pouvez spécifier une instance PendingIntent qui peut être déclenchée lorsqu'une instance SafetySourceIssue est rejetée. Le Centre de Sécurité gère ces licenciements problématiques :

  • Si une source soulève un problème, un utilisateur peut le rejeter sur l'écran du Centre de sécurité en appuyant sur le bouton Ignorer (un bouton X sur la carte d'avertissement).
  • Lorsqu'un utilisateur ignore un problème, si le problème persiste, il ne réapparaîtra plus dans l'interface utilisateur.
  • Les licenciements persistants sur un disque restent lors des redémarrages de l'appareil.
  • Si la source du Safety Center cesse de signaler un problème, puis le signale à nouveau ultérieurement, le problème refait surface. Il s'agit de permettre les situations dans lesquelles un utilisateur voit un avertissement, le rejette, puis prend des mesures qui devraient atténuer le problème, mais l'utilisateur refait ensuite quelque chose qui provoque un problème similaire. À ce stade, la carte d’avertissement devrait refaire surface.
  • Les cartes d'avertissement jaunes et rouges réapparaissent tous les 180 jours, sauf si l'utilisateur les a ignorées plusieurs fois.

Des comportements supplémentaires ne devraient pas être requis par la source, sauf :

  • La source essaie de mettre en œuvre ce comportement différemment, par exemple, de ne jamais ressusciter le problème.
  • La source essaie de l'utiliser comme rappel, par exemple, pour enregistrer les informations.

Fournir des données pour plusieurs utilisateurs/profils

L'API SafetyCenterManager peut être utilisée entre les utilisateurs et les profils. Pour plus d'informations, consultez Création d'applications multi-utilisateurs . L'objet Context qui fournit SafetyCenterManager est associé à une instance UserHandle , de sorte que l'instance SafetyCenterManager renvoyée interagit avec le Safety Center pour cette instance UserHandle . Par défaut, Context est associé à l'utilisateur en cours d'exécution, mais il est possible de créer une instance pour un autre utilisateur si l'application détient les autorisations INTERACT_ACROSS_USERS et INTERACT_ACROSS_USERS_FULL . Cet exemple montre l'émission d'un appel entre utilisateurs/profils :

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

Chaque utilisateur de l'appareil peut avoir plusieurs profils gérés. Le Safety Center fournit des données différentes pour chaque utilisateur, mais fusionne les données de tous les profils gérés associés à un utilisateur donné.

Lorsque profile="all_profiles" est défini pour la source dans le fichier de configuration, les événements suivants se produisent :

  • Il existe une entrée d'interface utilisateur pour l'utilisateur (parent du profil) et tous ses profils gérés associés (qui utilisent des instances titleForWork ).
  • Le signal d'actualisation ou de nouvelle analyse est envoyé pour le profil parent et tous les profils gérés associés. Le récepteur associé est démarré pour chaque profil et peut fournir les données associées directement à SafetyCenterManager sans avoir à effectuer un appel entre profils, sauf si le récepteur ou l'application est singleUser .

  • La source est censée fournir des données sur l'utilisateur et tous ses profils gérés. Les données de chaque entrée de l'interface utilisateur peuvent être différentes selon le profil.

Essai

vous pouvez accéder ShadowSafetyCenterManager et l'utiliser dans 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);
}

Vous pouvez écrire davantage de tests de bout en bout (E2E), mais cela sort du cadre de ce guide. Pour plus d'informations sur l'écriture de ces tests E2E, voir Tests CTS (CtsSafetyCenterTestCases)

Test et API internes

Les API internes et les API de test sont destinées à un usage interne et ne sont donc pas décrites en détail dans ce guide. Cependant, nous pourrions étendre certaines API internes à l'avenir pour permettre aux OEM de créer leur propre interface utilisateur et nous mettrons à jour ce guide pour fournir des conseils sur la façon de les utiliser.

Autorisations

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Utilisé pour les API internes du Safety Center
    • Accordé uniquement à PermissionController et au shell

Application Paramètres

Redirection du centre de sécurité

Par défaut, le Centre de sécurité est accessible via l'application Paramètres avec une nouvelle entrée Sécurité et confidentialité . Si vous utilisez une autre application Paramètres ou si vous avez modifié l'application Paramètres, vous devrez peut-être personnaliser la manière dont vous accédez au Centre de sécurité.

Lorsque le Centre de sécurité est activé :

  • L'entrée de confidentialité héritée est un code caché
  • L'entrée de sécurité héritée est un code caché
  • Une nouvelle entrée de sécurité et de confidentialité est ajoutée au code
  • La nouvelle entrée de sécurité et de confidentialité redirige vers le code Safety Center
  • Les actions d'intention android.settings.PRIVACY_SETTINGS et android.settings.SECURITY_SETTINGS sont redirigées vers l'ouverture du Centre de sécurité (code : security , Privacy )

Pages avancées de sécurité et de confidentialité

L'application Paramètres contient des paramètres supplémentaires sous les titres Plus de paramètres de sécurité et Plus de paramètres de confidentialité , disponibles dans Safety Center :

Sources de sécurité

Safety Center s'intègre à un ensemble spécifique de sources de sécurité fournies par l'application Paramètres :

  • Une source de sécurité d'écran de verrouillage vérifie qu'un écran de verrouillage est configuré avec un mot de passe (ou une autre sécurité), pour garantir que les informations privées de l'utilisateur sont protégées de tout accès externe.
  • Une source de sécurité biométrique (masquée par défaut) apparaît pour s'intégrer à un capteur d'empreintes digitales ou de visage.

Le code source de ces sources Safety Center est accessible via la recherche de code Android . Si l'application Paramètres n'est pas modifiée (aucune modification n'est apportée au nom du package, au code source ou au code source qui traite de l'écran de verrouillage et de la biométrie), alors cette intégration devrait fonctionner immédiatement. Sinon, certaines modifications pourraient être nécessaires, telles que la modification du fichier de configuration pour changer le nom du package de l'application Paramètres et les sources qui s'intègrent à Safety Center, ainsi que l'intégration. Pour plus d'informations, consultez Mettre à jour le fichier de configuration et les paramètres d'intégration .

À propos de l'intention en attente

Si vous comptez sur l’intégration existante de l’application Paramètres Safety Center dans Android 14 ou version ultérieure, le bug décrit ci-dessous a été corrigé. La lecture de cette section n'est pas nécessaire dans ce cas.

Lorsque vous êtes sûr que le bogue n'existe pas, définissez une valeur de configuration de ressource booléenne XML dans l'application Paramètres config_isSafetyCenterLockScreenPendingIntentFixed sur true pour désactiver la solution de contournement dans Safety Center.

Solution de contournement en attente d'intention

Ce bogue est dû au fait que les paramètres utilisent des extras d'instance Intent pour déterminer quel fragment ouvrir. Étant donné que Intent#equals ne prend pas en compte les extras de l'instance Intent , l'instance PendingIntent pour l'icône du menu d'engrenage et l'entrée sont considérées comme égales et naviguent vers la même interface utilisateur (même si elles sont destinées à naviguer vers une interface utilisateur différente). Ce problème est résolu dans une version QPR en différenciant les instances PendingIntent par code de demande. Alternativement, cela pourrait être différencié en utilisant Intent#setId .

Sources de sécurité internes

Certaines sources Safety Center sont internes et sont implémentées dans l'application système PermissionController au sein du module PermissionController. Ces sources se comportent comme des sources normales du Safety Center et ne reçoivent aucun traitement spécial. Le code de ces sources est disponible via la recherche de code Android .

Il s'agit principalement de signaux de confidentialité, par exemple :

  • Accessibilité
  • Révoquer automatiquement les applications inutilisées
  • Accès à la localisation
  • Écouteur de notifications
  • Informations sur la politique de travail