Como criar aplicativos com reconhecimento de vários usuários

Quando um dispositivo oferece suporte a vários usuários , seus aplicativos devem estar cientes desses usuários distintos.

Certos aplicativos precisam ter alguns componentes executados como singletons e podem aceitar solicitações de qualquer usuário. Atualmente, apenas aplicativos do sistema podem usar esse recurso.

Esta facilidade:

  • Conserva recursos
  • Arbitra um ou mais recursos compartilhados entre usuários
  • Reduz a sobrecarga de rede usando uma única conexão de servidor

Consulte o diagrama abaixo para obter uma representação do fluxo de permissões com vários usuários.

Fluxo de permissões de vários usuários

Figura 1. Permissões de vários usuários

Habilitando um componente singleton

Para identificar um aplicativo como singleton, adicione android:singleUser=”true” ao seu serviço, receptor ou provedor no manifesto do Android.

O sistema instanciará esse componente no processo executado apenas como usuário 0. Quaisquer solicitações para se conectar a esse provedor ou serviço, ou para transmitir para esse receptor, de qualquer usuário serão roteadas para o processo no usuário 0. Se este for o único componente em seu aplicativo, apenas uma instância de seu aplicativo será executada.

As atividades em seu pacote ainda serão iniciadas em um processo separado para cada usuário, com o UID no intervalo de UID desse usuário (como 1010034).

Interagindo com os usuários

Definir permissões

Essas permissões são necessárias

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

Empregar APIs

Use as APIs a seguir para tornar os aplicativos cientes de vários usuários.

  1. Extraia o identificador do usuário das chamadas recebidas do Binder:
    • int userHandle = UserHandle.getCallingUserId()
  2. Use APIs novas e protegidas para iniciar serviços, atividades, transmissões em um usuário específico:
    • Context.startActivityAsUser(Intent, UserHandle)
    • Context.bindServiceAsUser(Intent, …, UserHandle)
    • Context.sendBroadcastAsUser(Intent, … , UserHandle)
    • Context.startServiceAsUser(Intent, …, UserHandle)
    UserHandle pode ser um usuário explícito ou um dos identificadores especiais: UserHandle.CURRENT ou UserHandle.ALL . CURRENT indica o usuário que está atualmente em primeiro plano. Use ALL quando quiser enviar uma transmissão para todos os usuários.
  3. Comunique-se com componentes em seu próprio aplicativo: (INTERACT_ACROSS_USERS) Ou com componentes em outros aplicativos: (INTERACT_ACROSS_USERS_FULL)
  4. Pode ser necessário criar componentes de proxy que são executados no processo do usuário que acessam o componente singleUser no usuário 0.
  5. Consulte usuários e seus handles com o novo serviço de sistema UserManager :
    • UserManager.getUsers()
    • UserManager.getUserInfo()
    • UserManager.supportsMultipleUsers()
    • UserManager.getUserSerialNumber(int userHandle) - um número não reciclado que corresponde a um identificador de usuário.
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles() - retorna a coleção de perfis próprios e gerenciados, se houver.
  6. Registre-se para ouvir usuários específicos ou todos e os retornos de chamada com novas APIs no ContentObserver, PackageMonitor, BroadcastReceiver que fornecem informações adicionais sobre qual usuário causou o retorno de chamada.

Serviços em vários usuários ou perfis

Nem todos os serviços precisam executar uma instância em outro usuário ou perfil de trabalho. Se o serviço do sistema precisar ser executado apenas como usuário 0, desative os componentes do serviço ao executar com outros usuários para ajudar a preservar os recursos. O exemplo a seguir mostra como você pode fazer isso nos pontos de entrada do seu serviço:

// Add on all entry points such as boot_completed or other manifest-listed receivers and providers
if (!UserManager.isSystemUser()) {
    // Disable the service
    ComponentName targetServiceName = new ComponentName(this, TargetService.class);
    context.getPackageManager().setComponentEnabledSetting(
        targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);
}

O exemplo também pode usar PackageManager.setApplicationEnabledSetting() para desabilitar o aplicativo inteiro.