Criar um app que será executado em um perfil de trabalho

1. Antes de começar

O que é um perfil de trabalho?

Um perfil de trabalho é um perfil secundário que pode ser ativado no dispositivo pessoal de um usuário quando a empresa permite que os funcionários usem dispositivos pessoais no trabalho.

Os perfis de trabalho podem ser controlados por um administrador de TI, e as funcionalidades disponíveis são definidas de forma separada do perfil principal do usuário. Com essa abordagem, as organizações podem controlar o ambiente em que os apps e os dados específicos da empresa são executados no dispositivo, enquanto o usuário ainda usa os apps e perfis pessoais.

Como isso afeta seu app? Os apps podem ser instalados em um perfil de trabalho, o que significa que podem enfrentar restrições de execução e mudanças de comportamento. Se esse for o caso, eles também precisam estar protegidos. Mesmo que o app seja executado em um perfil pessoal, o perfil de trabalho ainda pode afetar o comportamento dele.

Pré-requisitos

Este codelab foi projetado para desenvolvedores Android com habilidades de nível básico a intermediário.

Ele pressupõe que você já criou um app, usou o Android Studio e testou seu app em um dispositivo ou emulador.

O que você vai fazer

Neste codelab, você modificará um aplicativo para oferecer a melhor experiência do usuário quando o app for instalado em um dispositivo com um perfil de trabalho. Você aprenderá a fazer o app:

  • processar a lista de contatos pessoais e de trabalho ao mesmo tempo;
  • alternar entre o perfil pessoal e de trabalho dentro do app.

caf809dbd1e16c75.png

Pré-requisitos

  • Um dispositivo Android não gerenciado, ou seja, que não pertence nem é gerenciado por uma organização.

2. Começar a configuração

Configurar um dispositivo de teste

Recomendamos que você use um dispositivo físico para este codelab. No entanto, você ainda pode fazer a mesma configuração abaixo em um emulador usando uma imagem que inclua a Google Play Store.

TestDPC

O Google cria o app TestDPC para ajudar a simular e testar um ambiente gerenciado no seu dispositivo. Ele configura um perfil de trabalho e oferece controles para ativar/desativar determinados recursos no dispositivo, da mesma forma que um administrador de TI.

Instalar o app TestDPC

No dispositivo, abra a Google Play Store e faça o download do app TestDPC.

Configurar um perfil de trabalho

Depois que o app TestDPC estiver instalado, você verá dois ícones no dispositivo: um ícone de configuração e o ícone do app TestDPC. Toque no ícone de configuração e siga as etapas.

Agora você tem dois perfis separados: um para apps pessoais e outro para apps de trabalho. É possível alternar entre os dois usando as guias na parte de cima da lista de apps.

Cada perfil tem um app da Play Store próprio. Os apps de trabalho são identificados por uma pequena pasta em cima do ícone na tela de início.

46175af7ad32979d.gif

Você pode instalar apps usando a Play Store normalmente. O app vai ser instalado no perfil em que a Play Store for iniciada (pessoal ou de trabalho). Os apps também podem existir nos dois perfis quando forem instalados usando a Play Store de ambos. Nesse caso, cada versão do app vai ter espaços de configuração e armazenamento totalmente isolados.

Como instalar o app em um perfil específico

Nos parágrafos a seguir, vamos ver como alternar entre o perfil padrão e o perfil de trabalho com a classe CrossProfileApps. Para confirmar esse comportamento, o app precisa ser instalado nos dois perfis.

Você pode confirmar o número de ID do perfil com o comando adb abaixo.

$ adb shell pm list users

É possível instalar um app em um perfil designado usando o comando adb abaixo.

$ adb install --user [id number of profile] [path of apk file]

Você pode ter os mesmos resultados definindo a configuração de execução/depuração no projeto e selecionando a opção "Install for all users".

7634e3dcb0a744ca.png

Ao atualizar o app com a execução no Android Studio, ele vai ser instalado nos dois perfis.

3. Carregar contatos

Configure alguns contatos de teste para usar no app de demonstração:

  1. Inicie o app Contatos no perfil pessoal do dispositivo.
  2. Adicione alguns contatos de teste que possam ser identificados como contatos pessoais.
  3. Inicie o app Contatos no perfil de trabalho. Você não verá os contatos pessoais que acabou de adicionar.
  4. Adicione alguns contatos de teste que possam ser identificados como contatos de trabalho.

Quando acabar de definir os contatos, teste o código inicial do app de demonstração.

4. Acessar o código inicial

  1. Para fazer o download do app de exemplo:
  • Clone o repositório do GitHub.
$ git clone https://github.com/android/enterprise-samples.git

$ cd enterprise-samples/Work-profile-codelab
  • Ou faça o download do projeto no link abaixo.

Fazer o download do ZIP

  1. Abra e execute o app no Android Studio.

O app ficará assim ao ser iniciado pela primeira vez:

f9779ab476511718.png

Fazer um teste

Ao final deste codelab, seu app vai mostrar os contatos pessoais e de trabalho juntos quando executado no perfil pessoal. Também é possível alternar entre perfis iniciando outra instância do app para o outro perfil dentro do próprio app.

5. Exibir contatos pessoais e de trabalho

Ao carregar contatos usando ContactsContract.Contacts.CONTENT_URI, o app decidirá quais serão exibidos dependendo do perfil em que ele está sendo executado. Contudo, em muitos casos, é possível que você queira que o app carregue as duas listas de contatos ao mesmo tempo. O usuário pode querer compartilhar um item pessoal, como uma foto ou documento, com um colega de trabalho, por exemplo. Para fazer isso, você precisará recuperar as duas listas de contatos.

Abrir MainActivity.kt

O método onCreateLoader() é responsável por criar o carregador de cursor para recuperar e carregar os contatos. No momento, ele retorna apenas um CursorLoader usando o ContentURI padrão. Você precisará chamar esse método duas vezes: uma vez para os contatos pessoais e outra para os de trabalho. Para diferenciá-los, transmitiremos um ID diferente ao onCreateLoader() para cada caso. Será necessário conferir o ID transmitido ao método para decidir qual ContentURI será usado.

Primeiro, mude o valor da variável ContentURI de acordo com o valor do ID transmitido ao método. No caso de PERSONAL_CONTACTS_LOADER_ID, atribua ao ContactsContract.Contacts.CONTENT_URI padrão. Caso contrário, você vai criar um ENTERPRISE_CONTENT_FILTER_URI, conforme descrito aqui.

ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()

Como esse é um URI de filtro de conteúdo, o builder precisa de um filtro de pesquisa (a frase de pesquisa) para pesquisar/carregar os contatos.

Por enquanto, fixe a frase de pesquisa no código para que seja qualquer nome que comece com a letra "a".

val nameFilter = Uri.encode("a") // names that start with a

Também é necessário especificar o diretório de contatos para a pesquisa. Use o diretório ENTERPRISE_DEFAULT, que procura os contatos armazenados localmente no dispositivo.

O método onCreateLoader() concluído ficará assim:

override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
        val nameFilter = Uri.encode("a") // names that start with a
        val contentURI = when (id) {
            PERSONAL_CONTACTS_LOADER_ID -> ContactsContract.Contacts.CONTENT_URI
            else -> {
                ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()
            }
        }
        return CursorLoader(
            this, contentURI, arrayOf(
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            ), null, null, null
        )
    }

Agora é necessário inicializar outro Loader com um novo valor de ID para acionar o método acima.

Primeiro, crie um novo valor constante de ID para os contatos de trabalho na parte superior da MainActivity:

const val WORK_CONTACTS_LOADER_ID = 1

Em seguida, em initLoaders(), use o LoaderManager para inicializar um novo Loader com o novo ID criado acima:

private fun initLoaders() {
        LoaderManager.getInstance(this).
            initLoader(PERSONAL_CONTACTS_LOADER_ID, null, this)
        LoaderManager.getInstance(this).
            initLoader(WORK_CONTACTS_LOADER_ID, null, this)
    }

Todos os outros métodos funcionarão da mesma forma, já que o cursor de dados de ambos os carregadores têm a mesma estrutura.

Testar

Execute o app no perfil pessoal. Você vai ver tanto os contatos pessoais quanto os de trabalho.

3b8f9c73feee88fb.png

E o perfil de trabalho?

Se o app for executado no perfil de trabalho, apenas os contatos de trabalho serão exibidos, sem incluir os pessoais. Isso ocorre porque um dos principais objetivos dos perfis de trabalho é proteger a privacidade do usuário. Por isso, geralmente os apps de trabalho não conseguem acessar as informações do perfil pessoal.

9312158a2dc03891.png

6. Alternar perfis em um app

O Android inclui APIs para iniciar outra instância do app em um perfil diferente, o que ajuda o usuário a alternar entre contas. Por exemplo, um app de e-mails pode fornecer uma IU que permite ao usuário alternar entre o perfil pessoal e o perfil de trabalho para acessar duas contas de e-mail.

Qualquer app pode chamar essas APIs para iniciar a atividade principal de um mesmo app, caso ele já esteja instalado no outro perfil.

Para adicionar a alternância de contas entre perfis ao app, é necessário primeiro adicionar um botão ao layout da atividade principal que permita ao usuário trocar de perfil.

Abra activity_main.xml e adicione um widget de botão abaixo do widget recycler-view:

<androidx.appcompat.widget.AppCompatButton
        android:id="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/contacts_rv"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

No MainActivity.kt, defina o evento de clique do botão para alternar entre perfis no método onCreate.

Para fazer isso, primeiro inclua o serviço do sistema CrossProfileApps:

val crossProfileApps = getSystemService(CrossProfileApps::class.java)

Essa classe oferece todas as APIs necessárias para implementar um recurso de alternância entre perfis. É possível recuperar a lista de perfis de usuário chamando targetUserProfiles, que retornará todos os outros perfis em que o app está instalado.

val userHandles = crossProfileApps.targetUserProfiles

Agora, você pode usar o primeiro userHandle retornado e iniciar o app no outro perfil.

crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )

Também é possível ter um texto localizado que solicita que o usuário troque de perfil e usar essa informação para definir o valor de texto do botão.

val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())

Agora, juntando todas essas partes, vamos adicionar isso ao resultado do método onCreate na MainActivity.kt:

override fun onCreate(savedInstanceState: Bundle?) {

     ...

     val crossProfileApps = getSystemService(CrossProfileApps::class.java)
       val userHandles = crossProfileApps.targetUserProfiles
       val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())
        binding.button.apply {
            text = label
            setOnClickListener {
                crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )
            }
        }
}

Testar

Se você executar o app agora, o botão na parte de baixo da tela vai indicar que ele está pronto para alternar para o Perfil de trabalho ou o Perfil pessoal, dependendo do local em que foi iniciado.

Ao clicar nesse botão, o app vai ser iniciado no outro perfil.

db741d4872052fbc.gif

7. Parabéns!

Você modificou um app que funciona em um perfil pessoal e de trabalho e que consegue detectar quando há um perfil de trabalho no dispositivo para recuperar contatos de trabalho até mesmo no modo pessoal.

Você também implementou um recurso que permite ao usuário alternar entre o perfil de trabalho e o pessoal no app durante a execução, sem precisar fechá-lo e reiniciá-lo no perfil adequado. Essa é uma boa prática para ajudar os usuários que usam seu app de formas diferentes em perfis distintos.

Saiba mais