Redirecionar para a Central de segurança
Qualquer app pode abrir a Central de segurança usando a
ação android.content.Intent.ACTION_SAFETY_CENTER
(valor de string
android.intent.action.SAFETY_CENTER
).
Para abrir a Central de segurança, faça uma chamada em 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 card de aviso específico da Central de segurança usando
extras de intent específicos. Esses extras não são destinados a terceiros, portanto,
fazem parte de SafetyCenterManager
, que faz parte de @SystemApi
. Somente
apps do sistema podem acessar esses extras.
Extras de intent que redirecionam um card de aviso específico:
EXTRA_SAFETY_SOURCE_ID
- Valor de string:
android.safetycenter.extra.SAFETY_SOURCE_ID
- String type: especifica o ID da origem de segurança do card de aviso associado
- Obrigatório para que o redirecionamento para o problema funcione
- Valor de 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.
- Obrigató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 card de aviso associado - Opcional (o padrão é o usuário atual)
- Valor da string:
O snippet 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 versões mais recentes, a página da Central de segurança é dividida
em várias subpáginas que representam os diferentes SafetySourcesGroup
. No
Android 13, isso é mostrado como entradas rebatíveis.
É possível redirecionar para uma subpágina específica usando este extra da intent:
EXTRA_SAFETY_SOURCES_GROUP_ID
- Valor de string:
android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID
- Tipo de string: especifica o ID do
SafetySourcesGroup
. - Obrigatório para que o redirecionamento para a subpágina funcione
- Valor de string:
O snippet de código abaixo pode ser usado em uma instância Activity
para abrir
a tela do Centro 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);
Usar as APIs de origem da Central de segurança
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 em
Pesquisa
de código.
O código de implementação das APIs está disponível no Code
Search.
Permissões
As APIs de origem da Central de segurança só podem ser acessadas por apps do sistema que estão na lista de permissões usando as permissões listadas abaixo. Para saber mais, consulte Lista de permissões privilegiadas.
READ_SAFETY_CENTER_STATUS
signature|privileged
- Usado para a API
SafetyCenterManager#isSafetyCenterEnabled()
(não necessária para fontes da Central de segurança, eles só precisam da permissãoSEND_SAFETY_CENTER_UPDATE
). - Usado por apps do sistema que verificam se a Central de segurança está ativada
- Concedido apenas a apps do sistema que estão na lista de permissões
SEND_SAFETY_CENTER_UPDATE
internal|privileged
- Usado para a API ativada e a API SafetyFontes
- Usado apenas por fontes de segurança
- Concedida apenas a apps do sistema na lista de permissões
Essas permissões são privilegiadas e só podem ser adquiridas adicionando-as ao
arquivo relevante, por exemplo, ao arquivo
com.android.settings.xml
do app Configurações e ao arquivo AndroidManifest.xml
do app. Consulte
protectionLevel
para mais informações sobre o modelo de permissão.
Instalar o SafetyCenterManager
SafetyCenterManager
é uma classe @SystemApi
que pode ser acessada por apps do sistema
a partir do Android 13. Esta chamada demonstra como
acessar 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;
}
Verificar se o Safety Center está ativado
Essa chamada verifica se o Safety Center está ativado. A chamada requer a
permissão READ_SAFETY_CENTER_STATUS
ou SEND_SAFETY_CENTER_UPDATE
:
boolean isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled();
if (isSafetyCenterEnabled) {
// …
} else {
// …
}
Fornecer dados
Os dados de origem do Safety Center com o String sourceId
fornecido são fornecidos ao Safety
Center com o objeto SafetySourceData
, que representa uma entrada da interface e uma
lista de problemas (cards de aviso). A entrada da interface e os cartões de aviso podem ter
níveis de gravidade diferentes 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 interface ou para mostrar uma entrada não especificada
- Não deve ser usado para cards de alerta
SEVERITY_LEVEL_INFORMATION
- Informações básicas ou sugestão secundária
- Cor: verde
SEVERITY_LEVEL_RECOMMENDATION
- Recomendação de que o usuário tome medidas em relação a esse problema, já que ele pode colocar o usuário em risco
- Cor: amarelo
SEVERITY_LEVEL_CRITICAL_WARNING
- Aviso crítico de que o usuário precisa tomar medidas em relação a esse problema, já que ele representa um risco
- Cor: vermelho
SafetySourceData
O objeto SafetySourceData
é composto por uma entrada de interface, cartões de aviso e
invariantes.
- Instância
SafetySourceStatus
opcional (entrada da interface) - Lista de
SafetySourceIssue
instâncias (cards de aviso) - Extras do
Bundle
opcionais (a partir do 14) - Invariantes:
- A lista
SafetySourceIssue
precisa ser composta por problemas com identificadores exclusivos. - A instância
SafetySourceIssue
não pode ser mais importante queSafetySourceStatus
, se houver uma. A menos queSafetySourceStatus
sejaSEVERITY_LEVEL_UNSPECIFIED
, caso em que problemas deSEVERITY_LEVEL_INFORMATION
são permitidos. - Os requisitos adicionais impostos pela configuração da API precisam ser atendidos. Por exemplo, se a origem for somente de problemas, ela não poderá fornecer uma instância de
SafetySourceStatus
.
- A lista
SafetySourceStatus
- Título
CharSequence
obrigatório - Resumo de
CharSequence
obrigatório - Nível de gravidade obrigatório
- Instância opcional
PendingIntent
para redirecionar o usuário para a página certa (o padrão usaintentAction
da configuração, se houver) IconAction
opcional (mostrado como um ícone lateral na entrada) composto de:- Tipo de ícone obrigatório, que precisa ser um dos seguintes:
ICON_TYPE_GEAR
: mostrado como uma engrenagem ao lado da entrada da interfaceICON_TYPE_INFO
: aparece como um ícone de informações ao lado da entrada da interface.
- Necessário
PendingIntent
para redirecionar o usuário a outra página
- Tipo de ícone obrigatório, que precisa ser um dos seguintes:
- Valor booleano opcional
enabled
que permite marcar a entrada da interface como desativada, para que não seja clicável (o padrão étrue
) - Invariantes:
- Instâncias de
PendingIntent
precisam abrir uma instância deActivity
. - Se a entrada estiver desativada, ela precisará ser designada como
SEVERITY_LEVEL_UNSPECIFIED
. - Requisitos adicionais impostos pela configuração da API.
- Instâncias de
SafetySourceIssue
- Identificador
String
exclusivo obrigatório - Título
CharSequence
obrigatório - Subtítulo opcional em
CharSequence
- Resumo de
CharSequence
obrigatório - Nível de gravidade necessário
- Categoria de problema opcional, que precisa 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. Esse é o padrão.ISSUE_CATEGORY_DATA
(do Android 14 em diante): o problema afeta os dados do usuário.ISSUE_CATEGORY_PASSWORDS
(do Android 14 em diante): 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 usar para esse problema. Cada instância deAction
é composta por:- Identificador
String
exclusivo obrigatório - Rótulo
CharSequence
obrigatório - É necessário
PendingIntent
para redirecionar o usuário para outra página ou processar a ação diretamente da tela da Central de segurança. - Booleano opcional para especificar se o problema pode ser resolvido diretamente na
tela da SafetyCenter (o padrão é
false
) - Mensagem de sucesso
CharSequence
opcional, a ser mostrada ao usuário quando o problema é resolvido diretamente na tela da Central de segurança.
- Identificador
PendingIntent
opcional chamado quando o usuário dispensa o problema (o padrão é que nada é chamado)- Identificador de tipo de problema
String
obrigatório. É semelhante ao identificador de problema, mas não precisa ser exclusivo e é usado para registro. - O
String
opcional para o ID de eliminação de duplicação permite postar o mesmoSafetySourceIssue
de fontes diferentes e mostrá-lo apenas uma vez na interface, supondo que tenham os mesmosdeduplicationGroup
(a partir do Android 14). Se não for especificado, o problema nunca será eliminado CharSequence
opcional para o título de atribuição. Esse é um texto que mostra a origem do card de aviso (a partir do Android 14). Se não for especificado, será usado o título doSafetySourcesGroup
- Ação de problema opcional (a partir do Android 14),
que precisa ser uma destas:
ISSUE_ACTIONABILITY_MANUAL
: o usuário precisa resolver esse problema manualmente. Esse é o padrão.ISSUE_ACTIONABILITY_TIP
: esse problema é apenas uma dica e pode não exigir nenhuma entrada do usuário.ISSUE_ACTIONABILITY_AUTOMATIC
: esse 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 precisa ser um dos seguintes:
NOTIFICATION_BEHAVIOR_UNSPECIFIED
: a Central de segurança decide se uma notificação é necessária para o card de aviso. Esse é o padrão.NOTIFICATION_BEHAVIOR_NEVER
: nenhuma notificação foi postada.NOTIFICATION_BEHAVIOR_DELAYED
: uma notificação é postada algum tempo após o primeiro relato do problema.NOTIFICATION_BEHAVIOR_IMMEDIATELY
: uma notificação é postada assim que o problema é informado.
Notification
opcional, para mostrar uma notificação personalizada com o card de aviso (a partir do Android 14). Se não for especificado, oNotification
será derivado do card de aviso. Composto por:- Título
CharSequence
obrigatório - Resumo de
CharSequence
obrigatório - Lista de elementos
Action
que o usuário pode receber para essa notificação
- Título
- Invariantes:
- A lista de instâncias
Action
precisa ser composta de ações com identificadores exclusivos - A lista de instâncias
Action
precisa conter um ou dois elementosAction
. Se a capacidade de ação não forISSUE_ACTIONABILITY_MANUAL
, é permitido terAction
zero. - O
PendingIntent
OnDismiss não pode abrir uma instânciaActivity
. - Requisitos adicionais impostos pela configuração da API
- A lista de instâncias
Os dados são fornecidos ao Safety Center em determinados eventos. Por isso, é necessário
especificar o que fez com que a origem fornecesse SafetySourceData
com uma
instância SafetyEvent
.
SafetyEvent
- O tipo obrigatório, que precisa ser um destes:
SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
: o estado da origem mudou.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
: responde a um sinal de atualização/reverificação da Central de segurança. Use esse valor em vez deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para que a Central de segurança possa rastrear a solicitação de atualização/reverificação.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
: resolvemosSafetySourceIssue.Action
diretamente na tela da Central de segurança. Use em vez deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para que a Central de segurança possa acompanhar a resolução deSafetySourceIssue.Action
.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
: tentamos resolverSafetySourceIssue.Action
diretamente na tela da Central de segurança, mas não foi possível. Use essa opção em vez deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
para que a Central de segurança possa monitorar a falha deSafetySourceIssue.Action
.SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED
: o idioma do dispositivo mudou. Por isso, estamos atualizando o texto dos dados fornecidos. O uso deSAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
é permitido.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
: fornecemos esses dados como parte de uma inicialização inicial, já que os dados da Central de segurança não são mantidos nas reinicializações. É permitido usar oSAFETY_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
que está sendo resolvida. - Invariantes:
- O ID de transmissão de atualização precisa ser fornecido se o tipo for
SAFETY_EVENT_TYPE_REFRESH_REQUESTED
. - Os IDs do problema e da ação precisarã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 precisa ser fornecido se o tipo for
Confira abaixo um exemplo de como uma fonte pode fornecer dados ao Safety Center. Neste caso, ele 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);
Receber os últimos dados fornecidos
Você pode receber os últimos dados fornecidos à Central de segurança de uma origem do seu
app. É possível usar isso para mostrar algo na sua própria interface, verificar se os dados
precisam ser atualizados antes de executar uma operação de alto custo ou para fornecer a
mesma instância do SafetySourceData
à Central de segurança com algumas mudanças ou com uma
nova instância do SafetyEvent
. Isso também é útil para testes.
Use este código para acessar os últimos dados fornecidos à Central de segurança:
SafetySourceData lastDataProvided =
safetyCenterManager.getSafetySourceData("MySourceId");
Informar um erro
Se não for possível coletar dados do SafetySourceData
, informe o erro à Central
de segurança, que muda a entrada para cinza, limpa os dados em cache e mostra uma
mensagem como Não foi possível verificar a configuração. Também é possível informar um erro se
uma instância de SafetySourceIssue.Action
não for resolvida. Nesse caso, os
dados em cache não são limpos e a entrada da interface não é alterada, mas uma mensagem é
exibida para o usuário informando que algo deu errado.
É possível fornecer o erro usando SafetySourceErrorDetails
, que é composto
por:
SafetySourceErrorDetails
: instânciaSafetyEvent
obrigató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 do Safety Center para fornecer novos dados. Responder a uma solicitação de atualização ou nova verificação garante que o usuário veja o status atual ao abrir o Centro de segurança 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 está enviando uma solicitação para atualizar os dados da fonte de segurança de um determinado app.
- Intenção protegida que só pode ser enviada pelo sistema
- É enviada a todas as fontes de segurança no arquivo de configuração como uma intent
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
- O tipo de matriz de string (
String[]
) representa os IDs de origem a serem atualizados para o app especificado.
- Valor da string:
EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
- Valor da string:
android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE
- Tipo de número inteiro, representa um tipo de solicitação
@IntDef
- Precisa ser um dos seguintes:
EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
: solicita que a fonte forneça dados de maneira relativamente rápida, normalmente quando o usuário abre a páginaEXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA
: solicita que a origem forneça os dados mais atualizados possível, normalmente quando o usuário pressiona o botão "Nova verificação".
- Valor da string:
EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
- Valor da string:
android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID
- Tipo de string, representa um identificador exclusivo para a atualização solicitada
- Valor da string:
Para receber um indicador da Central de segurança, implemente uma
instância
BroadcastReceiver
. A transmissão é enviada com BroadcastOptions
especial, que permite que o
receptor inicie um serviço em primeiro plano.
O 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>
O ideal é que uma fonte da Central de segurança seja implementada para chamar
SafetyCenterManager
quando os dados mudarem. Por motivos de integridade do sistema, recomendamos
responder apenas ao sinal de nova verificação (quando o usuário toca no botão
de leitura), e não quando o usuário abre a Central de segurança. Se essa funcionalidade for
necessária, o campo refreshOnPageOpenAllowed="true"
no arquivo de configuração
precisa ser definido para que a origem receba a transmissão entregue nesses casos.
Responder à Central de segurança quando ela estiver ativada ou desativada
Você pode responder quando o Safety Center for ativado ou desativado usando esta ação de intent:
ACTION_SAFETY_CENTER_ENABLED_CHANGED
- Valor da string:
android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED
- Acionado quando o Safety Center é ativado ou desativado enquanto o dispositivo está em execução.
- Não é chamado na inicialização (use
ACTION_BOOT_COMPLETED
para isso) - Intent protegida que só pode ser enviada pelo sistema
- Enviada a todas as fontes de segurança no arquivo de configuração como uma intent
explícita, requer a permissão
SEND_SAFETY_CENTER_UPDATE
- Enviada como uma intent implícita que requer a permissão
READ_SAFETY_CENTER_STATUS
- Valor da string:
Essa ação de intent é útil para ativar ou desativar recursos relacionados ao Centro de segurança no dispositivo.
Implementar a resolução de ações
Uma ação de resolução é uma instância SafetySourceIssue.Action
que um usuário pode
resolver diretamente na tela da Central de segurança. O usuário toca em um botão de ação, e a instância PendingIntent
na SafetySourceIssue.Action
enviada pela
fonte de segurança é acionada. Isso resolve o problema em segundo plano e
notifica a Central de segurança quando ele é concluído.
Para implementar ações de resolução, a origem da Central de segurança pode usar um serviço se
a operação for esperada para levar algum tempo (PendingIntent.getService
) ou um
broadcast receiver (PendingIntent.getBroadcast
).
Use este código para enviar um problema resolvido à Central de segurança:
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 dispensas de problemas
É possível especificar uma instância de PendingIntent
que pode ser acionada quando uma
instância de SafetySourceIssue
é dispensada. A Central de segurança lida com estas dispensas
de problemas:
- Se uma fonte enviar um problema, o usuário poderá dispensá-lo na tela do Centro de segurança tocando no botão de dispensa (um botão X no card de aviso).
- Quando um usuário dispensa um problema, se ele continuar, ele não será mostrado na interface novamente.
- As dispensas persistentes em um disco permanecem durante as reinicializações do dispositivo.
- Se a origem da Central de segurança parar de fornecer um problema e disponibilizá-lo novamente mais tarde, ele aparecerá novamente. Isso permite situações em que um usuário recebe um aviso, o dispensa e depois toma uma ação que deveria aliviar o problema, mas o usuário faz algo novamente que causa um problema semelhante. Nesse momento, o card de aviso vai reaparecer.
- Os cards de aviso amarelos e vermelhos reaparecem a cada 180 dias, a menos que o usuário os tenha dispensado várias vezes.
Não é necessário que a fonte tenha outros comportamentos, a menos que:
- A origem tenta implementar esse comportamento de maneira diferente, por exemplo, sem nunca reparar o problema.
- A fonte tenta usar isso como um callback, por exemplo, para registrar as informações.
Fornecer dados para vários usuários/perfis
A API SafetyCenterManager
pode ser usada entre usuários e perfis. Para mais
informações, consulte Criar apps compatíveis com vários usuários
. O objeto Context
que fornece SafetyCenterManager
está associado a uma instância de UserHandle
.
Portanto, a instância de SafetyCenterManager
retornada interage com a
Central de segurança dessa instância de UserHandle
. Por padrão, Context
é
associado ao usuário em execução, mas é possível criar uma instância para
outro usuário se o app 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 combina 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 UIentry para o usuário (pai do perfil) e todos os perfis gerenciados
associados (que usam instâncias
titleForWork
). O sinal de atualização ou nova verificação é 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 a
SafetyCenterManager
, sem precisar fazer uma chamada entre perfis, a menos que o receptor ou o app sejasingleUser
.A fonte precisa fornecer dados para o usuário e todos os perfis gerenciados. Os dados de cada entrada da interface podem ser diferentes, dependendo do perfil.
Teste
é possível 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 de ponta a ponta (E2E), mas isso está fora do escopo deste guia. Para mais informações sobre como escrever esses testes E2E, consulte Testes do CTS (CtsSafetyCenterTestCases).
APIs de teste e internas
As APIs internas e de teste são para uso interno, por isso não são descritas em detalhes neste guia. No entanto, podemos estender algumas APIs internas no futuro para permitir que os OEMs criem a própria interface e vamos atualizar este guia para fornecer orientações sobre como usá-las.
Permissões
MANAGE_SAFETY_CENTER
internal|installer|role
- Usado para as APIs internas do Safety Center
- Concedido apenas ao PermissionController e ao shell
App Config.
Redirecionamento para a Central de segurança
Por padrão, a Central de segurança é acessada no app Configurações com uma nova entrada Segurança e privacidade. Se você usa outro app Configurações ou se modificou ele, pode ser necessário personalizar a forma como a Central de segurança é acessada.
Quando o Safety Center está ativado:
- A entrada Privacy legada está com código oculto
- A entrada de Segurança legada está com código oculto
- Uma nova entrada de Segurança e privacidade foi adicionada código
- A nova entrada de Segurança e privacidade redireciona para o código da Central de segurança
- As ações das intents
android.settings.PRIVACY_SETTINGS
eandroid.settings.SECURITY_SETTINGS
são redirecionadas para a Central de segurança (código: security, privacy).
Páginas avançadas de segurança e privacidade
O app Configurações contém outras configurações 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, a página de configurações avançadas de segurança e privacidade foi mesclada em uma única página "Mais segurança e privacidade" com ação de intent
"com.android.settings.MORE_SECURITY_PRIVACY_SETTINGS"
Fontes de segurança
A Central de segurança se integra a um conjunto específico de fontes de segurança fornecidas pelo app Configurações:
- Uma fonte de segurança da tela de bloqueio verifica se uma tela de bloqueio está configurada com um código de acesso (ou outra segurança) para garantir que as informações particulares do usuário fiquem protegidas contra acesso externo.
- Uma origem de segurança biométrica (oculta por padrão) é mostrada para integração com um sensor de impressão digital ou facial.
O código-fonte dessas fontes da Central de segurança pode ser acessado pela Pesquisa de código do Android. Se o app Configurações não for modificado (sem mudanças no nome do pacote, no código-fonte ou no código-fonte que lida com tela de bloqueio e biometria), essa integração vai funcionar imediatamente. Caso contrário, algumas modificações podem ser necessárias, como mudar o arquivo de configuração para mudar o nome do pacote do app Configurações e as fontes que se integram à Central de segurança, bem como a integração. Para mais informações, consulte Atualizar o arquivo de configuração e as configurações de integração.
Sobre a PendingIntent
Se você usa a integração do app Configurações com o Safety Center no Android 14 ou versões mais recentes, o bug descrito abaixo foi corrigido. Nesse caso, não é necessário ler esta seção.
Quando tiver certeza de que o bug não existe, defina um valor de configuração de recurso
booleano XML no app Configurações
config_isSafetyCenterLockScreenPendingIntentFixed
para true
para desativar a
solução no Safety Center.
Solução alternativa para PendingIntent
Esse bug é causado quando as configurações usam extras de instância Intent
para determinar qual
fragmento abrir. Como Intent#equals
não considera os extras da instância
Intent
, a instância PendingIntent
do ícone do menu de engrenagem e a
entrada são consideradas iguais e navegar para a mesma interface, mesmo que elas sejam
destinadas a navegar para uma interface diferente. Esse problema foi corrigido em uma versão do QPR
ao diferenciar as instâncias de PendingIntent
pelo código de solicitação. Como alternativa,
isso pode ser diferenciado usando Intent#setId
.
Fontes de segurança internas
Algumas fontes da Central de segurança são internas e implementadas no app do sistema PermissionController dentro do módulo PermissionController. Essas fontes se comportam como as fontes normais do Safety Center e não recebem tratamento especial. O código dessas origens está disponível na pesquisa de código do Android.
Eles são principalmente indicadores de privacidade, por exemplo:
- Acessibilidade
- Revogar automaticamente apps não usados
- Acesso ao local
- Ouvinte de notificações
- Informações da política de trabalho