The Android Developer Challenge is back! Submit your idea before December 2.

Modificar contatos usando intents

Esta lição mostra como usar um Intent para inserir um novo contato ou modificar os dados de um contato. Em vez de acessar diretamente o Provedor de contatos, um Intent inicia o app de contatos que executa a Activity apropriada. Para as ações de modificação descritas nesta lição, se você enviar dados estendidos no Intent, eles serão inseridos na IU da Activity iniciada.

O uso de um Intent para inserir ou atualizar um único contato é a melhor maneira de modificar o Provedor de contatos, pelos seguintes motivos:

  • Isso economiza o tempo e o esforço necessários para desenvolver sua IU e o código.
  • Evita a introdução de erros causados por modificações que não seguem as regras do Provedor de contatos.
  • Reduz o número de permissões que você precisa solicitar. Seu app não precisa de permissão para gravar no Provedor de contatos, porque delega modificações no app de contatos que já tem essa permissão.

Inserir um novo contato usando um intent

Em geral, você permite que o usuário insira um novo contato quando seu app recebe novos dados. Por exemplo, um app de avaliação de restaurantes pode permitir que os usuários adicionem o restaurante como contato enquanto o avaliam. Para fazer isso usando um intent, crie-o usando o máximo de dados disponíveis e envie-o ao app de contatos.

A inclusão um contato usando o app de contatos insere um novo contato bruto na tabela ContactsContract.RawContacts do Provedor de contatos. Se necessário, o app de contatos solicita aos usuários o tipo de conta e a conta a serem usados durante a criação do contato bruto. O app de contatos também notifica os usuários se o contato bruto já existe. Os usuários têm a opção de cancelar a inserção, caso em que nenhum contato é criado. Para saber mais sobre contatos brutos, consulte o guia da API do Provedor de contatos.

Criar um intent

Para começar, crie um novo objeto Intent com a ação Intents.Insert.ACTION. Define o tipo MIME como RawContacts.CONTENT_TYPE. Por exemplo:

Kotlin

    ...
    // Creates a new Intent to insert a contact
    val intent = Intent(ContactsContract.Intents.Insert.ACTION).apply {
        // Sets the MIME type to match the Contacts Provider
        type = ContactsContract.RawContacts.CONTENT_TYPE
    }
    

Java

    ...
    // Creates a new Intent to insert a contact
    Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION);
    // Sets the MIME type to match the Contacts Provider
    intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
    

Se você já possui detalhes do contato, por exemplo, um número de telefone ou endereço de e-mail, pode inseri-los no intent como dados estendidos. Para um valor-chave, use a constante apropriada de Intents.Insert. O app de contatos exibe os dados na sua tela de inserção, permitindo que os usuários façam outras edições e inclusões.

Kotlin

    private var emailAddress: EditText? = null
    private var phoneNumber: EditText? = null
    ...
    /* Assumes EditText fields in your UI contain an email address
     * and a phone number.
     *
     */
    emailAddress = findViewById(R.id.email)
    phoneNumber = findViewById(R.id.phone)
    ...
    /*
     * Inserts new data into the Intent. This data is passed to the
     * contacts app's Insert screen
     */
    intent.apply {
        // Inserts an email address
        putExtra(ContactsContract.Intents.Insert.EMAIL, emailAddress?.text)
        /*
         * In this example, sets the email type to be a work email.
         * You can set other email types as necessary.
         */
        putExtra(
                ContactsContract.Intents.Insert.EMAIL_TYPE,
                ContactsContract.CommonDataKinds.Email.TYPE_WORK
        )
        // Inserts a phone number
        putExtra(ContactsContract.Intents.Insert.PHONE, phoneNumber?.text)
        /*
         * In this example, sets the phone type to be a work phone.
         * You can set other phone types as necessary.
         */
        putExtra(
                ContactsContract.Intents.Insert.PHONE_TYPE,
                ContactsContract.CommonDataKinds.Phone.TYPE_WORK
        )
    }
    

Java

    private EditText emailAddress = null;
    private EditText phoneNumber = null;
    ...
    /* Assumes EditText fields in your UI contain an email address
     * and a phone number.
     *
     */
    emailAddress = (EditText) findViewById(R.id.email);
    phoneNumber = (EditText) findViewById(R.id.phone);
    ...
    /*
     * Inserts new data into the Intent. This data is passed to the
     * contacts app's Insert screen
     */
    // Inserts an email address
    intent.putExtra(ContactsContract.Intents.Insert.EMAIL, emailAddress.getText())
    /*
     * In this example, sets the email type to be a work email.
     * You can set other email types as necessary.
     */
          .putExtra(ContactsContract.Intents.Insert.EMAIL_TYPE,
                ContactsContract.CommonDataKinds.Email.TYPE_WORK)
    // Inserts a phone number
          .putExtra(ContactsContract.Intents.Insert.PHONE, phoneNumber.getText())
    /*
     * In this example, sets the phone type to be a work phone.
     * You can set other phone types as necessary.
     */
          .putExtra(ContactsContract.Intents.Insert.PHONE_TYPE,
                ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
    

Depois de criar o Intent, envie-o chamando startActivity().

Kotlin

        /* Sends the Intent
         */
        startActivity(intent)
    

Java

        /* Sends the Intent
         */
        startActivity(intent);
    

Essa chamada abre uma tela no app de contatos que permite que os usuários insiram um novo contato. O tipo de conta e o nome da conta do contato são listados na parte superior da tela. Depois que os usuários inserem os dados e clicam em Concluído, a lista de contatos do app de contatos é exibida. Os usuários retornam ao seu app clicando em Voltar.

Editar um contato já existente usando um intent

A edição de um contato já existente usando um Intent é útil se o usuário já escolheu um contato de interesse. Por exemplo, um app que encontra contatos que têm endereços de correspondência, mas não têm CEP, pode dar aos usuários a opção de procurar o código postal e adicioná-lo ao contato.

Para editar um contato já existente usando um intent, use um procedimento semelhante à inserção de um contato. Crie um intent, conforme descrito na seção Inserir um novo contato usando um intent, mas adicione Contacts.CONTENT_LOOKUP_URI e o tipo MIME Contacts.CONTENT_ITEM_TYPE do contato ao intent. Para editar o contato com os detalhes que já você tem, insira-os nos dados estendidos do intent. Observe que algumas colunas de nome não podem ser editadas usando um intent. Essas colunas estão listadas na seção de resumo da referência da API para a classe ContactsContract.Contacts no título "Atualizar".

Por fim, envie o intent. Como resposta, o app de contatos exibe uma tela de edição. Quando o usuário terminar e salvar as edições, o app de contatos exibirá uma lista de contatos. Quando o usuário clicar em Voltar, seu app será exibido.

Criar o intent

Para editar um contato, chame Intent(action) para criar um intent com a ação ACTION_EDIT. Chame setDataAndType() para definir o valor dos dados do intent para Contacts.CONTENT_LOOKUP_URI e o tipo MIME do contato como Contacts.CONTENT_ITEM_TYPE. Como uma chamada para setType() substitui o valor atual dos dados para Intent, você precisa definir os dados e o tipo MIME ao mesmo tempo.

Para ver o Contacts.CONTENT_LOOKUP_URI de um contato, chame Contacts.getLookupUri(id, lookupkey) com os valores de Contacts._ID e Contacts.LOOKUP_KEY do contato como argumentos.

Observação: o valor LOOKUP_KEY de um contato é o identificador que você precisa usar para recuperar um contato. Ele permanece constante, mesmo que o provedor altere o ID da linha do contato para processar operações internas.

O seguinte snippet mostra como criar um intent:

Kotlin

        // The Cursor that contains the Contact row
        var mCursor: Cursor? = null
        // The index of the lookup key column in the cursor
        var lookupKeyIndex: Int = 0
        // The index of the contact's _ID value
        var idIndex: Int = 0
        // The lookup key from the Cursor
        var currentLookupKey: String? = null
        // The _ID value from the Cursor
        var currentId: Long = 0
        // A content URI pointing to the contact
        var selectedContactUri: Uri? = null
        ...
        /*
         * Once the user has selected a contact to edit,
         * this gets the contact's lookup key and _ID values from the
         * cursor and creates the necessary URI.
         */
        mCursor?.apply {
            // Gets the lookup key column index
            lookupKeyIndex = getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
            // Gets the lookup key value
            currentLookupKey = getString(lookupKeyIndex)
            // Gets the _ID column index
            idIndex = getColumnIndex(ContactsContract.Contacts._ID)
            currentId = getLong(idIndex)
            selectedContactUri = ContactsContract.Contacts.getLookupUri(currentId, mCurrentLookupKey)
        }

        // Creates a new Intent to edit a contact
        val editIntent = Intent(Intent.ACTION_EDIT).apply {
            /*
             * Sets the contact URI to edit, and the data type that the
             * Intent must match
             */
            setDataAndType(selectedContactUri, ContactsContract.Contacts.CONTENT_ITEM_TYPE)
        }
    

Java

        // The Cursor that contains the Contact row
        public Cursor mCursor;
        // The index of the lookup key column in the cursor
        public int lookupKeyIndex;
        // The index of the contact's _ID value
        public int idIndex;
        // The lookup key from the Cursor
        public String currentLookupKey;
        // The _ID value from the Cursor
        public long currentId;
        // A content URI pointing to the contact
        Uri selectedContactUri;
        ...
        /*
         * Once the user has selected a contact to edit,
         * this gets the contact's lookup key and _ID values from the
         * cursor and creates the necessary URI.
         */
        // Gets the lookup key column index
        lookupKeyIndex = mCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
        // Gets the lookup key value
        currentLookupKey = mCursor.getString(lookupKeyIndex);
        // Gets the _ID column index
        idIndex = mCursor.getColumnIndex(ContactsContract.Contacts._ID);
        currentId = mCursor.getLong(idIndex);
        selectedContactUri =
                Contacts.getLookupUri(currentId, mCurrentLookupKey);
        ...
        // Creates a new Intent to edit a contact
        Intent editIntent = new Intent(Intent.ACTION_EDIT);
        /*
         * Sets the contact URI to edit, and the data type that the
         * Intent must match
         */
        editIntent.setDataAndType(selectedContactUri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
    

Adicionar a sinalização de navegação

No Android 4.0 (API de nível 14) e versões posteriores, um problema no app de contatos causa um erro de navegação. Quando o app envia um intent de edição ao app de contatos, e os usuários editam e salvam um contato, quando clicam em Voltar, eles veem a tela da lista de contatos. Para voltar ao seu app, eles precisam clicar em Recentes e selecioná-lo.

Para contornar esse problema no Android 4.0.3 (API de nível 15) e versões posteriores, adicione a chave de dados estendida finishActivityOnSaveCompleted ao intent, com um valor true. As versões do Android anteriores ao Android 4.0 aceitam essa chave, ela não faz efeito. Para definir os dados estendidos, faça o seguinte:

Kotlin

        // Sets the special extended data for navigation
        editIntent.putExtra("finishActivityOnSaveCompleted", true)
    

Java

        // Sets the special extended data for navigation
        editIntent.putExtra("finishActivityOnSaveCompleted", true);
    

Adicionar outros dados estendidos

Para adicionar outros dados estendidos ao Intent, chame putExtra() conforme desejado. Você pode adicionar dados estendidos para campos de contato comuns usando os valores-chave especificados em Intents.Insert. Lembre-se de que algumas colunas da tabela ContactsContract.Contacts não podem ser modificadas. Essas colunas estão listadas na seção de resumo da referência da API para a classe ContactsContract.Contacts no título "Atualizar".

Enviar o intent

Por fim, envie o intent que você construiu. Exemplo:

Kotlin

        // Sends the Intent
        startActivity(editIntent)
    

Java

        // Sends the Intent
        startActivity(editIntent);
    

Permitir que os usuários optem por inserir ou editar usando um intent

Você pode permitir que os usuários decidam se querem inserir um contato ou editar um já existente enviando um Intent com a ação ACTION_INSERT_OR_EDIT. Por exemplo, um app cliente de e-mail pode permitir que os usuários adicionem um endereço de e-mail recebido a um novo contato ou como outro endereço de um contato já existente. Defina o tipo MIME para esse intent como Contacts.CONTENT_ITEM_TYPE, mas não defina o URI dos dados.

Quando você enviar esse intent, o app de contatos exibirá uma lista de contatos. Os usuários podem inserir um novo contato ou escolher um já existente e editá-lo. Todos os campos de dados estendidos adicionados ao intent preenchem a tela exibida. Você pode usar qualquer um dos valores-chave especificados em Intents.Insert. O seguinte snippet de código mostra como construir e enviar o intent:

Kotlin

        // Creates a new Intent to insert or edit a contact
        val intentInsertEdit = Intent(Intent.ACTION_INSERT_OR_EDIT).apply {
            // Sets the MIME type
            type = ContactsContract.Contacts.CONTENT_ITEM_TYPE
        }
        // Add code here to insert extended data, if desired

        // Sends the Intent with an request ID
        startActivity(intentInsertEdit)
    

Java

        // Creates a new Intent to insert or edit a contact
        Intent intentInsertEdit = new Intent(Intent.ACTION_INSERT_OR_EDIT);
        // Sets the MIME type
        intentInsertEdit.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
        // Add code here to insert extended data, if desired
        ...
        // Sends the Intent with an request ID
        startActivity(intentInsertEdit);