Interactúa con el Centro de seguridad

Redireccionar al Centro de seguridad

Cualquier app puede abrir el Centro de seguridad con el Acción android.content.Intent.ACTION_SAFETY_CENTER (valor de cadena android.intent.action.SAFETY_CENTER).

Para abrir el Centro de seguridad, realiza una llamada desde una instancia de Activity:

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Redireccionar a un problema específico

También es posible redireccionar a una tarjeta de advertencia específica del Centro de seguridad con extras de intent específico. Estos extras no están destinados a ser utilizados por terceros, por lo que son parte de SafetyCenterManager, que es parte de @SystemApi. Solo las apps del sistema pueden acceder a estos extras.

Elementos adicionales de intent que redireccionan una tarjeta de advertencia específica:

  • EXTRA_SAFETY_SOURCE_ID
    • Valor de cadena: android.safetycenter.extra.SAFETY_SOURCE_ID
    • Tipo de cadena: especifica el ID de la fuente de seguridad de la tarjeta de advertencia
    • Obligatorio para que funcione el redireccionamiento al problema
  • EXTRA_SAFETY_SOURCE_ISSUE_ID
    • Valor de cadena: android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
    • Tipo de cadena: Especifica el ID de la tarjeta de advertencia
    • Obligatorio para que funcione el redireccionamiento al problema
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Valor de cadena: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Tipo UserHandle: Especifica UserHandle para la advertencia asociada. tarjeta
    • Opcional (la configuración predeterminada es el usuario actual)

El siguiente fragmento de código se puede usar desde una instancia de Activity para abrir la pantalla del Centro de seguridad a un problema específico:

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

Redireccionar a una subpágina específica (a partir de Android 14)

En Android 14 o versiones posteriores, la página del Centro de seguridad se divide en varias subpáginas que representan los diferentes SafetySourcesGroup (en Android 13 (se muestra como entradas contraíbles).

Es posible redireccionar a una subpágina específica con este intent adicional:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • Valor de cadena: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • Tipo de cadena: Especifica el ID de SafetySourcesGroup.
    • Obligatorio para que funcione el redireccionamiento a la subpágina

El siguiente fragmento de código se puede usar desde una instancia de Activity para abrir la pantalla del Centro de seguridad a una subpágina específica:

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

startActivity(openSafetyCenterIntent);

Cómo usar las APIs de origen del Centro de seguridad

Las APIs de origen del Centro de seguridad están disponibles usando SafetyCenterManager (que es un @SystemApi). El código para la plataforma de API está disponible en Código Búsqueda. El código de implementación de las APIs está disponible en Code Búsqueda.

Permisos

Solo las apps del sistema incluidas en la lista de entidades permitidas pueden acceder a las APIs de origen del Centro de seguridad con los permisos que se indican a continuación. Para obtener información adicional, consulta Información Lista de entidades permitidas de permisos.

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Se usa para la API de SafetyCenterManager#isSafetyCenterEnabled() (no necesarias para las fuentes del Centro de seguridad, solo necesitan SEND_SAFETY_CENTER_UPDATE)
    • Lo usan las apps del sistema que verifican si el Centro de seguridad está habilitado
    • Se otorga solo a las apps del sistema incluidas en la lista de entidades permitidas.
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Se usa para la API habilitada y la API de Safety Sources
    • Solo lo usan fuentes de seguridad
    • Se otorga solo a las apps del sistema incluidas en la lista de entidades permitidas.

Estos permisos tienen privilegios y solo puedes adquirirlos si los agregas a el archivo relevante, por ejemplo, el com.android.settings.xml de la app de Configuración y el archivo AndroidManifest.xml de la app. Consulta protectionLevel para obtener más información sobre el modelo de permisos.

Cómo obtener SafetyCenterManager

SafetyCenterManager es una clase @SystemApi a la que se puede acceder desde las apps del sistema. a partir de Android 13. Esta llamada demuestra cómo obtén 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;
}

Cómo verificar si el Centro de seguridad está habilitado

Esta llamada verifica si se habilitó el Centro de seguridad. La llamada requiere la READ_SAFETY_CENTER_STATUS o el permiso SEND_SAFETY_CENTER_UPDATE:

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

Proporciona datos

Los datos de origen del Centro de seguridad con el String sourceId especificado se proporcionan a Centrado con el objeto SafetySourceData, que representa una entrada de IU y una una lista de problemas (tarjetas de advertencia). La entrada de la IU y las tarjetas de advertencia pueden tener diferentes niveles de gravedad especificados en la clase SafetySourceData:

  • SEVERITY_LEVEL_UNSPECIFIED
    • No se especificó ninguna gravedad
    • Color: Gris o transparente (según la SafetySourcesGroup de las entrada)
    • Se usa para datos dinámicos que se presenten como una entrada estática en la IU o para mostrar una entrada no especificada
    • No se debe usar para tarjetas de advertencia
  • SEVERITY_LEVEL_INFORMATION
    • Información básica o sugerencia menor
    • Color: Verde
  • SEVERITY_LEVEL_RECOMMENDATION
    • Se recomienda que el usuario tome medidas con respecto a este problema, ya que podría ponerlos en riesgo
    • Color: Amarillo
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • Advertencia crítica que indica que el usuario debe tomar medidas al respecto, ya que presenta un riesgo
    • Color: Rojo

SafetySourceData

El objeto SafetySourceData consta de una entrada de IU, tarjetas de advertencia y invariantes.

  • Instancia de SafetySourceStatus opcional (entrada de la IU)
  • Lista de instancias de SafetySourceIssue (tarjetas de advertencia)
  • Elementos adicionales opcionales de Bundle (a partir de 14)
  • Invariantes:
    • La lista SafetySourceIssue debe incluir problemas con bases de datos identificadores.
    • La instancia SafetySourceIssue no debe ser de mayor importancia que SafetySourceStatus si hay una (a menos que SafetySourceStatus sea SEVERITY_LEVEL_UNSPECIFIED, en cuyo caso SEVERITY_LEVEL_INFORMATION errores).
    • Se deben cumplir los requisitos adicionales impuestos por la configuración de la API por ejemplo, si la fuente es solo del problema, no debe proporcionar un Instancia SafetySourceStatus.

SafetySourceStatus

  • Título CharSequence obligatorio
  • Resumen obligatorio de CharSequence
  • Nivel de gravedad obligatorio
  • Opcional PendingIntent para redireccionar al usuario a la página correcta (la configuración predeterminada usa intentAction desde la configuración, si corresponde)
  • IconAction opcional (que se muestra como un ícono lateral en la entrada) que incluye lo siguiente:
    • Es un tipo de ícono obligatorio, que debe ser uno de los siguientes tipos:
      • ICON_TYPE_GEAR: Se muestra como un engranaje junto a la entrada de la IU.
      • ICON_TYPE_INFO: Se muestra como un ícono de información junto a la entrada de la IU.
    • Obligatorias PendingIntent para redireccionar al usuario a otra página
  • Valor booleano enabled opcional que permite marcar la entrada de la IU como inhabilitado, por lo que no se puede hacer clic en él (el valor predeterminado es true)
  • Invariantes:
    • Las instancias PendingIntent deben abrir una instancia Activity.
    • Si la entrada está inhabilitada, se debe designar SEVERITY_LEVEL_UNSPECIFIED
    • Los requisitos adicionales que impone la configuración de la API.

SafetySourceIssue

  • Identificador único obligatorio de String
  • Título CharSequence obligatorio
  • Subtítulo CharSequence opcional
  • Resumen obligatorio de CharSequence
  • Nivel de gravedad obligatorio
  • Categoría de problema opcional, que debe ser una de las siguientes:
    • ISSUE_CATEGORY_DEVICE: El problema afecta al dispositivo del usuario.
    • ISSUE_CATEGORY_ACCOUNT: El problema afecta las cuentas del usuario.
    • ISSUE_CATEGORY_GENERAL: El problema afecta la seguridad general del usuario. Es el valor predeterminado.
    • ISSUE_CATEGORY_DATA (A partir de Android 14): El problema afecta los datos del usuario.
    • ISSUE_CATEGORY_PASSWORDS (a partir de Android 14): El problema afecta contraseñas.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (a partir de Android 14): El problema afecta la configuración la seguridad de los datos.
  • Lista de elementos Action que el usuario puede tomar para este problema, cada uno Instancia Action que se compone de lo siguiente:
    • Identificador único obligatorio de String
    • Etiqueta CharSequence obligatoria
    • Obligatorias PendingIntent para redireccionar al usuario a otra página o procesar la acción directamente desde la pantalla del Centro de seguridad
    • Booleano opcional para especificar si este problema se puede resolver directamente desde la pantalla de SafetyCenter (el valor predeterminado es false)
    • Mensaje de éxito CharSequence opcional que se mostrará al usuario Cuando el problema se resuelve correctamente directamente desde el Centro de seguridad pantalla
  • Opcional PendingIntent a la que se llama cuando el usuario descarta el problema (el valor predeterminado es llama)
  • Es el identificador del tipo de problema String obligatorio. Esto es similar al problema identificador único, pero no tiene que ser único, y se usa para el registro
  • String opcional para el ID de anulación de duplicación, lo que permite publicar el mismo SafetySourceIssue de diferentes fuentes y solo se muestra una vez en IU de suponer que tienen el mismo deduplicationGroup (a partir de Android 14). Si no se especifica, el problema nunca se con anulación de duplicación
  • CharSequence opcional para el título de atribución; este es un texto que muestra donde se originó la tarjeta de advertencia (Iniciar Android 14). Si no se especifica, se usará el título del SafetySourcesGroup
  • Acción opcional del problema (a partir de Android 14) que debe ser uno de los siguientes:
    • ISSUE_ACTIONABILITY_MANUAL: El usuario debe resolver este problema. manualmente. Es el valor predeterminado.
    • ISSUE_ACTIONABILITY_TIP: Este problema es solo una sugerencia y es posible que no requiera a cualquier entrada del usuario.
    • ISSUE_ACTIONABILITY_AUTOMATIC: Ya se resolvió este problema y es posible que no requiera ninguna entrada del usuario.
  • Comportamiento de notificación opcional (a partir de Android 14), que debe ser uno de los siguientes:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED: El Centro de seguridad decidirá si un para poder ver la tarjeta de advertencia. Es el valor predeterminado.
    • NOTIFICATION_BEHAVIOR_NEVER: No se publica ninguna notificación.
    • NOTIFICATION_BEHAVIOR_DELAYED: Se publicará una notificación en algún momento. después de informar el problema por primera vez.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY: Se publica una notificación en cuanto se informa el problema.
  • Notification opcional para mostrar una notificación personalizada con la tarjeta de advertencia (A partir de Android 14). Si no se especifica, el Notification se deriva de la tarjeta de advertencia. Compuesto por:
    • Título CharSequence obligatorio
    • Resumen obligatorio de CharSequence
    • Lista de elementos Action que el usuario puede tomar para esta notificación
  • Invariantes:
    • La lista de instancias de Action debe constar de acciones con identificadores
    • La lista de instancias de Action debe contener uno o dos Action o de terceros. Si la capacidad de acción no es ISSUE_ACTIONABILITY_MANUAL, no se permite tener un valor de Action.
    • El elemento OnDismiss PendingIntent no debe abrir una instancia de Activity
    • Requisitos adicionales impuestos por la configuración de la API

Se proporcionan datos sobre ciertos eventos al Centro de seguridad, por lo que es necesario especifica qué provocó que la fuente proporcionara a SafetySourceData un Instancia SafetyEvent.

SafetyEvent

  • Tipo obligatorio, que debe ser uno de los siguientes:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED: El estado de la fuente tiene cambió.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED: Cómo responder a una actualización o un nuevo análisis señal del Centro de seguridad; usar esto en lugar de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para que el Centro de seguridad pueda hacer un seguimiento de la solicitud de actualización o volver a analizar.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED: Lo resolvimos SafetySourceIssue.Action directamente desde la pantalla del Centro de seguridad. usar esto en lugar de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED por Seguridad Centro para poder realizar un seguimiento de la resolución de SafetySourceIssue.Action.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED: Intentamos solucionar el problema SafetySourceIssue.Action directamente desde la pantalla del Centro de seguridad, pero no lo lograste; usar esto en lugar de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para que el Centro de seguridad pueda ha fallado la pista SafetySourceIssue.Action.
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED: Es el idioma del dispositivo. cambió, por lo que actualizaremos el texto de los datos proporcionados; es puede usar SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para esto.
    • SAFETY_EVENT_TYPE_DEVICE_REBOOTED: Proporcionamos estos datos como parte de un inicio inicial, ya que los datos del Centro de seguridad no persisten en reinicios; se permite usar SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para esto.
  • Es el identificador String opcional para el ID de transmisión actualizado.
  • Identificador String opcional para la instancia SafetySourceIssue que obtiene resuelto.
  • Identificador String opcional para la instancia SafetySourceIssue.Action que se está resolviendo.
  • Invariantes:
    • Se debe proporcionar el ID de actualización de la transmisión si el tipo es SAFETY_EVENT_TYPE_REFRESH_REQUESTED
    • Se deben proporcionar los IDs de problema y de acción si el tipo es SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED o SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED

A continuación, se muestra un ejemplo de cómo una fuente podría proporcionar datos al Centro de seguridad (en este en caso de que proporcione una entrada con una sola tarjeta de advertencia):

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

Obtener los últimos datos proporcionados

Puedes obtener los últimos datos que se proporcionaron al Centro de seguridad de una fuente que pertenece a tu . Puedes usar esto para mostrar algo en tu propia IU y verificar si los datos deben actualizarse antes de realizar una operación costosa o para proporcionar la misma instancia de SafetySourceData al Centro de seguridad con algunos cambios o con un nueva instancia de SafetyEvent. También es útil para realizar pruebas.

Usa este código para obtener los últimos datos proporcionados al Centro de seguridad:

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

Informar un error

Si no puedes recopilar datos de SafetySourceData, informa el error a Seguridad de Google, que cambia la entrada a gris, borra los datos almacenados en caché y proporciona mensaje, como No se pudo verificar la configuración. También puedes informar un error si no se resuelve una instancia de SafetySourceIssue.Action, en cuyo caso el los datos almacenados en caché no se borran y la entrada de la IU no se modifica; pero un mensaje es que se muestra al usuario para informarle que se produjo un error.

Puedes proporcionar el error usando SafetySourceErrorDetails, que se compone de:

  • SafetySourceErrorDetails: Instancia de SafetyEvent obligatoria:
// 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);

Cómo responder a una solicitud de actualización o volver a analizar

Puedes recibir una señal del Centro de seguridad para proporcionar datos nuevos. Responder a un de actualización o volver a analizar garantiza que el usuario vea el estado actual cuando abriendo el Centro de seguridad y cuando presionen el botón de análisis.

Para ello, se recibe una transmisión con la siguiente acción:

  • ACTION_REFRESH_SAFETY_SOURCES
    • Valor de cadena: android.safetycenter.action.REFRESH_SAFETY_SOURCES
    • Se activa cuando el Centro de seguridad envía una solicitud para actualizar los datos de la fuente de seguridad de una app determinada
    • Intent protegido que solo puede enviar el sistema
    • Se envía a todas las fuentes de seguridad en el archivo de configuración como un intent y requiere el permiso SEND_SAFETY_CENTER_UPDATE

Se proporcionan los siguientes extras como parte de esta transmisión:

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • Valor de cadena: android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • El tipo de array de cadenas (String[]) representa los IDs de origen que se deben actualizar. la app determinada
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • Valor de cadena: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Tipo de número entero, representa un tipo de solicitud @IntDef
    • Debe ser uno de los siguientes:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA: Solicita que la fuente haga lo siguiente: Proporcionan datos relativamente rápido, generalmente cuando el usuario abre la página.
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA: Solicita la fuente. para proporcionar datos lo más actualizados posible, generalmente cuando el usuario presiona el botón volver a buscar
  • EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID

    • Valor de cadena: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
    • Tipo de cadena representa un identificador único para la actualización solicitada

Para recibir una señal del Centro de seguridad, implementa un BroadcastReceiver instancia. La transmisión se envía con un BroadcastOptions especial que permite a la para iniciar un servicio en primer plano.

BroadcastReceiver responde a una solicitud de actualización:

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 misma instancia de BroadcastReceiver del ejemplo anterior se declara en 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>

Lo ideal es que una fuente del Centro de seguridad se implemente de tal manera que llame SafetyCenterManager cuando cambian sus datos. Por motivos de estado del sistema, Se recomienda que respondas solo a la señal de nueva búsqueda (cuando el usuario presione no cuando el usuario abra el Centro de seguridad. Si esta función está obligatorio, el campo refreshOnPageOpenAllowed="true" del archivo de configuración se debe establecer para que la fuente reciba la transmisión entregada en estos casos.

Responde al Centro de seguridad cuando esté habilitado o inhabilitado

Puedes responder cuando el Centro de seguridad esté habilitado o inhabilitado con este acción de intent:

  • ACTION_SAFETY_CENTER_ENABLED_CHANGED
    • Valor de cadena: android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
    • Se activa cuando el Centro de seguridad está habilitado o inhabilitado mientras el dispositivo se está ejecutando
    • No se llama durante el inicio (usar ACTION_BOOT_COMPLETED en ese caso)
    • Intent protegido que solo puede enviar el sistema
    • Se envía a todas las fuentes de seguridad en el archivo de configuración como un intent, requiere el permiso SEND_SAFETY_CENTER_UPDATE
    • Se envía como un intent implícito que requiere el READ_SAFETY_CENTER_STATUS. permiso

Esta acción de intent es útil para habilitar o inhabilitar funciones relacionadas con Centro de seguridad en el dispositivo.

Implementa acciones de resolución

Una acción de resolución es una instancia de SafetySourceIssue.Action que un usuario puede resolverse directamente en la pantalla del Centro de seguridad. El usuario presiona un botón de acción y la instancia PendingIntent en SafetySourceIssue.Action que envió el de seguridad, lo que resuelve el problema en segundo plano y le notificará al Centro de seguridad cuando finalice.

Para implementar acciones de resolución, la fuente del Centro de seguridad puede usar un servicio en los siguientes casos: se espera que la operación demore un tiempo (PendingIntent.getService) o un receptor de emisión (PendingIntent.getBroadcast).

Usa este código para enviar un problema de resolución al Centro de seguridad:

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 resuelve la acción:

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 misma instancia de BroadcastReceiver del ejemplo anterior se declara en 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>

Cómo responder a los descartes de problemas

Puedes especificar una instancia de PendingIntent que se pueda activar cuando una Se descartó la instancia SafetySourceIssue. El Centro de seguridad se encarga de estos problemas descartes:

  • Si una fuente envía un problema, el usuario puede descartarlo en el Centro de seguridad. la pantalla presionando el botón para descartar (un botón X en la tarjeta de advertencia).
  • Cuando un usuario descarta un problema, no se mostrará si este continúa. en la IU nuevamente.
  • Los descartes persistentes en un disco permanecen durante el reinicio del dispositivo.
  • Si la fuente del Centro de seguridad deja de proporcionar un problema y, luego, proporciona la problema de nuevo en otro momento, el problema reaparece. Esto permite situaciones en las que un usuario ve una advertencia, la descarta y, luego, toma medidas que debería aliviar el problema, pero luego el usuario vuelve a hacer algo causa un problema similar. En este punto, la tarjeta de advertencia debería volver a aparecer.
  • Las tarjetas de advertencia amarillas y rojas reaparecen cada 180 días, a menos que el usuario las descarté varias veces.

La fuente no debería necesitar comportamientos adicionales, a menos que ocurra lo siguiente:

  • La fuente intenta implementar este comportamiento de manera diferente; por ejemplo, nunca replantear el problema.
  • La fuente intenta usar esto como una devolución de llamada, por ejemplo, para registrar el información.

Proporciona datos para múltiples usuarios/perfiles

La API de SafetyCenterManager se puede usar con usuarios y perfiles. Para ver más consulta Cómo compilar Multiuser-Aware Apps. El Context El objeto que proporciona SafetyCenterManager está asociado con un UserHandle. por lo que la instancia SafetyCenterManager que se muestra interactúa con el Centro de seguridad de esa instancia UserHandle. De forma predeterminada, Context es asociada con el usuario en ejecución, pero es posible crear una instancia para otro usuario si la app contiene las etiquetas INTERACT_ACROSS_USERS y Permisos INTERACT_ACROSS_USERS_FULL. En este ejemplo, se muestra cómo realizar una llamada en todos los usuarios o perfiles:

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

Cada usuario del dispositivo puede tener varios perfiles administrados. El Centro de seguridad proporciona datos diferentes para cada usuario, pero combina los datos de todos los servicios asociados a un usuario determinado.

Cuando se establece profile="all_profiles" para la fuente en el archivo de configuración, ocurre lo siguiente:

  • Existe una UIentry para el usuario (nivel superior del perfil) y todos sus atributos perfiles administrados (que usan instancias titleForWork).
  • El indicador de actualización o nueva búsqueda se envía al perfil superior y a todos perfiles administrados asociados. El receptor asociado se inicia para cada y pueden proporcionar los datos asociados directamente a SafetyCenterManager sin tener que realizar una llamada de perfil sincronizado, a menos que la o que la app sea singleUser

  • Se espera que la fuente proporcione datos al usuario y a todos sus perfiles. Los datos para cada entrada de la IU pueden ser diferentes según el perfil.

Prueba

Puedes acceder a ShadowSafetyCenterManager y usarlo en una prueba de 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);
}

Puedes escribir más pruebas de extremo a extremo (E2E), pero está fuera del alcance de este curso. . Para obtener más información sobre cómo escribir estas pruebas E2E, consulta Pruebas CTS (CtsSafetyCenterTestCases)

APIs internas y de prueba

Las APIs internas y las APIs de prueba son para uso interno, por lo que no se describen en en esta guía. Sin embargo, es posible que ampliemos algunas APIs internas en el futuro para que los OEM puedan crear su propia IU. Actualizaremos esta guía para proporcionar orientación sobre cómo usarlos.

Permisos

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Se usa para las APIs del Centro de seguridad internas
    • Solo se otorga al PermissionController y a la shell.

App de Configuración

Redireccionamiento del Centro de seguridad

De forma predeterminada, se accede al Centro de seguridad desde la app de Configuración con un nuevo Seguridad y privacidad. Si usas una app de Configuración diferente o si Modificaste la app de Configuración, es posible que debas personalizar el modo en que el Centro de seguridad y cómo se accede a ellos.

Cuando el Centro de seguridad está habilitado:

  • La entrada Privacidad heredada está oculta código
  • La entrada de Seguridad heredada está oculta código
  • Nueva seguridad y se agregó la entrada de privacidad código
  • Nueva seguridad y La entrada de privacidad redirecciona al código del Centro de seguridad
  • android.settings.PRIVACY_SETTINGS y android.settings.SECURITY_SETTINGS las acciones de intent se redireccionan al Centro de seguridad abierto (código: seguridad, privacidad)

Páginas de seguridad y privacidad avanzadas

La app de Configuración incluye parámetros de configuración adicionales en Más parámetros de configuración de seguridad y Más parámetros de configuración de privacidad, disponibles en el Centro de seguridad:

Fuentes de seguridad

El Centro de seguridad se integra con un conjunto específico de fuentes de seguridad proporcionadas por la App de Configuración:

  • Una fuente de seguridad de la pantalla de bloqueo verifica que la pantalla de bloqueo esté configurada con una contraseña (o algún otro tipo de seguridad), para garantizar que la información privada del usuario se mantiene a salvo del acceso externo.
  • Una fuente de seguridad biométrica (oculta de forma predeterminada) se puede integrar en un sensor de huellas dactilares o el rostro.

Se puede acceder al código fuente de estas fuentes del Centro de seguridad a través de Android. código búsqueda. Si no se modifica la aplicación Configuración (no se realizan cambios en el nombre del paquete, el código fuente o el código fuente que utiliza una pantalla de bloqueo y datos biométricos) esta integración debería funcionar de inmediato. De lo contrario, algunas modificaciones podrían requerirse, como cambiar el archivo de configuración para cambiar el paquete el nombre de la app de Configuración y las fuentes que se integran con el Centro de seguridad, y la integración. Para obtener más información, consulta Cómo actualizar la configuración y el integración de configuración.

Información acerca de PendingIntent

Si dependes de la integración existente del Centro de seguridad de la app de Configuración en Android 14 o una versión posterior, se corrigió el error descrito a continuación. No es necesario leer esta sección en este caso.

Cuando sepas con certeza que el error no existe, configura un recurso booleano XML. valor de configuración en la app de Configuración config_isSafetyCenterLockScreenPendingIntentFixed a true para desactivar la en el Centro de seguridad.

Solución alternativa de PendingIntent

Este error se debe a que la configuración usa los extras de instancia de Intent para determinar cuál que se abrirá. Porque Intent#equals no toma la instancia Intent extras en cuenta, la instancia PendingIntent para el ícono de menú de ajustes y la de entrada se consideran iguales y navegan a la misma IU (a pesar de que son para navegar a una IU diferente). Este problema se corrigió en una versión de QPR por diferenciar las instancias de PendingIntent por código de solicitud Por otro lado, esto podría diferenciarse usando Intent#setId.

Fuentes de seguridad internas

Algunas fuentes del Centro de seguridad son internas y se implementan en el App del sistema PermissionController dentro del módulo PermissionController. Estos las fuentes se comportan como las fuentes normales del Centro de seguridad y no reciben tratamiento. El código de estas fuentes está disponible a través del código de Android búsqueda.

Estos son principalmente indicadores de privacidad, por ejemplo:

  • Accesibilidad
  • Revocar automáticamente las apps en desuso
  • Acceso a la ubicación
  • Agente de escucha de notificaciones
  • Información sobre la política de trabajo