Redireccionar al Centro de seguridad
Cualquier app puede abrir el Centro de seguridad con la 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);
Redirecciona 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íficos. Estos elementos adicionales no están diseñados para que los usen terceros, por lo que forman parte de SafetyCenterManager
, que forma 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 asociada.
- Obligatorio para que funcione el redireccionamiento al problema
- Valor de cadena:
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
- Valor de cadena:
EXTRA_SAFETY_SOURCE_USER_HANDLE
- Valor de cadena:
android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
- Tipo
UserHandle
: EspecificaUserHandle
para la advertencia asociada. tarjeta - Opcional (el valor predeterminado es el usuario actual)
- Valor de cadena:
El siguiente fragmento de código se puede usar desde una instancia de Activity
para abrir la pantalla del Centro de seguridad en 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 que se pueden contraer).
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
- Valor de cadena:
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 de Safety Center están disponibles con SafetyCenterManager
(que es un @SystemApi
). El código de la plataforma de la API está disponible en Búsqueda de código.
El código de implementación de las APIs está disponible en Code Search.
Permisos
Solo las apps del sistema incluidas en la lista de entidades permitidas pueden acceder a las APIs de origen de Safety Center con los permisos que se indican a continuación. Para obtener más información, consulta Inclusión de permisos con privilegios en la lista de entidades permitidas.
READ_SAFETY_CENTER_STATUS
signature|privileged
- Se usa para la API de
SafetyCenterManager#isSafetyCenterEnabled()
(no necesarias para las fuentes del Centro de seguridad, solo necesitanSEND_SAFETY_CENTER_UPDATE
) - Lo usan las apps del sistema que verifican si el Centro de seguridad está habilitado.
- Solo se otorga 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.
Obtén SafetyCenterManager
SafetyCenterManager
es una clase @SystemApi
a la que se puede acceder desde las apps del sistema.
a partir de Android 13. En esta llamada, se muestra 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;
}
Cómo verificar si el Centro de seguridad está habilitado
Esta llamada verifica si se habilitó el Centro de seguridad. La llamada requiere el permiso READ_SAFETY_CENTER_STATUS
o SEND_SAFETY_CENTER_UPDATE
:
boolean isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled();
if (isSafetyCenterEnabled) {
// …
} else {
// …
}
Proporciona datos
Los datos de origen de Safety Center con el String sourceId
determinado se proporcionan a Safety Center con el objeto SafetySourceData
, que representa una entrada de la IU y 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 el
SafetySourcesGroup
de la 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 importante que indica que el usuario debe tomar medidas con respecto a este problema, ya que representa 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) - Invarianzas:
- La lista
SafetySourceIssue
debe incluir problemas con bases de datos identificadores. - La instancia de
SafetySourceIssue
no debe ser más importante queSafetySourceStatus
si hay una (a menos queSafetySourceStatus
seaSEVERITY_LEVEL_UNSPECIFIED
, en cuyo caso se permiten problemas deSEVERITY_LEVEL_INFORMATION
). - Se deben cumplir los requisitos adicionales que impone la configuración de la API. Por ejemplo, si la fuente solo tiene problemas, no debe proporcionar una instancia de
SafetySourceStatus
.
- La lista
SafetySourceStatus
- Título
CharSequence
obligatorio - Resumen obligatorio de
CharSequence
- Nivel de gravedad requerido
- Opcional
PendingIntent
para redireccionar al usuario a la página correcta (la configuración predeterminada usaintentAction
desde la configuración, si corresponde) IconAction
opcional (se muestra como un ícono lateral en la entrada) que consta de lo siguiente:- Es el tipo de ícono obligatorio, que debe ser uno de los siguientes:
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
- Es el tipo de ícono obligatorio, que debe ser uno de los siguientes:
- Es un valor booleano
enabled
opcional que permite marcar la entrada de la IU como inhabilitada, de modo que no se pueda hacer clic en ella (el valor predeterminado estrue
). - Invariantes:
- Las instancias
PendingIntent
deben abrir una instanciaActivity
. - Si la entrada está inhabilitada, se debe designar
SEVERITY_LEVEL_UNSPECIFIED
- Son requisitos adicionales que impone la configuración de la API.
- Las instancias
SafetySourceIssue
- Identificador único obligatorio de
String
- Título
CharSequence
obligatorio - Subtítulo
CharSequence
opcional - Resumen obligatorio de
CharSequence
- Nivel de gravedad requerido
- Categoría del 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 seguridad personal del usuario.
- Lista de elementos
Action
que el usuario puede tomar para este problema, cada uno InstanciaAction
que se compone de lo siguiente:- Es el identificador
String
único obligatorio. - 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
- Es el identificador
- Opcional
PendingIntent
a la que se llama cuando el usuario descarta el problema (el valor predeterminado es llama) - Es el identificador de tipo de error
String
obligatorio, que es similar al identificador de error, pero no tiene que ser único y se usa para el registro. String
opcional para el ID de anulación de duplicación. Esto permite publicar el mismoSafetySourceIssue
desde diferentes fuentes y mostrarlo solo una vez en la IU, siempre que tengan el mismodeduplicationGroup
(a partir de Android 14). Si no se especifica, el problema nunca se con anulación de duplicaciónCharSequence
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, usa el título de laSafetySourcesGroup
.- Accesibilidad opcional al problema (a partir de Android 14), que debe ser una de las siguientes opciones:
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 ninguna entrada del usuario.ISSUE_ACTIONABILITY_AUTOMATIC
: Este problema ya se solucionó 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
: Safety Center decidirá si se necesita una notificación para la tarjeta de advertencia. Es el valor predeterminado.NOTIFICATION_BEHAVIOR_NEVER
: No se publica ninguna notificación.NOTIFICATION_BEHAVIOR_DELAYED
: Se publica una notificación un tiempo después de que se informa 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, elNotification
se deriva de la tarjeta de advertencia. Se compone de lo siguiente:- Título
CharSequence
obligatorio - Resumen obligatorio de
CharSequence
- Lista de elementos
Action
que el usuario puede tomar para esta notificación
- Título
- Invarianzas:
- La lista de instancias de
Action
debe estar compuesta por acciones con identificadores únicos. - La lista de instancias de
Action
debe contener uno o dos elementosAction
. Si la capacidad de acción no esISSUE_ACTIONABILITY_MANUAL
, no se permite tener un valor deAction
. - El elemento OnDismiss
PendingIntent
no debe abrir una instancia deActivity
- Requisitos adicionales que impone la configuración de la API
- La lista de instancias de
Los datos se proporcionan a Safety Center en ciertos eventos, por lo que es necesario especificar qué causó que la fuente le proporcionara a SafetySourceData
una instancia de SafetyEvent
.
SafetyEvent
- Es el tipo obligatorio, que debe ser uno de los siguientes:
SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
: Cambió el estado de la fuente.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 deSAFETY_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 resolvimosSafetySourceIssue.Action
directamente desde la pantalla del Centro de seguridad. usar esto en lugar deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
por Seguridad Centro para poder realizar un seguimiento de la resolución deSafetySourceIssue.Action
.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
: Intentamos solucionar el problemaSafetySourceIssue.Action
directamente desde la pantalla del Centro de seguridad, pero no lo lograste; usar esto en lugar deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para que el Centro de seguridad pueda ha fallado la pistaSafetySourceIssue.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 usarSAFETY_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 se conservan durante los reinicios. Se permite usarSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para esto.
- Es el identificador
String
opcional para el ID de transmisión de actualización. - Es el identificador
String
opcional para la instanciaSafetySourceIssue
que se resuelve. - Identificador
String
opcional para la instanciaSafetySourceIssue.Action
que se está resolviendo. - Invarianzas:
- 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
oSAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
- Se debe proporcionar el ID de actualización de la transmisión si el tipo es
A continuación, se muestra un ejemplo de cómo una fuente puede proporcionar datos a Safety Center (en este caso, proporciona 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 proporcionados a Safety Center para una fuente que sea propiedad de tu app. Puedes usarlos para mostrar algo en tu propia IU, para verificar si los datos deben actualizarse antes de realizar una operación costosa o para proporcionar la misma instancia de SafetySourceData
a Safety Center con algunos cambios o con una instancia de SafetyEvent
nueva. También es útil para 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
, puedes informar el error a Safety Center, que cambia la entrada a gris, borra los datos almacenados en caché y muestra un mensaje similar a No se pudo verificar la configuración. También puedes informar un error si una instancia de SafetySourceIssue.Action
no se resuelve, en cuyo caso no se borran los datos almacenados en caché ni se cambia la entrada de la IU, pero se muestra un mensaje al usuario para informarle que se produjo un error.
Puedes proporcionar el error con SafetySourceErrorDetails
, que se compone de lo siguiente:
SafetySourceErrorDetails
: Instancia deSafetyEvent
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 análisis
Puedes recibir una señal del Centro de seguridad para proporcionar datos nuevos. Responder a una solicitud de actualización o de nuevo análisis garantiza que el usuario vea el estado actual cuando abra el Centro de seguridad y cuando presione el botón de análisis.
Para ello, 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 Safety Center 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 explícito y requiere el permiso
SEND_SAFETY_CENTER_UPDATE
.
- Valor de cadena:
Como parte de esta transmisión, se proporcionan los siguientes extras:
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
- Valor de cadena:
EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
- Valor de cadena:
android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
- Es un tipo de número entero que representa un tipo de solicitud
@IntDef
. - Debe ser una de las siguientes opciones:
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
- Valor de cadena:
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
- Valor de cadena:
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
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>
Lo ideal es que una fuente de Safety Center se implemente de manera tal que llame a SafetyCenterManager
cuando cambien sus datos. Por motivos de estado del sistema, te recomendamos que respondas solo a la señal de nuevo análisis (cuando el usuario presiona el botón de análisis) y no cuando abre 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 esta 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
- Valor de cadena:
Esta acción de intent es útil para habilitar o inhabilitar funciones relacionadas con Safety Center 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 se activa la instancia de PendingIntent
en SafetySourceIssue.Action
que envió la fuente de seguridad, lo que resuelve el problema en segundo plano y notifica al Centro de seguridad cuando se completa.
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 tome un tiempo (PendingIntent.getService
) o un
receptor de emisión (PendingIntent.getBroadcast
).
Usa este código para enviar un problema resuelto a 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
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>
Cómo responder a los descartes de problemas
Puedes especificar una instancia de PendingIntent
que se puede activar cuando se descarta una instancia de SafetySourceIssue
. El Centro de seguridad se encarga de estos problemas
descartes:
- Si una fuente envía un problema, el usuario puede descartarlo en la pantalla del Centro de seguridad presionando el botón de descarte (un botón con la letra X en la tarjeta de advertencia).
- Cuando un usuario descarta un problema, si este persiste, no se mostrará nuevamente en la IU.
- Los rechazos persistentes en un disco permanecen durante los reinicios del dispositivo.
- Si la fuente de Safety Center deja de proporcionar un problema y, luego, vuelve a proporcionarlo más adelante, el problema reaparecerá. 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 haya las descarté varias veces.
La fuente no debería necesitar comportamientos adicionales, a menos que se cumplan las siguientes condiciones:
- 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 la información.
Proporciona datos para varios usuarios o perfiles
La API de SafetyCenterManager
se puede usar con usuarios y perfiles. Para ver más
consulta Cómo compilar Multiuser-Aware
Apps. El objeto Context
que proporciona SafetyCenterManager
está asociado con una instancia de UserHandle
, por lo que la instancia de SafetyCenterManager
que se muestra interactúa con el Centro de seguridad de esa instancia de 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 entre 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. Safety Center proporciona datos diferentes para cada usuario, pero combina los datos de todos los perfiles administrados asociados con un usuario determinado.
Cuando se configura profile="all_profiles"
para la fuente en el archivo de configuración,
ocurre lo siguiente:
- Hay una entrada de IU para el usuario (elemento superior del perfil) y todos sus perfiles administrados asociados (que usan instancias de
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 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 app seansingleUser
.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 eso está fuera del alcance de esta guía. 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 de prueba son para uso interno, por lo que no se describen en detalle en esta guía. Sin embargo, es posible que extendamos algunas APIs internas en el futuro para permitir que los OEMs creen su propia IU a partir de ellas. Actualizaremos esta guía para brindar orientación sobre cómo usarlas.
Permisos
MANAGE_SAFETY_CENTER
internal|installer|role
- Se usa para las APIs internas de Safety Center
- Solo se otorga al PermissionController y a la shell.
App de Configuración
Redirección del Centro de seguridad
De forma predeterminada, se accede al Centro de seguridad a través de la app de Configuración con una nueva entrada Seguridad y privacidad. Si usas una app de Configuración diferente o si la modificaste, es posible que debas personalizar la forma en que se accede al Centro de seguridad.
Cuando Safety Center está habilitado, sucede lo siguiente:
- La entrada Privacidad heredada está oculta código
- La entrada heredada de Seguridad es un código oculto.
- Nueva seguridad y se agregó la entrada de privacidad código
- La nueva entrada Seguridad y privacidad redirecciona al código del Centro de seguridad.
- Las acciones de intent
android.settings.PRIVACY_SETTINGS
yandroid.settings.SECURITY_SETTINGS
se redireccionan para abrir el Centro de seguridad (código: security, privacy).
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:
Código de seguridad avanzado
Código de privacidad avanzado
A partir de Android 14, las funciones de seguridad la página de configuración de privacidad avanzada se fusionan en una sola página "Más seguridad y Privacidad página con acción de intent
"com.android.settings.MORE_SECURITY_PRIVACY_SETTINGS"
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.
- Se puede integrar una fuente de seguridad biométrica (oculta de forma predeterminada) con un sensor de huellas dactilares o el rostro.
Se puede acceder al código fuente de estas fuentes de Safety Center a través de la búsqueda de código de Android. 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, es posible que se requieran algunas modificaciones, como cambiar el archivo de configuración para cambiar el nombre del paquete de la app de Configuración y las fuentes que se integran con Safety Center, así como la integración. Para obtener más información, consulta Cómo actualizar el archivo de configuración y la configuración de integración.
Información acerca de PendingIntent
Si dependes de la integración existente de Safety Center en la app de Configuración en Android 14 o versiones posteriores, se corrigió el error que se describe 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 produce porque la configuración usa elementos adicionales de la instancia Intent
para determinar qué fragmento 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 Como alternativa, esto se podría diferenciar con Intent#setId
.
Fuentes de seguridad internas
Algunas fuentes de Safety Center son internas y se implementan en la app del sistema PermissionController dentro del módulo PermissionController. Estas fuentes se comportan como fuentes normales de Safety Center y no reciben ningún tratamiento especial. 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
- Cómo revocar automáticamente los permisos de las apps que no se usan
- Acceso a la ubicación
- Agente de escucha de notificaciones
- Información sobre la política de trabajo