Redirecionar para a Central de Segurança
Qualquer aplicativo pode abrir o Safety Center usando a ação android.content.Intent.ACTION_SAFETY_CENTER
(valor de string android.intent.action.SAFETY_CENTER
).
Para abrir o Safety Center, faça uma chamada de dentro de uma instância Activity
:
Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER);
startActivity(openSafetyCenterIntent);
Redirecionar para um problema específico
Também é possível redirecionar para um cartão de aviso específico do Safety Center usando extras de intenção específicos. Esses extras não devem ser usados por terceiros, portanto fazem parte do SafetyCenterManager
, que faz parte do @SystemApi
. Somente aplicativos do sistema podem acessar esses extras.
Extras de intenção que redirecionam um cartão de aviso específico:
-
EXTRA_SAFETY_SOURCE_ID
- Valor da string:
android.safetycenter.extra.SAFETY_SOURCE_ID
- Tipo de string: especifica o ID da fonte de segurança do cartão de advertência associado
- Necessário para que o redirecionamento para o problema funcione
- Valor da string:
-
EXTRA_SAFETY_SOURCE_ISSUE_ID
- Valor da string:
android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID
- Tipo de string: especifica o ID do cartão de aviso
- Necessário para que o redirecionamento para o problema funcione
- Valor da string:
-
EXTRA_SAFETY_SOURCE_USER_HANDLE
- Valor da string:
android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
- Tipo
UserHandle
: especificaUserHandle
para o cartão de aviso associado - Opcional (o padrão é o usuário atual)
- Valor da string:
O trecho de código abaixo pode ser usado em uma instância Activity
para abrir a tela da Central de segurança para um 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);
Redirecionar para uma subpágina específica (a partir do Android 14)
No Android 14 ou superior, a página Safety Center é dividida em várias subpáginas que representam os diferentes SafetySourcesGroup
(no Android 13, isso é mostrado como entradas recolhíveis).
É possível redirecionar para uma subpágina específica usando este intent extra:
-
EXTRA_SAFETY_SOURCES_GROUP_ID
- Valor da string:
android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
- Tipo de string: especifica o ID do
SafetySourcesGroup
- Necessário para que o redirecionamento para a subpágina funcione
- Valor da string:
O trecho de código abaixo pode ser usado em uma instância Activity
para abrir a tela da Central de segurança em uma subpágina específica:
Intent openSafetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER)
.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID, "TheSafetySourcesGroupId");
startActivity(openSafetyCenterIntent);
Use as APIs de origem do Safety Center
As APIs de origem do Safety Center estão disponíveis usando SafetyCenterManager
(que é um @SystemApi
). O código para a superfície da API está disponível no Code Search . O código de implementação das APIs está disponível no Code Search .
Permissões
As APIs de origem do Safety Center são acessíveis apenas por aplicativos do sistema permitidos usando as permissões listadas abaixo. Para obter informações adicionais, consulte Lista de permissões de permissões privilegiadas .
-
READ_SAFETY_CENTER_STATUS
-
signature|privileged
- Usado para a API
SafetyCenterManager#isSafetyCenterEnabled()
(não é necessário para fontes do Safety Center, eles só precisam da permissãoSEND_SAFETY_CENTER_UPDATE
) - Usado por aplicativos do sistema que verificam se a Central de Segurança está ativada
- Concedido apenas para aplicativos do sistema permitidos
-
-
SEND_SAFETY_CENTER_UPDATE
-
internal|privileged
- Usado para a API habilitada e a API Safety Sources
- Usado apenas por fontes de segurança
- Concedido apenas para aplicativos do sistema permitidos
-
Essas permissões são privilegiadas e você só pode adquiri-las adicionando-as ao arquivo relevante, por exemplo, o arquivo com.android.settings.xml
do aplicativo Configurações e ao arquivo AndroidManifest.xml
do aplicativo. Consulte protectionLevel
para obter mais informações sobre o modelo de permissão.
Obtenha o SafetyCenterManager
SafetyCenterManager
é uma classe @SystemApi
acessível em aplicativos do sistema a partir do Android 13. Esta chamada demonstra como obter o 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;
}
Verifique se a Central de Segurança está habilitada
Esta chamada verifica se o Safety Center está habilitado. A chamada requer a permissão READ_SAFETY_CENTER_STATUS
ou SEND_SAFETY_CENTER_UPDATE
:
boolean isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled();
if (isSafetyCenterEnabled) {
// …
} else {
// …
}
Forneça dados
Os dados de origem do Safety Center com a String sourceId
fornecida são fornecidos ao Safety Center com o objeto SafetySourceData
, que representa uma entrada de UI e uma lista de problemas (cartões de aviso). A entrada da UI e os cartões de aviso podem ter diferentes níveis de gravidade especificados na classe SafetySourceData
:
-
SEVERITY_LEVEL_UNSPECIFIED
- Nenhuma gravidade especificada
- Cor: Cinza ou transparente (dependendo do
SafetySourcesGroup
da entrada) - Usado para dados dinâmicos que se apresentam como uma entrada estática na IU ou para mostrar uma entrada não especificada
- Não deve ser usado para cartões de advertência
-
SEVERITY_LEVEL_INFORMATION
- Informações básicas ou pequenas sugestões
- Cor verde
-
SEVERITY_LEVEL_RECOMMENDATION
- Recomendação de que o usuário tome medidas em relação a esse problema, pois isso pode colocá-lo em risco
- Cor amarela
-
SEVERITY_LEVEL_CRITICAL_WARNING
- Aviso crítico de que o usuário deve tomar medidas sobre este problema, pois apresenta um risco
- Cor vermelha
SafetySourceData
O objeto SafetySourceData
é composto por uma entrada de UI, cartões de aviso e invariantes.
- Instância opcional
SafetySourceStatus
(entrada UI) - Lista de instâncias
SafetySourceIssue
(cartões de aviso) - Extras opcionais
Bundle
(a partir de 14) - Invariantes:
- A lista
SafetySourceIssue
deve ser composta por problemas com identificadores exclusivos. - A instância
SafetySourceIssue
não deve ser de maior importância queSafetySourceStatus
se houver uma (a menos queSafetySourceStatus
sejaSEVERITY_LEVEL_UNSPECIFIED
, caso em que problemasSEVERITY_LEVEL_INFORMATION
são permitidos). - Requisitos adicionais impostos pela configuração da API devem ser atendidos, por exemplo, se a fonte for somente de emissão, ela não deverá fornecer uma instância
SafetySourceStatus
.
- A lista
SafetySourceStatus
- Título
CharSequence
obrigatório - Resumo
CharSequence
obrigatório - Nível de gravidade necessário
- Instância opcional
PendingIntent
para redirecionar o usuário para a página correta (o padrão usaintentAction
da configuração, se houver) -
IconAction
opcional (mostrado como um ícone lateral na entrada) composto por:- Tipo de ícone obrigatório, que deve ser um dos seguintes tipos:
-
ICON_TYPE_GEAR
: mostrado como uma engrenagem ao lado da entrada da IU -
ICON_TYPE_INFO
: mostrado como um ícone de informações próximo à entrada da IU
-
-
PendingIntent
necessário para redirecionar o usuário para outra página
- Tipo de ícone obrigatório, que deve ser um dos seguintes tipos:
- Valor booleano
enabled
opcional que permite marcar a entrada da UI como desabilitada, portanto não é clicável (o padrão étrue
) - Invariantes:
- As instâncias
PendingIntent
devem abrir uma instânciaActivity
. - Se a entrada estiver desabilitada, ela deverá ser designada
SEVERITY_LEVEL_UNSPECIFIED
. - Requisitos adicionais impostos pela configuração da API.
- As instâncias
SafetySourceIssue
- Identificador
String
exclusivo obrigatório - Título
CharSequence
obrigatório - Legenda
CharSequence
opcional - Resumo
CharSequence
obrigatório - Nível de gravidade necessário
- Categoria de problema opcional, que deve ser uma das seguintes:
-
ISSUE_CATEGORY_DEVICE
: o problema afeta o dispositivo do usuário. -
ISSUE_CATEGORY_ACCOUNT
: o problema afeta as contas do usuário. -
ISSUE_CATEGORY_GENERAL
: o problema afeta a segurança geral do usuário. Este é o padrão. -
ISSUE_CATEGORY_DATA
(a partir do Android 14): o problema afeta os dados do usuário. -
ISSUE_CATEGORY_PASSWORDS
(a partir do Android 14): o problema afeta as senhas do usuário. -
ISSUE_CATEGORY_PERSONAL_SAFETY
(a partir do Android 14): o problema afeta a segurança pessoal do usuário.
-
- Lista de elementos
Action
que o usuário pode realizar para este problema, sendo cada instânciaAction
composta por:- Identificador
String
exclusivo obrigatório - Rótulo
CharSequence
obrigatório -
PendingIntent
necessário para redirecionar o usuário para outra página ou processar a ação diretamente na tela da Central de segurança - Booleano opcional para especificar se este problema pode ser resolvido diretamente na tela do Safety Center (o padrão é
false
) - Mensagem opcional de sucesso
CharSequence
, a ser exibida ao usuário quando o problema for resolvido com sucesso diretamente na tela do Safety Center
- Identificador
-
PendingIntent
opcional que é chamado quando o usuário descarta o problema (o padrão é que nada é chamado) - Obrigatório
String
identificador do tipo de problema; isso é semelhante ao identificador do problema, mas não precisa ser exclusivo e é usado para registro -
String
opcional para o ID de desduplicação, que permite postar o mesmoSafetySourceIssue
de diferentes fontes e mostrá-lo apenas uma vez na IU, presumindo que eles tenham o mesmodeduplicationGroup
(a partir do Android 14). Se não for especificado, o problema nunca será desduplicado -
CharSequence
opcional para o título da atribuição, este é um texto que mostra a origem do cartão de aviso (a partir do Android 14). Se não for especificado, usa o título doSafetySourcesGroup
- Ação opcional de problemas (a partir do Android 14), que deve ser um dos seguintes:
-
ISSUE_ACTIONABILITY_MANUAL
: O usuário precisa resolver esse problema manualmente. Este é o padrão. -
ISSUE_ACTIONABILITY_TIP
: Este problema é apenas uma dica e pode não exigir nenhuma entrada do usuário. -
ISSUE_ACTIONABILITY_AUTOMATIC
: Este problema já foi resolvido e pode não exigir nenhuma entrada do usuário.
-
- Comportamento de notificação opcional (a partir do Android 14), que deve ser um dos seguintes:
-
NOTIFICATION_BEHAVIOR_UNSPECIFIED
: O Safety Center decidirá se uma notificação é necessária para o cartão de aviso. Este é o padrão. -
NOTIFICATION_BEHAVIOR_NEVER
: Nenhuma notificação é postada. -
NOTIFICATION_BEHAVIOR_DELAYED
: uma notificação é postada algum tempo após o problema ser relatado pela primeira vez. -
NOTIFICATION_BEHAVIOR_IMMEDIATELY
: uma notificação é publicada assim que o problema é relatado.
-
-
Notification
opcional, para mostrar uma notificação personalizada com o cartão de aviso (a partir do Android 14). Se não for especificado, aNotification
será derivada do cartão de aviso. Composto de:- Título
CharSequence
obrigatório - Resumo
CharSequence
obrigatório - Lista de elementos
Action
que o usuário pode realizar para esta notificação
- Título
- Invariantes:
- A lista de instâncias
Action
deve ser composta por ações com identificadores únicos - A lista de instâncias
Action
deve conter um ou dois elementosAction
. Se a capacidade de ação não forISSUE_ACTIONABILITY_MANUAL
, é permitido ter zeroAction
. - O OnDismiss
PendingIntent
não deve abrir uma instânciaActivity
- Requisitos adicionais impostos pela configuração da API
- A lista de instâncias
Os dados são fornecidos em determinados eventos ao Safety Center, portanto, é necessário especificar o que fez com que a fonte fornecesse ao SafetySourceData
uma instância SafetyEvent
.
SafetyEvent
- Tipo obrigatório, que deve ser um dos seguintes:
-
SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
: O estado da origem foi alterado. -
SAFETY_EVENT_TYPE_REFRESH_REQUESTED
: respondendo a um sinal de atualização/nova varredura do Safety Center; use isso em vez deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para o Safety Center poder rastrear a solicitação de atualização/nova varredura. -
SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
: ResolvemosSafetySourceIssue.Action
diretamente na tela do Safety Center; use isso em vez deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para o Safety Center poder rastrear oSafetySourceIssue.Action
que está sendo resolvido. -
SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
: Tentamos resolverSafetySourceIssue.Action
diretamente na tela do Safety Center, mas não conseguimos; use isso em vez deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para que o Safety Center possa rastrear a falha deSafetySourceIssue.Action
. -
SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED
: O idioma do dispositivo mudou, por isso estamos atualizando o texto dos dados fornecidos; é permitido usarSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para isso. -
SAFETY_EVENT_TYPE_DEVICE_REBOOTED
: estamos fornecendo esses dados como parte de uma inicialização inicial, pois os dados do Safety Center não persistem durante as reinicializações; é permitido usarSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para isso.
-
- Identificador
String
opcional para o ID de transmissão de atualização. - Identificador
String
opcional para a instânciaSafetySourceIssue
sendo resolvida. - Identificador
String
opcional para a instânciaSafetySourceIssue.Action
sendo resolvida. - Invariantes:
- O ID de transmissão de atualização deverá ser fornecido se o tipo for
SAFETY_EVENT_TYPE_REFRESH_REQUESTED
- Os IDs de problema e ação deverão ser fornecidos se o tipo for
SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
ouSAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
- O ID de transmissão de atualização deverá ser fornecido se o tipo for
Abaixo está um exemplo de como uma fonte pode fornecer dados ao Safety Center (neste caso, fornece uma entrada com um único cartão de aviso):
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);
Obtenha os últimos dados fornecidos
Você pode obter os últimos dados fornecidos ao Safety Center de uma fonte pertencente ao seu aplicativo. Você pode usar isso para exibir algo em sua própria IU, para verificar se os dados precisam ser atualizados antes de executar uma operação cara ou para fornecer a mesma instância SafetySourceData
ao Safety Center com algumas alterações ou com uma nova instância SafetyEvent
. Também é útil para testes.
Use este código para obter os últimos dados fornecidos ao Safety Center:
SafetySourceData lastDataProvided = safetyCenterManager.getSafetySourceData("MySourceId");
Informar um erro
Se você não conseguir coletar dados SafetySourceData
, poderá relatar o erro ao Safety Center, que altera a entrada para cinza, limpa os dados armazenados em cache e fornece uma mensagem semelhante a Couldn't check setting . Você também pode relatar um erro se uma instância de SafetySourceIssue.Action
não for resolvida; nesse caso, os dados armazenados em cache não serão limpos e a entrada da UI não será alterada; mas uma mensagem é exibida ao usuário para informá-lo de que algo deu errado.
Você pode fornecer o erro usando SafetySourceErrorDetails
, que é composto por:
-
SafetySourceErrorDetails
: instânciaSafetyEvent
necessária :
// 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 uma solicitação de atualização ou nova verificação
Você pode receber um sinal da Central de Segurança para fornecer novos dados. Responder a uma solicitação de atualização ou nova verificação garante que o usuário visualize o status atual ao abrir o Safety Center e ao tocar no botão de verificação.
Isso é feito recebendo uma transmissão com a seguinte ação:
-
ACTION_REFRESH_SAFETY_SOURCES
- Valor da string:
android.safetycenter.action.REFRESH_SAFETY_SOURCES
- Acionado quando o Safety Center envia uma solicitação para atualizar os dados da fonte de segurança de um determinado aplicativo
- Intenção protegida que só pode ser enviada pelo sistema
- Enviado para todas as fontes de segurança no arquivo de configuração como uma intenção explícita e requer a permissão
SEND_SAFETY_CENTER_UPDATE
- Valor da string:
Os seguintes extras são fornecidos como parte desta transmissão:
-
EXTRA_REFRESH_SAFETY_SOURCE_IDS
- Valor da string:
android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS
- Tipo de matriz de string (
String[]
), representa os IDs de origem a serem atualizados para o aplicativo determinado
- Valor da string:
EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
- Valor da string:
android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
- Tipo inteiro, representa um tipo de solicitação
@IntDef
- Deve ser um dos:
-
EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
: solicita que a fonte forneça dados relativamente rápido, normalmente quando o usuário abre a página -
EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA
: solicita que a fonte forneça dados o mais atualizados possível, normalmente quando o usuário pressiona o botão de nova verificação
-
- Valor da string:
EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
- Valor da string:
android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
- Tipo string, representa um identificador exclusivo para a atualização solicitada
- Valor da string:
Para obter um sinal do Safety Center, implemente uma instância BroadcastReceiver
. A transmissão é enviada com BroadcastOptions
especiais que permitem ao receptor iniciar um serviço em primeiro plano.
BroadcastReceiver
responde a uma solicitação de atualização:
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;
}
}
A mesma instância de BroadcastReceiver
no exemplo acima é declarada em 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, uma fonte do Safety Center é implementada de forma que chame SafetyCenterManager
quando seus dados forem alterados. Por motivos de integridade do sistema, recomendamos responder apenas ao sinal de nova verificação (quando o usuário toca no botão de verificação) e não quando o usuário abre a Central de Segurança. Se esta funcionalidade for necessária, o campo refreshOnPageOpenAllowed="true"
no arquivo de configuração deverá ser definido para que a origem receba a transmissão entregue nesses casos.
Responder à Central de Segurança quando ativado ou desativado
Você pode responder quando a Central de Segurança for ativada ou desativada usando esta ação de intenção:
-
ACTION_SAFETY_CENTER_ENABLED_CHANGED
- Valor da string:
android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
- Acionado quando a Central de Segurança está ativada ou desativada enquanto o dispositivo está em execução
- Não chamado na inicialização (use
ACTION_BOOT_COMPLETED
para isso) - Intenção protegida que só pode ser enviada pelo sistema
- Enviado para todas as fontes de segurança no arquivo de configuração como uma intenção explícita, requer a permissão
SEND_SAFETY_CENTER_UPDATE
- Enviado como uma intenção implícita que requer a permissão
READ_SAFETY_CENTER_STATUS
- Valor da string:
Esta ação intencional é útil para ativar ou desativar recursos relacionados ao Safety Center no dispositivo.
Implementar ações de resolução
Uma ação de resolução é uma instância SafetySourceIssue.Action
que um usuário pode resolver diretamente na tela do Safety Center. O usuário toca em um botão de ação e a instância PendingIntent
em SafetySourceIssue.Action
enviada pela fonte de segurança é acionada, o que resolve o problema em segundo plano e notifica a Central de Segurança quando isso é concluído.
Para implementar ações de resolução, a origem do Safety Center pode usar um serviço se a operação demorar algum tempo ( PendingIntent.getService
) ou um receptor de transmissão ( PendingIntent.getBroadcast
).
Use este código para enviar uma solução de problema para o 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
resolve a ação:
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).
}
}
A mesma instância de BroadcastReceiver
no exemplo acima é declarada em 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 questões de demissões
Você pode especificar uma instância PendingIntent
que pode ser acionada quando uma instância SafetySourceIssue
é dispensada. O Centro de Segurança lida com estes problemas de dispensa:
- Se uma fonte apresentar um problema, o usuário poderá descartá-lo na tela do Safety Center tocando no botão descartar (um botão X no cartão de aviso).
- Quando um usuário descarta um problema, se o problema persistir, ele não aparecerá na IU novamente.
- As dispensas persistentes em um disco permanecem durante as reinicializações do dispositivo.
- Se a fonte do Safety Center parar de fornecer um problema e fornecê-lo novamente posteriormente, o problema reaparecerá. Isso permite situações em que um usuário vê um aviso, o ignora e, em seguida, executa uma ação que deve aliviar o problema, mas depois o usuário faz algo novamente que causa um problema semelhante. Neste ponto, o cartão de advertência deve ressurgir.
- Os cartões de aviso amarelos e vermelhos reaparecem a cada 180 dias, a menos que o usuário os tenha descartado várias vezes.
Comportamentos adicionais não devem ser necessários pela fonte, a menos que:
- A fonte tenta implementar esse comportamento de forma diferente, por exemplo, nunca ressurgindo o problema.
- A fonte tenta usar isso como retorno de chamada, por exemplo, para registrar as informações.
Fornece dados para vários usuários/perfis
A API SafetyCenterManager
pode ser usada entre usuários e perfis. Para obter mais informações, consulte Construindo aplicativos compatíveis com multiusuários . O objeto Context
que fornece SafetyCenterManager
está associado a uma instância UserHandle
, portanto, a instância SafetyCenterManager
retornada interage com o Safety Center para essa instância UserHandle
. Por padrão, Context
está associado ao usuário em execução, mas é possível criar uma instância para outro usuário se o aplicativo tiver as permissões INTERACT_ACROSS_USERS
e INTERACT_ACROSS_USERS_FULL
. Este exemplo mostra como fazer uma chamada entre usuários/perfis:
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 usuário no dispositivo pode ter vários perfis gerenciados. A Central de Segurança fornece dados diferentes para cada usuário, mas mescla os dados de todos os perfis gerenciados associados a um determinado usuário.
Quando profile="all_profiles"
é definido para a origem no arquivo de configuração, ocorre o seguinte:
- Há uma entrada de UI para o usuário (perfil pai) e todos os seus perfis gerenciados associados (que usam instâncias
titleForWork
). O sinal de atualização ou nova varredura é enviado para o perfil pai e todos os perfis gerenciados associados. O receptor associado é iniciado para cada perfil e pode fornecer os dados associados diretamente ao
SafetyCenterManager
sem precisar fazer uma chamada entre perfis, a menos que o receptor ou o aplicativo sejasingleUser
.Espera-se que a fonte forneça dados para o usuário e todos os seus perfis gerenciados. Os dados de cada entrada da UI podem ser diferentes dependendo do perfil.
Teste
você pode acessar ShadowSafetyCenterManager
e usá-lo em um teste 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);
}
Você pode escrever mais testes ponta a ponta (E2E), mas isso está fora do escopo deste guia. Para obter mais informações sobre como escrever esses testes E2E, consulte Testes CTS (CtsSafetyCenterTestCases)
Teste e APIs internas
As APIs internas e as APIs de teste são para uso interno, portanto não são descritas detalhadamente neste guia. No entanto, poderemos estender algumas APIs internas no futuro para permitir que os OEMs criem sua própria UI e atualizaremos este guia para fornecer orientações sobre como usá-las.
Permissões
-
MANAGE_SAFETY_CENTER
-
internal|installer|role
- Usado para APIs internas do Safety Center
- Concedido apenas para PermissionController e shell
-
Aplicativo de configurações
Redirecionamento da Central de Segurança
Por padrão, a Central de Segurança é acessada por meio do aplicativo Configurações com uma nova entrada Segurança e privacidade . Se você usar um aplicativo Configurações diferente ou se tiver modificado o aplicativo Configurações, talvez seja necessário personalizar a forma como a Central de Segurança é acessada.
Quando a Central de Segurança está ativada:
- A entrada de privacidade herdada é um código oculto
- A entrada de segurança herdada é um código oculto
- Nova entrada de segurança e privacidade com código adicionado
- Nova entrada de segurança e privacidade redireciona para o código do Safety Center
- As ações de intenção
android.settings.PRIVACY_SETTINGS
eandroid.settings.SECURITY_SETTINGS
são redirecionadas para abrir a Central de Segurança (código: security , privacidade )
Páginas avançadas de segurança e privacidade
O aplicativo Configurações contém configurações adicionais nos títulos Mais configurações de segurança e Mais configurações de privacidade , disponíveis na Central de segurança:
Código de segurança avançado
Código de privacidade avançado
A partir do Android 14, as páginas de configurações avançadas de segurança e privacidade são mescladas em uma única página "Mais segurança e privacidade" com a ação intencional
"com.android.settings.MORE_SECURITY_PRIVACY_SETTINGS"
Fontes de segurança
O Safety Center se integra a um conjunto específico de fontes de segurança fornecidas pelo aplicativo Configurações:
- Uma fonte de segurança da tela de bloqueio verifica se a tela de bloqueio está configurada com uma senha (ou outra segurança), para garantir que as informações privadas do usuário sejam mantidas protegidas contra acesso externo.
- Uma fonte de segurança biométrica (oculta por padrão) surge para integração com uma impressão digital ou sensor facial.
O código-fonte dessas fontes do Safety Center pode ser acessado por meio da pesquisa de código do Android . Se o aplicativo Configurações não for modificado (não forem feitas alterações no nome do pacote, no código-fonte ou no código-fonte que trata da tela de bloqueio e da biometria), essa integração deverá funcionar imediatamente. Caso contrário, algumas modificações poderão ser necessárias, como alterar o arquivo de configuração para alterar o nome do pacote do aplicativo Configurações e as fontes que se integram ao Safety Center, bem como a integração. Para obter mais informações, consulte Atualizar o arquivo de configuração e as configurações de integração .
Sobre PendingIntent
Se você confia na integração existente do aplicativo Configurações Safety Center no Android 14 ou superior, o bug descrito abaixo foi corrigido. A leitura desta seção não é necessária neste caso.
Quando tiver certeza de que o bug não existe, defina um valor de configuração de recurso booleano XML no aplicativo Configurações config_isSafetyCenterLockScreenPendingIntentFixed
como true
para desativar a solução alternativa no Safety Center.
Solução alternativa PendingIntent
Este bug é causado por Configurações que usam extras de instância Intent
para determinar qual fragmento abrir. Como Intent#equals
não leva em consideração os extras da instância Intent
, a instância PendingIntent
para o ícone do menu de engrenagem e a entrada são consideradas iguais e navegam para a mesma IU (mesmo que se destinem a navegar para uma IU diferente). Esse problema foi corrigido em uma versão QPR diferenciando as instâncias PendingIntent
por código de solicitação. Alternativamente, isso pode ser diferenciado usando Intent#setId
.
Fontes internas de segurança
Algumas fontes do Safety Center são internas e implementadas no aplicativo do sistema PermissionController dentro do módulo PermissionController. Essas fontes se comportam como fontes regulares do Safety Center e não recebem tratamento especial. O código para essas fontes está disponível através da pesquisa de código do Android .
Estes são principalmente sinais de privacidade, por exemplo:
- Acessibilidade
- Revogar automaticamente aplicativos não utilizados
- Acesso à localização
- Ouvinte de notificação
- Informações sobre política de trabalho