Как изменять контакты с помощью намерений

В этом уроке показано, как использовать Intent для вставки нового контакта или изменения данных контакта. Вместо того чтобы обращаться к поставщику контактов напрямую, Intent запускает приложение "Контакты", которое выполняет соответствующее Activity. Если вы отправляете расширенные данные в Intent, они вводятся в интерфейс запускаемого Activity.

Использование Intent для вставки или обновления одного контакта – предпочтительный способ изменения поставщика контактов по следующим причинам:

  • Это позволяет сэкономить время и силы на разработку собственного интерфейса и кода.
  • Это позволяет избежать ошибок, вызванных изменениями, которые не соответствуют правилам поставщика контактов.
  • Вам нужно будет запрашивать меньше разрешений. Вашему приложению не требуется разрешение на запись в поставщик контактов, поскольку оно делегирует изменения приложению "Контакты", у которого уже есть это разрешение.

Как добавить новый контакт с помощью намерения

Часто требуется разрешить пользователю вставлять новый контакт, когда приложение получает новые данные. Например, приложение с отзывами о ресторанах может позволить пользователям добавлять ресторан в качестве контакта при написании отзыва. Для этого создайте намерение, используя все доступные данные, а затем отправьте его в приложение "Контакты".

При добавлении контакта через приложение "Контакты" в таблицу ContactsContract.RawContacts поставщика контактов вставляется новый необработанный контакт. При необходимости приложение "Контакты" предлагает пользователям выбрать тип аккаунта и аккаунт, который будет использоваться при создании необработанного контакта. Приложение "Контакты" также уведомляет пользователей, если необработанный контакт уже существует. Пользователи могут отменить вставку, и в этом случае контакт не будет создан. Подробнее о необработанных контактах рассказывается в руководстве по API поставщика контактов.

Создать намерение

Для начала создайте новый объект Intent с действием Intents.Insert.ACTION. Укажите MIME-тип RawContacts.CONTENT_TYPE. Пример:

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);

Если у вас уже есть сведения о контакте, например номер телефона или адрес электронной почты, вы можете вставить их в намерение в качестве расширенных данных. Для значения ключа используйте подходящую константу из Intents.Insert. Приложение "Контакты" отображает данные на экране вставки, позволяя пользователям вносить дополнительные изменения и дополнения.

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);

Создав объект Intent, отправьте его, вызвав метод startActivity().

Kotlin

    /* Sends the Intent
     */
    startActivity(intent)

Java

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

Этот вызов открывает экран в приложении "Контакты", на котором пользователи могут ввести данные нового контакта. Тип и название аккаунта, в котором сохранен контакт, указаны в верхней части экрана. После того как пользователь введет данные и нажмет Готово, появится список контактов приложения "Контакты". Чтобы вернуться в приложение, пользователь нажимает Назад.

Как изменить существующий контакт с помощью намерения

Редактирование существующего контакта с помощью Intent полезно, если пользователь уже выбрал нужный контакт. Например, приложение, которое находит контакты с почтовыми адресами, но без почтового индекса, может предоставить пользователям возможность найти индекс и добавить его в контакт.

Чтобы изменить существующий контакт с помощью намерения, используйте процедуру, аналогичную вставке контакта. Создайте намерение, как описано в разделе Добавление нового контакта с помощью намерения, но добавьте в него Contacts.CONTENT_LOOKUP_URI контакта и MIME-тип Contacts.CONTENT_ITEM_TYPE. Если вы хотите изменить контакт, используя уже имеющиеся у вас данные, вы можете поместить их в расширенные данные намерения. Обратите внимание, что некоторые столбцы с названиями нельзя изменить с помощью намерения. Они перечислены в разделе сводки документации по API для класса ContactsContract.Contacts под заголовком Update (Обновление).

Наконец, отправьте намерение. В ответ приложение "Контакты" показывает экран редактирования. Когда пользователь закончит редактирование и сохранит изменения, приложение "Контакты" покажет список контактов. Когда пользователь нажимает Назад, снова открывается ваше приложение.

Создайте намерение

Чтобы изменить контакт, вызовите Intent(action) для создания намерения с действием ACTION_EDIT. Вызовите метод setDataAndType(), чтобы задать значение данных для намерения, соответствующее Contacts.CONTENT_LOOKUP_URI контакта, и MIME-тип, соответствующий MIME-типу Contacts.CONTENT_ITEM_TYPE. Поскольку вызов метода setType() перезаписывает текущее значение данных для Intent, необходимо задать данные и MIME-тип одновременно.

Чтобы получить Contacts.CONTENT_LOOKUP_URI контакта, вызовите Contacts.getLookupUri(id, lookupkey) со значениями Contacts._ID и Contacts.LOOKUP_KEY контакта в качестве аргументов.

Примечание. Значение LOOKUP_KEY контакта – это идентификатор, который следует использовать для получения контакта. Он остается неизменным, даже если поставщик меняет идентификатор строки контакта для выполнения внутренних операций.

В следующем фрагменте кода показано, как создать намерение:

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);

Добавьте флажок навигации

В Android 4.0 (API версии 14) и более поздних версиях из-за проблемы в приложении "Контакты" навигация работает некорректно. Когда ваше приложение отправляет намерение редактирования в приложение "Контакты", пользователи редактируют и сохраняют контакт, а затем нажимают кнопку Назад, чтобы вернуться к списку контактов. Чтобы вернуться в ваше приложение, пользователю нужно нажать Недавние и выбрать его.

Чтобы обойти эту проблему в Android 4.0.3 (API версии 15) и более поздних версиях, добавьте в намерение ключ расширенных данных finishActivityOnSaveCompleted со значением true. В версиях Android до 4.0 этот ключ принимается, но не действует. Чтобы задать расширенные данные, выполните следующие действия:

Kotlin

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

Java

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

Добавьте другие расширенные данные

Чтобы добавить в Intent дополнительные расширенные данные, вызовите putExtra(). Вы можете добавить расширенные данные для стандартных полей контактов, используя пары "ключ-значение", указанные в Intents.Insert. Помните, что некоторые столбцы в таблице ContactsContract.Contacts нельзя изменить. Эти столбцы перечислены в разделе сводки в документации по API для класса ContactsContract.Contacts под заголовком "Обновление".

Отправить намерение

Наконец, отправьте созданное намерение. Пример:

Kotlin

    // Sends the Intent
    startActivity(editIntent)

Java

    // Sends the Intent
    startActivity(editIntent);

Разрешите пользователям выбирать, вставлять или редактировать с помощью намерения

Вы можете разрешить пользователям выбирать, вставлять ли контакт или редактировать существующий, отправив Intent с действием ACTION_INSERT_OR_EDIT. Например, почтовый клиент может позволить пользователям добавлять адрес электронной почты входящего письма в новый контакт или в качестве дополнительного адреса для существующего контакта. Задайте для этого намерения MIME-тип Contacts.CONTENT_ITEM_TYPE, но не указывайте URI данных.

При отправке этого намерения приложение "Контакты" показывает список контактов. Пользователи могут добавить новый контакт или выбрать существующий и изменить его. Все поля расширенных данных, которые вы добавляете в намерение, заполняют появившийся экран. Вы можете использовать любые значения ключей, указанные в Intents.Insert. В следующем фрагменте кода показано, как создать и отправить намерение:

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);