Interagir com o Centro de Segurança

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
  • 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
  • EXTRA_SAFETY_SOURCE_USER_HANDLE
    • Valor da string: android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE
    • Tipo UserHandle : especifica UserHandle para o cartão de aviso associado
    • Opcional (o padrão é o usuário atual)

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

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ão SEND_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 que SafetySourceStatus se houver uma (a menos que SafetySourceStatus seja SEVERITY_LEVEL_UNSPECIFIED , caso em que problemas SEVERITY_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 .

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 usa intentAction 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
  • 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ância Activity .
    • Se a entrada estiver desabilitada, ela deverá ser designada SEVERITY_LEVEL_UNSPECIFIED .
    • Requisitos adicionais impostos pela configuração da API.

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ância Action 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
  • 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 mesmo SafetySourceIssue de diferentes fontes e mostrá-lo apenas uma vez na IU, presumindo que eles tenham o mesmo deduplicationGroup (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 do SafetySourcesGroup
  • 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, a Notification 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
  • 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 elementos Action . Se a capacidade de ação não for ISSUE_ACTIONABILITY_MANUAL , é permitido ter zero Action .
    • O OnDismiss PendingIntent não deve abrir uma instância Activity
    • Requisitos adicionais impostos pela configuração da API

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 de SAFETY_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 : Resolvemos SafetySourceIssue.Action diretamente na tela do Safety Center; use isso em vez de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para o Safety Center poder rastrear o SafetySourceIssue.Action que está sendo resolvido.
    • SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED : Tentamos resolver SafetySourceIssue.Action diretamente na tela do Safety Center, mas não conseguimos; use isso em vez de SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED para que o Safety Center possa rastrear a falha de SafetySourceIssue.Action .
    • SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED : O idioma do dispositivo mudou, por isso estamos atualizando o texto dos dados fornecidos; é permitido usar SAFETY_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 usar SAFETY_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ância SafetySourceIssue sendo resolvida.
  • Identificador String opcional para a instância SafetySourceIssue.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 ou SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED

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ância SafetyEvent 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

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
  • 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
  • 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

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

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 seja singleUser .

  • 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 e android.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:

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