インテントを使用して連絡先を編集する

このレッスンでは、Intent を使用して新しい連絡先を挿入する方法や既存の連絡先データを編集する方法について説明します。Intent は、連絡先プロバイダに直接アクセスするのではなく、連絡先アプリを起動して、適切な Activity を実行します。このレッスンで説明する編集アクションの場合、Intent を使用して拡張データを送信すると、起動した Activity の UI に入力されます。

Intent を使用して単一の連絡先の挿入や更新を行う方法は、連絡先プロバイダを編集する方法として適しています。たとえば、以下のようなメリットがあります。

  • 独自の UI とコードを開発する時間と労力を節約できます。
  • 連絡先プロバイダのルールに沿わない編集によって引き起こされるエラーの発生を回避できます。
  • リクエストする必要のあるパーミッションの数の削減できます。アプリは、すでに書き込みパーミッションを持っている連絡先アプリに編集処理を委任するため、連絡先プロバイダに対する書き込みパーミッションを取得する必要がありません。

インテントを使用して新しい連絡先を挿入する

アプリが新しいデータを受信したときに、ユーザーが新しい連絡先を挿入できるようにしたい場合があります。たとえば、レストランのレビューアプリの場合、ユーザーがレストランをレビューするときに、連絡先として追加できると便利です。インテントを使用してこの処理を行うには、利用可能なデータをすべて使用してインテントを作成し、連絡先アプリにインテントを送信します。

連絡先アプリを使用して連絡先を挿入すると、新しい未加工連絡先が連絡先プロバイダの ContactsContract.RawContacts テーブルに挿入されます。必要に応じて、連絡先アプリは、未加工連絡先を作成する際に使用するアカウント タイプとアカウント名をユーザーに求めます。連絡先アプリは、未加工の連絡先がすでに存在する場合もユーザーに通知します。ユーザーは、挿入をキャンセルするオプションを持っており、キャンセルすると連絡先は作成されません。未加工連絡先の詳細については、Contacts Provider API ガイドをご覧ください。

インテントを作成する

まず、Intents.Insert.ACTION アクションを使用して、新しい Intent オブジェクトを作成します。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);
    

電話番号やメールアドレスなど、詳細な連絡先情報をすでに持っている場合は、それを拡張データとしてインテントに挿入します。Key-Value には、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_URIContacts.CONTENT_ITEM_TYPE MIME タイプをインテントに追加します。入手済みの詳細情報を使用して連絡先を編集したい場合は、インテントの拡張データに追加します。なお、インテントでは編集できない名前列もあります。該当する列については、ContactsContract.Contacts クラス API リファレンスの「概要」にある「更新」のリストをご覧ください。

最後に、インテントを送信します。レスポンスとして、連絡先アプリが編集画面を表示します。ユーザーが編集を終了して保存すると、連絡先アプリは、連絡先リストを表示します。ユーザーが [戻る] をタップすると、元のアプリが表示されます。

インテントを作成する

連絡先を編集するには、Intent(action) を呼び出して、ACTION_EDIT アクションを使用してインテントを作成します。setDataAndType() を呼び出して、インテントのデータ値を連絡先の Contacts.CONTENT_LOOKUP_URI に設定し、MIME タイプを Contacts.CONTENT_ITEM_TYPE MIME タイプに設定します。setType() 呼び出すと Intent の現在のデータ値が上書きされるため、データ値と MIME タイプを同時に設定する必要があります。

連絡先の Contacts.CONTENT_LOOKUP_URI を取得するには、連絡先の Contacts._ID 値と Contacts.LOOKUP_KEY 値を引数として、Contacts.getLookupUri(id, lookupkey) を呼び出します。

注: 連絡先の LOOKUP_KEY 値は、連絡先を取得する際に使用する ID です。この値は、プロバイダが内部処理を行うために連絡先の行 ID を変更した場合でも、一定のまま変わりません。

インテントを作成する方法を次のスニペットに示します。

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 より前の Android バージョンもこのキーを受け入れますが、効果はありません。拡張データを設定する手順は次のとおりです。

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 内で指定した Key-Value を使用して、一般的な連絡先フィールドに追加することができます。なお、ContactsContract.Contacts テーブルの中には、編集できない列があります。該当する列については、ContactsContract.Contacts クラス API リファレンスの「概要」にある「更新」のリストをご覧ください。

インテントを送信する

最後に、作成したインテントを送信します。たとえば、次のようになります。

Kotlin

        // Sends the Intent
        startActivity(editIntent)
    

Java

        // Sends the Intent
        startActivity(editIntent);
    

インテントを使用して、挿入と編集のいずれを行うのかユーザーが選択できるようにする

ACTION_INSERT_OR_EDIT アクションを使用して Intent を送信すると、連絡先を挿入するのか、既存の連絡先を編集するのかをユーザーが選択できるようになります。たとえば、メール クライアント アプリの場合、受信メールアドレスを新しい連絡先として追加するのか、既存の連絡先の追加アドレスとして追加するのかをユーザーが選択できます。このインテントは、MIME タイプを Contacts.CONTENT_ITEM_TYPE に設定します。データ URI は設定しません。

このインテントを送信すると、連絡先アプリが連絡先のリストを表示します。ユーザーは、新しい連絡先を挿入するか、既存の連絡先を選択して編集することができます。インテントに追加した拡張データ フィールドが、表示される画面に示されます。Intents.Insert 内で指定した任意の Key-Value を使用できます。インテントを作成して送信する方法を次のコード スニペットに示します。

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