2013年04月27日

【Android】電話帳アプリの呼び出しと連絡先データの登録&検索&削除【ContentProviderOperation】

今回は電話帳アプリから連絡先を取得する方法を紹介しよう。
このサンプルは、他のアプリからデータを受信する方法の「基本形」となる。

また今回は電話帳アプリを呼び出すサンプルのみならず、電話帳へ連絡先を登録&検索&削除するサンプルも含まれていて、一石二鳥なエントリになるはずだ。

なお、以下はAndroid2.0以上を想定している。


まずはマニフェストに電話帳への読み書き許可を追加する。

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.contactssample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.contactssample.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

ポイントはここ。

<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

これでアプリに電話帳への読み書き許可を与えている。

次にメッセージリソース。

strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">電話帳操作サンプル</string>
    <string name="action_settings">設定</string>
    <string name="button_add_contacts">電話帳にサンプルデータ登録</string>
    <string name="button_pick_contact">電話帳を開く</string>

</resources>

次は画面レイアウト定義。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="addContacts"
            android:text="@string/button_add_contacts" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="pickContact"
            android:text="@string/button_pick_contact" />
    </LinearLayout>

</LinearLayout>

これは電話帳へサンプルデータを投入するボタンと、電話帳アプリを呼び出すボタンの二つだけのシンプルな画面定義である。


次はメインとなるアクティビティのソースコード。

MainActivity.java
package com.example.contactssample;

import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.util.AndroidException;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    // 電話帳アプリ呼び出しのための任意のリクエストコード
    static final int PICK_CONTACT_REQUEST = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @SuppressLint("ShowToast")
    public void addContacts(View view) throws AndroidException,
            OperationApplicationException {

        // まずは電話帳データを全削除!
        // CAUTION:★電話帳の全削除なので本番機で実行する際は注意!!!
        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null,
                null, null, null);
        while (cur.moveToNext()) {
            String lookupKey = cur.getString(cur
                    .getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
            Uri uri = Uri.withAppendedPath(
                    ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
            cr.delete(uri, null, null);
        }

        // そして電話帳に適当なデータを登録
        toastInfo(addContact("hogeyama hogetaro", "090-xxxx-xxxx"));
        toastInfo(addContact("foo baa", "080-xxxx-xxxx"));
        toastInfo(addContact("baz bazuo", "070-xxxx-xxxx"));
    }

    /**
     * 表示名と電話番号を電話帳に登録
     * 
     * @param dispname
     * @param number
     * @return {@link Uri}
     * @throws AndroidException
     * @throws AndroidException
     * @throws OperationApplicationException
     */
    private Uri addContact(String dispname, String number)
            throws AndroidException, OperationApplicationException {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        int rawContactInsertIndex = ops.size();

        ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
                .withValue(RawContacts.ACCOUNT_TYPE, null)
                .withValue(RawContacts.ACCOUNT_NAME, null).build());
        ops.add(ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(Data.RAW_CONTACT_ID,
                        rawContactInsertIndex)
                .withValue(ContactsContract.Data.MIMETYPE,
                        Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, number).build());
        ops.add(ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(Data.RAW_CONTACT_ID,
                        rawContactInsertIndex)
                .withValue(ContactsContract.Data.MIMETYPE,
                        StructuredName.CONTENT_ITEM_TYPE)
                .withValue(StructuredName.DISPLAY_NAME, dispname).build());
        ContentProviderResult[] res = getContentResolver().applyBatch(
                ContactsContract.AUTHORITY, ops);

        if (res != null) {
            return res[2].uri; // dispnameをops.addした時のindex番号のuriを返す
        } else {
            return null;
        }
    }

    /**
     * 電話帳アプリを開く
     * 
     * @param view
     */
    @SuppressLint("ShowToast")
    public void pickContact(View view) {
        Intent intent = new Intent(Intent.ACTION_PICK,
                ContactsContract.Contacts.CONTENT_URI);
        intent.setType(Phone.CONTENT_TYPE);
        startActivityForResult(intent, PICK_CONTACT_REQUEST);
    }

    /**
     * 電話帳アプリからの戻り値を受け取る
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PICK_CONTACT_REQUEST) {
            if (resultCode == RESULT_OK) {
                Uri contactUri = data.getData();
                toastInfo(contactUri);
            }
        }
    }

    /**
     * 電話帳URIから表示名と電話番号を取得してトースト表示
     * 
     * @param uri
     * 
     */
    private void toastInfo(Uri uri) {
        String[] projection = { Phone.DISPLAY_NAME, Phone.NUMBER };
        Cursor cursor = getContentResolver().query(uri, projection, null, null,
                null);
        cursor.moveToFirst();

        // 表示名取得
        int dispNameCol = cursor.getColumnIndex(Phone.DISPLAY_NAME);
        String dispName = cursor.getString(dispNameCol);
        // 電話番号取得
        int numberCol = cursor.getColumnIndex(Phone.NUMBER);
        String number = cursor.getString(numberCol);

        // 取得した情報をトースト表示
        Toast.makeText(this, "DISPLAY_NAME:" + dispName + "\nNUMBER:" + number,
                Toast.LENGTH_LONG).show();
    }
}

他アプリ呼び出し

電話帳アプリを呼び出す処理で重要なのは、
・PICK_CONTACT_REQUESTの定義と、
・pickContact()、
・onActivityResult()
の三箇所。

pickContact()では電話帳のアクティビティを戻り値を受ける形で呼び出して、onActivityResult()で電話帳アプリからの戻り値を受け取っている。
電話帳アプリに限らず、他のどのアプリを呼び出す場合も基本はこの形になる。


電話帳(Contacts)へ連絡先を登録、検索、削除

電話帳への連絡先の登録は、addContact()の中身を見て欲しい。ContentProviderOperationを巧みに利用している。ちょっと複雑だが、ここらへんの処理はよく理解しておこう。

次に電話帳から連絡先データの取得の仕方だが、toastInfo()の中で実現している。ContactUriさえ取得できれば、連絡先データも取得できるのである。

そして電話帳から連絡先データを削除する方法は、addContacts()の先頭行で行なっている。
削除の基本は cursor.delete(uri, null, null); である。


■参考にさせていただいたサイト
ContentProviderOperation によるアドレス帳へのアクセス : カネチの備忘録
Inserting contacts in Android 2.2 : Stack Overflow
posted by 寄り道退屈男 at 16:56 | Comment(0) | TrackBack(0) | Android
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/65758306
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック