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

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? Qualquer app pode ser instalado em um perfil de trabalho, o que significa que ele pode encontrar restrições no tempo de execução e mudanças comportamentais. O app também precisa estar protegido caso não seja destinado para fins de trabalho. 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 antes, já usou o Android Studio e testou seu app em um dispositivo ou emulador.

O que você fará:

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.

e69c26cfc305d675.png

O que será necessário

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

Configurar um dispositivo de teste

Recomendamos que você use um dispositivo físico para este codelab. Contudo, também é possível definir a mesma configuração apresentada abaixo em um emulador.

TestDPC

O app TestDPC foi criado pelo Google para ajudar a simular e testar um ambiente gerenciado no seu próprio dispositivo. Ele configura um perfil de trabalho e fornece 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 superior 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.

153e3b8dbfb4a86e.gif

Você pode instalar apps usando a Play Store normalmente. O app 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 terá espaços de configuração e armazenamento totalmente isolados.

Por padrão, instalar um app executando-o no Android Studio fará com que ele seja instalado nos dois perfis.

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.

  1. Para fazer o download do app de amostra:
  • clone o repositório do GitHub;
$  git clone https://github.com/a-samak/work-profile-codelab
  • ou faça o download do repositório como um arquivo ZIP.

Fazer o download do ZIP

  1. Após o download, vá até a pasta do projeto e mude para a ramificação starter.
$  git checkout starter
  1. Abra e execute o app no Android Studio.

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

f9779ab476511718.png

Fazer um teste

Quando você executa o app do Android Studio em um dispositivo ou emulador, ele é instalado nos dois perfis. Se você preferir, poderá excluir o app de um dos perfis e deixá-lo no outro.

Execute o app no perfil pessoal. Você verá uma lista com todos os contatos pessoais, mas nenhum dos contatos de trabalho. Agora, execute o app no perfil de trabalho. Você verá os contatos de trabalho, mas nenhum dos contatos pessoais.

Ao final deste codelab, o app exibirá 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.

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-o ao ContactsContract.Contacts.CONTENT_URI padrão. Caso contrário, você 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 W
        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ê verá tanto os contatos pessoais quanto os de trabalho.

f9779ab476511718.png 7e4846e179664d66.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.

9b7ddeec64957963.png

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"
        />

Em MainActivity.kt, defina o evento de clique do botão para alternar entre perfis.

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, você adicionará o seguinte a MainActivity.kt:

val crossProfileApps = getSystemService(CrossProfileApps::class.java)
        val userHandles = crossProfileApps.targetUserProfiles
        val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())
        button = findViewById<AppCompatButton>(R.id.button).apply {
            text = label
            setOnClickListener {
                crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )
            }
        }

Testar

Se você executar o app agora, o botão na parte inferior indicará que ele está pronto para alternar entre o Perfil de trabalho e o Perfil pessoal, dependendo do local em que foi iniciado.

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

d904de4fdc0d091b.png 4835ce56fcf10ea1.png

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