Interactuar con el Centro de seguridad

Redirigir al centro de seguridad

Cualquier aplicación puede abrir el Centro de seguridad usando la acción android.content.Intent.ACTION_SAFETY_CENTER (valor de cadena android.intent.action.SAFETY_CENTER ).

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

Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);

startActivity(openSafetyCenterIntent);

Redirigir a un problema específico

También es posible redirigir a una tarjeta de advertencia específica del Centro de seguridad utilizando extras de intención específicos. Estos extras no están destinados a ser utilizados por terceros, por lo que forman parte de SafetyCenterManager , que forma parte de @SystemApi . Sólo las aplicaciones del sistema pueden acceder a estos extras.

Extras de intención que redirigen 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 asociada.
    • Requerido para que funcione la redirección 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.
    • Requerido para que funcione la redirección al problema
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Valor de cadena: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Tipo UserHandle : especifica UserHandle para la tarjeta de advertencia asociada.
    • Opcional (el valor predeterminado es el usuario actual)

El siguiente fragmento de código se puede utilizar desde una instancia 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);

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

En Android 14 o superior, la página del Centro de seguridad se divide en varias subpáginas que representan los diferentes SafetySourcesGroup (en Android 13, esto se muestra como entradas plegables).

Es posible redirigir a una subpágina específica utilizando este intent extra:

  • EXTRA_SAFETY_SOURCES_GROUP_ID
    • Valor de cadena: android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
    • Tipo de cadena: especifica el ID de SafetySourcesGroup
    • Requerido para que funcione la redirección a la subpágina

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

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

startActivity(openSafetyCenterIntent);

Utilice las API de origen del Centro de seguridad

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

Permisos

Solo las aplicaciones del sistema incluidas en la lista permitida que utilizan los permisos que se enumeran a continuación pueden acceder a las API de origen del Centro de seguridad. Para obtener información adicional, consulte Lista de permitidos de permisos privilegiados .

  • READ_SAFETY_CENTER_STATUS
    • signature|privileged
    • Se utiliza para la API SafetyCenterManager#isSafetyCenterEnabled() (no es necesario para las fuentes del Centro de seguridad, solo necesitan el permiso SEND_SAFETY_CENTER_UPDATE )
    • Utilizado por aplicaciones del sistema que verifican si el Centro de seguridad está habilitado
    • Otorgado solo a aplicaciones del sistema incluidas en la lista permitida
  • SEND_SAFETY_CENTER_UPDATE
    • internal|privileged
    • Se utiliza para la API habilitada y la API de fuentes de seguridad.
    • Utilizado únicamente por fuentes de seguridad.
    • Otorgado solo a aplicaciones del sistema incluidas en la lista permitida

Estos permisos son privilegiados y puede adquirirlos solo agregándolos al archivo relevante, por ejemplo, el archivo com.android.settings.xml para la aplicación Configuración y al archivo AndroidManifest.xml de la aplicación. Consulte protectionLevel para obtener más información sobre el modelo de permiso.

Obtenga el SafetyCenterManager

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

Compruebe si el Centro de seguridad está habilitado

Esta llamada verifica si el Centro de seguridad está habilitado. La llamada requiere el permiso READ_SAFETY_CENTER_STATUS o SEND_SAFETY_CENTER_UPDATE :

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

Proveer información

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

  • SEVERITY_LEVEL_UNSPECIFIED
    • No se especifica gravedad
    • Color: Gris o transparente (dependiendo del SafetySourcesGroup de la entrada)
    • Se utiliza para datos dinámicos que se presentan como una entrada estática en la interfaz de usuario o para mostrar una entrada no especificada.
    • No debe usarse para tarjetas de advertencia.
  • SEVERITY_LEVEL_INFORMATION
    • Información básica o sugerencia menor.
    • Color verde
  • SEVERITY_LEVEL_RECOMMENDATION
    • Recomendación de que el usuario tome medidas sobre este tema, ya que podría ponerlo en riesgo
    • Color amarillo
  • SEVERITY_LEVEL_CRITICAL_WARNING
    • Advertencia crítica de que el usuario debe tomar medidas sobre este tema, ya que presenta un riesgo.
    • Color rojo

SafetySourceData

El objeto SafetySourceData se compone de una entrada de interfaz de usuario, tarjetas de advertencia e invariantes.

  • Instancia opcional SafetySourceStatus (entrada de interfaz de usuario)
  • Lista de instancias SafetySourceIssue (tarjetas de advertencia)
  • Extras Bundle opcional (a partir de 14)
  • Invariantes:
    • La lista SafetySourceIssue debe estar compuesta de problemas con identificadores únicos.
    • La instancia SafetySourceIssue no debe ser de mayor importancia que SafetySourceStatus si existe (a menos que SafetySourceStatus sea SEVERITY_LEVEL_UNSPECIFIED , en cuyo caso se permiten problemas SEVERITY_LEVEL_INFORMATION ).
    • Se deben cumplir requisitos adicionales impuestos por la configuración de API; por ejemplo, si la fuente es solo para problemas, no debe proporcionar una instancia SafetySourceStatus .

SafetySourceStatus

  • Título CharSequence requerido
  • Resumen CharSequence requerido
  • Nivel de gravedad requerido
  • Instancia opcional PendingIntent para redirigir al usuario a la página correcta (el valor predeterminado usa intentAction de la configuración, si corresponde)
  • IconAction opcional (que se muestra como un ícono lateral en la entrada) compuesto por:
    • Tipo de icono requerido, que debe ser uno de los siguientes tipos:
      • ICON_TYPE_GEAR : se muestra como un engranaje junto a la entrada de la interfaz de usuario.
      • ICON_TYPE_INFO : se muestra como un icono de información junto a la entrada de la interfaz de usuario.
    • Se requiere PendingIntent para redirigir al usuario a otra página
  • Valor booleano enabled opcional que permite marcar la entrada de la interfaz de usuario como deshabilitada, por lo que no se puede hacer clic en ella (el valor predeterminado es true )
  • Invariantes:
    • Las instancias PendingIntent deben abrir una instancia Activity .
    • Si la entrada está deshabilitada, debe designarse SEVERITY_LEVEL_UNSPECIFIED .
    • Requisitos adicionales impuestos por la configuración de API.

SafetySourceIssue

  • Identificador String único requerido
  • Título CharSequence requerido
  • Subtítulo opcional CharSequence
  • Resumen CharSequence requerido
  • Nivel de gravedad requerido
  • Categoría de emisión opcional, que debe ser una de:
    • ISSUE_CATEGORY_DEVICE : el problema afecta el dispositivo del usuario.
    • ISSUE_CATEGORY_ACCOUNT : El problema afecta las cuentas del usuario.
    • ISSUE_CATEGORY_GENERAL : El problema afecta la seguridad general del usuario. Este 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 las contraseñas del usuario.
    • ISSUE_CATEGORY_PERSONAL_SAFETY (a partir de Android 14): el problema afecta la seguridad personal del usuario.
  • Lista de elementos Action que el usuario puede tomar para este problema, estando cada instancia Action compuesta por:
    • Identificador String único requerido
    • Etiqueta CharSequence requerida
    • Se requiere PendingIntent para redirigir 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 del Centro de seguridad (el valor predeterminado es false )
    • Mensaje de éxito CharSequence opcional, que se mostrará al usuario cuando el problema se resuelva exitosamente directamente desde la pantalla del Centro de seguridad
  • PendingIntent opcional que se llama cuando el usuario descarta el problema (el valor predeterminado es no llamar a nada)
  • Requerido Identificador de tipo de problema String ; Esto es similar al identificador de problema, pero no tiene que ser único y se usa para iniciar sesión.
  • String opcional para la identificación de deduplicación, esto permite publicar el mismo SafetySourceIssue de diferentes fuentes y mostrarlo solo una vez en la interfaz de usuario, suponiendo que tengan el mismo deduplicationGroup (a partir de Android 14). Si no se especifica, el problema nunca se deduplica
  • CharSequence opcional para el título de atribución, este es un texto que muestra dónde se originó la tarjeta de advertencia (a partir de Android 14). Si no se especifica, utiliza el título de SafetySourcesGroup
  • Capacidad de resolución de problemas opcional (a partir de Android 14), que debe ser una de las siguientes:
    • ISSUE_ACTIONABILITY_MANUAL : el usuario debe resolver este problema manualmente. Este es el valor predeterminado.
    • ISSUE_ACTIONABILITY_TIP : este problema es solo un consejo y es posible que no requiera ninguna intervención del usuario.
    • ISSUE_ACTIONABILITY_AUTOMATIC : este problema ya se ha solucionado y es posible que no requiera ninguna intervención del usuario.
  • Comportamiento de notificación opcional (a partir de Android 14), que debe ser uno de:
    • NOTIFICATION_BEHAVIOR_UNSPECIFIED : El Centro de seguridad decidirá si se necesita una notificación para la tarjeta de advertencia. Este es el valor predeterminado.
    • NOTIFICATION_BEHAVIOR_NEVER : No se publica ninguna notificación.
    • NOTIFICATION_BEHAVIOR_DELAYED : se publica una notificación algún tiempo después de que se informa el problema por primera vez.
    • NOTIFICATION_BEHAVIOR_IMMEDIATELY : se publica una notificación tan pronto como 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, la Notification se deriva de la tarjeta de advertencia. Compuesto de:
    • Título CharSequence requerido
    • Resumen CharSequence requerido
    • Lista de elementos Action que el usuario puede realizar para esta notificación
  • Invariantes:
    • La lista de instancias Action debe estar compuesta de acciones con identificadores únicos.
    • La lista de instancias Action debe contener uno o dos elementos Action . Si la capacidad de acción no es ISSUE_ACTIONABILITY_MANUAL , se permite tener cero Action .
    • El OnDismiss PendingIntent no debe abrir una instancia Activity
    • Requisitos adicionales impuestos por la configuración API

Los datos se proporcionan sobre ciertos eventos al Centro de seguridad, por lo que es necesario especificar qué causó que la fuente proporcionara SafetySourceData una instancia SafetyEvent .

SafetyEvent

  • Tipo requerido, que debe ser uno de:
    • SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED : El estado de la fuente ha cambiado.
    • SAFETY_EVENT_TYPE_REFRESH_REQUESTED : Respondiendo a una señal de actualización/reexploración del Centro de seguridad; use esto en lugar de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para que Safety Center pueda realizar un seguimiento de la solicitud de actualización/rescaneo.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED : Resolvimos SafetySourceIssue.Action directamente desde la pantalla del Centro de seguridad; use esto en lugar de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para que Safety Center pueda realizar un seguimiento del SafetySourceIssue.Action que se está resolviendo.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : Intentamos resolver SafetySourceIssue.Action directamente desde la pantalla del Centro de seguridad, pero no pudimos hacerlo; use esto en lugar de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para que Safety Center pueda rastrear el error SafetySourceIssue.Action .
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : el idioma del dispositivo ha cambiado, por lo que estamos actualizando el texto de los datos proporcionados; está permitido 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 durante los reinicios; está permitido usar SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para esto.
  • Identificador String opcional para el ID de transmisión de actualización.
  • Identificador String opcional para la instancia SafetySourceIssue que se resuelve.
  • Identificador String opcional para la instancia SafetySourceIssue.Action que se resuelve.
  • Invariantes:
    • Se debe proporcionar el ID de transmisión de actualización si el tipo es SAFETY_EVENT_TYPE_REFRESH_REQUESTED
    • Se deben proporcionar los ID del problema y la 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 caso, proporciona una entrada con una única 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

Puede obtener los últimos datos proporcionados al Centro de seguridad para una fuente propiedad de su aplicación. Puede usar esto para mostrar algo en su propia interfaz de usuario, para verificar si es necesario actualizar los datos antes de realizar una operación costosa o para proporcionar la misma instancia SafetySourceData al Centro de seguridad con algunos cambios o con una nueva instancia SafetyEvent . También es útil para realizar pruebas.

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

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

Informar un error

Si no puede recopilar datos SafetySourceData , puede informar el error al Centro de seguridad, que cambia la entrada a gris, borra los datos almacenados en caché y proporciona un mensaje parecido a No se pudo verificar la configuración . También puede informar un error si una instancia de SafetySourceIssue.Action no se resuelve, en cuyo caso los datos almacenados en caché no se borran y la entrada de la interfaz de usuario no se modifica; pero aparece un mensaje al usuario para informarle que algo salió mal.

Puede proporcionar el error utilizando SafetySourceErrorDetails , que se compone de:

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

Responder a una solicitud de actualización o reexploración

Puede recibir una señal del Centro de seguridad para proporcionar nuevos datos. Responder a una solicitud de actualización o reescaneo garantiza que el usuario vea el estado actual al abrir el Centro de seguridad y cuando toque el botón de escaneo.

Esto se hace recibiendo 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 para una aplicación determinada.
    • Intento protegido que solo puede ser enviado por el sistema
    • Se envía a todas las fuentes de seguridad en el archivo de configuración como intención explícita y requiere el permiso SEND_SAFETY_CENTER_UPDATE

Los siguientes extras se proporcionan como parte de esta transmisión:

  • EXTRA_REFRESH_SAFETY_SOURCE_IDS
    • Valor de cadena: android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
    • Tipo de matriz de cadena ( String[] ), representa los ID de origen que se actualizarán para la aplicación determinada
  • EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE

    • Valor de cadena: android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
    • Tipo entero, representa un tipo de solicitud @IntDef
    • Debe ser uno de:
      • EXTRA_REFRESH_REQUEST_TYPE_GET_DATA : solicita a la fuente que proporcione datos relativamente rápido, normalmente cuando el usuario abre la página.
      • EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA : solicita a la fuente que proporcione datos lo más actualizados posible, generalmente cuando el usuario presiona el botón de volver a escanear.
  • 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, implemente una instancia BroadcastReceiver . La transmisión se envía con BroadcastOptions especiales que permiten al receptor 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 en el 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>

Idealmente, una fuente de Safety Center se implementa de tal manera que llame SafetyCenterManager cuando cambien sus datos. Por razones de salud del sistema, recomendamos responder solo a la señal de volver a escanear (cuando el usuario toca el botón de escaneo) y no cuando el usuario abre el Centro de seguridad. Si se requiere esta funcionalidad, se debe configurar el campo refreshOnPageOpenAllowed="true" en el archivo de configuración para que la fuente reciba la transmisión entregada en estos casos.

Responder al Centro de seguridad cuando esté habilitado o deshabilitado

Puede responder cuando el Centro de seguridad está habilitado o deshabilitado mediante esta acción de intención:

  • 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 deshabilitado mientras el dispositivo está en ejecución
    • No se llama al arrancar (use ACTION_BOOT_COMPLETED para eso)
    • Intento protegido que solo puede ser enviado por el sistema
    • Enviado a todas las fuentes de seguridad en el archivo de configuración como una intención explícita, requiere el permiso SEND_SAFETY_CENTER_UPDATE
    • Enviado como una intención implícita que requiere el permiso READ_SAFETY_CENTER_STATUS

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

Implementar acciones resolutivas

Una acción de resolución es una instancia SafetySourceIssue.Action que un usuario puede resolver directamente desde la pantalla del Centro de seguridad. El usuario toca un botón de acción y se activa la instancia PendingIntent en SafetySourceIssue.Action enviada por la fuente de seguridad, lo que resuelve el problema en segundo plano y notifica al Centro de seguridad cuando termina.

Para implementar acciones de resolución, la fuente del Centro de seguridad puede usar un servicio si se espera que la operación demore algún tiempo ( PendingIntent.getService ) o un receptor de transmisión ( PendingIntent.getBroadcast ).

Utilice 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 en el 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>

Responder a los despidos

Puede especificar una instancia PendingIntent que se puede activar cuando se descarta una instancia SafetySourceIssue . El Centro de Seguridad maneja estos despidos por problemas:

  • Si una fuente informa un problema, un usuario puede descartarlo en la pantalla del Centro de seguridad tocando el botón descartar (un botón X en la tarjeta de advertencia).
  • Cuando un usuario descarta un problema, si el problema continúa, no volverá a aparecer en la interfaz de usuario.
  • Los despidos persistentes en un disco permanecen durante los reinicios del dispositivo.
  • Si la fuente del Centro de seguridad deja de proporcionar un problema y luego lo vuelve a proporcionar más adelante, el problema vuelve a surgir. Esto es para permitir situaciones en las que un usuario ve una advertencia, la descarta y luego toma medidas que deberían aliviar el problema, pero luego el usuario vuelve a hacer algo que causa un problema similar. En este punto, la tarjeta de advertencia debería resurgir.
  • Las tarjetas de advertencia amarillas y rojas reaparecen cada 180 días, a menos que el usuario las haya ignorado varias veces.

La fuente no debería necesitar comportamientos adicionales a menos que:

  • La fuente intenta implementar este comportamiento de manera diferente, por ejemplo, nunca resurgir el problema.
  • La fuente intenta utilizar esto como devolución de llamada, por ejemplo, para registrar la información.

Proporcionar datos para múltiples usuarios/perfiles

La API SafetyCenterManager se puede utilizar entre usuarios y perfiles. Para obtener más información, consulte Creación de aplicaciones multiusuario . El objeto Context que proporciona SafetyCenterManager está asociado con una instancia UserHandle , por lo que la instancia SafetyCenterManager devuelta interactúa con el Centro de seguridad para esa instancia UserHandle . De forma predeterminada, Context está asociado con el usuario que ejecuta, pero es posible crear una instancia para otro usuario si la aplicación tiene los permisos INTERACT_ACROSS_USERS e INTERACT_ACROSS_USERS_FULL . Este ejemplo muestra cómo realizar una llamada entre usuarios/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 fusiona los datos de todos los perfiles administrados asociados con un usuario determinado.

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

  • Hay una entrada de interfaz de usuario para el usuario (perfil principal) y todos sus perfiles administrados asociados (que usan instancias titleForWork ).
  • La señal de actualización o reexploración se envía para el perfil principal y todos los perfiles administrados asociados. El receptor asociado se inicia para cada perfil y puede proporcionar los datos asociados directamente a SafetyCenterManager sin tener que realizar una llamada entre perfiles a menos que el receptor o la aplicación sea singleUser .

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

Pruebas

puede acceder ShadowSafetyCenterManager y utilizarlo en una prueba 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);
}

Puede escribir más pruebas de un extremo a otro (E2E), pero eso está fuera del alcance de esta guía. Para obtener más información sobre cómo escribir estas pruebas E2E, consulte Pruebas CTS (CtsSafetyCenterTestCases)

API de prueba y internas

Las API internas y las API de prueba son para uso interno, por lo que no se describen en detalle en esta guía. Sin embargo, es posible que ampliemos algunas API internas en el futuro para permitir que los OEM creen su propia interfaz de usuario y actualizaremos esta guía para brindar orientación sobre cómo usarlas.

Permisos

  • MANAGE_SAFETY_CENTER
    • internal|installer|role
    • Se utiliza para las API internas del Centro de seguridad
    • Sólo concedido a PermissionController y Shell

Aplicación de configuración

Redirección del centro de seguridad

De forma predeterminada, se accede al Centro de seguridad a través de la aplicación Configuración con una nueva entrada de Seguridad y privacidad . Si usa una aplicación de Configuración diferente o si modificó la aplicación de Configuración, es posible que deba personalizar cómo se accede al Centro de seguridad.

Cuando el Centro de seguridad está habilitado:

  • La entrada de privacidad heredada es un código oculto
  • La entrada de seguridad heredada es un código oculto
  • Se agrega un nuevo código de entrada de Seguridad y privacidad
  • La nueva entrada de Seguridad y privacidad redirige al código del Centro de seguridad
  • Las acciones de intención android.settings.PRIVACY_SETTINGS y android.settings.SECURITY_SETTINGS se redirigen para abrir el Centro de seguridad (código: seguridad , privacidad ).

Páginas avanzadas de seguridad y privacidad

La aplicación Configuración contiene configuraciones adicionales en Más configuraciones de seguridad y Más títulos de configuraciones de privacidad , disponibles en el Centro de seguridad:

Fuentes de seguridad

Safety Center se integra con un conjunto específico de fuentes de seguridad proporcionadas por la aplicación Configuración:

  • Una fuente de seguridad de la pantalla de bloqueo verifica que la pantalla de bloqueo esté configurada con un código de acceso (u otro tipo de seguridad) para garantizar que la información privada del usuario se mantenga a salvo del acceso externo.
  • Aparece una fuente de seguridad biométrica (oculta de forma predeterminada) para integrarse con un sensor facial o de huellas dactilares.

Se puede acceder al código fuente de estas fuentes del Centro de seguridad mediante la búsqueda de código de Android . Si la aplicación Configuración no se modifica (no se realizan cambios en el nombre del paquete, el código fuente o el código fuente que trata con una pantalla de bloqueo y datos biométricos), entonces esta integración debería funcionar de inmediato. De lo contrario, es posible que se requieran algunas modificaciones, como cambiar el archivo de configuración para cambiar el nombre del paquete de la aplicación Configuración y las fuentes que se integran con Safety Center, así como la integración. Para obtener más información, consulte Actualizar el archivo de configuración y los ajustes de integración .

Acerca de la intención pendiente

Si confía en la integración existente del Centro de seguridad de la aplicación Configuración en Android 14 o superior, se solucionó el error que se describe a continuación. En este caso no es necesario leer esta sección.

Cuando esté seguro de que el error no existe, establezca un valor de configuración de recurso booleano XML en la aplicación Configuración config_isSafetyCenterLockScreenPendingIntentFixed en true para desactivar la solución alternativa dentro del Centro de seguridad.

Solución alternativa de intención pendiente

Este error se debe a que la Configuración utiliza extras de instancia Intent para determinar qué fragmento abrir. Debido a que Intent#equals no tiene en cuenta los extras de la instancia Intent , la instancia PendingIntent para el icono del menú de ajustes y la entrada se consideran iguales y navegan a la misma interfaz de usuario (aunque estén destinadas a navegar a una interfaz de usuario diferente). Este problema se solucionó en una versión de QPR al diferenciar las instancias PendingIntent por código de solicitud. Alternativamente, esto podría diferenciarse usando Intent#setId .

Fuentes de seguridad internas

Algunas fuentes del Centro de seguridad son internas y se implementan en la aplicación del sistema PermissionController dentro del módulo PermissionController. Estas fuentes se comportan como fuentes habituales del Centro de seguridad y no reciben ningún tratamiento especial. El código de estas fuentes está disponible a través de la búsqueda de códigos de Android .

Se trata principalmente de señales de privacidad, por ejemplo:

  • Accesibilidad
  • Revocar automáticamente aplicaciones no utilizadas
  • Acceso a la ubicación
  • Oyente de notificaciones
  • Información de política laboral