728x90

로그인한 폰의 전화번호를 자동으로 인식하여 가져오는 코드다.

DB 에 등록된 전화번호와 로그인한 전화번호가 다른지 파악해 달라는 요청으로 검색하고 수정했다.


AndroidManifest.xml 파일에 추가할 사항

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


전화번호 자동 읽어오기 코드

@SuppressLint("MissingPermission")
public String getPhoneNumber() {
    TelephonyManager telephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    String phoneNumber = "";
    try {
        if (telephony.getLine1Number() != null) {
            phoneNumber = telephony.getLine1Number();
        } else {
            if (telephony.getSimSerialNumber() != null) {
                phoneNumber = telephony.getSimSerialNumber();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (phoneNumber.startsWith("+82")) {
        phoneNumber = phoneNumber.replace("+82", "0");
// +8210xxxxyyyy 로 시작되는 번호

    }
    //phoneNumber = phoneNumber.substring(phoneNumber.length()-10,phoneNumber.length());
    //phoneNumber="0"+phoneNumber;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        phoneNumber = PhoneNumberUtils.formatNumber(phoneNumber, Locale.getDefault().getCountry());
    } else {
        phoneNumber = PhoneNumberUtils.formatNumber(phoneNumber);
    }
    return phoneNumber;
}



2020.3.26 Update

코틀린에서 전화번호 읽어오는 함수로 변환했더니 아래와 같은 결과를 반환했다.

fun getPhoneNumber(): String {
    val telephony =
        getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    var phoneNumber = ""
    try {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_SMS
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_PHONE_NUMBERS
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            return ""
        }
        if (telephony.line1Number != null) {
            phoneNumber = telephony.line1Number
        } else {
            if (telephony.simSerialNumber != null) {
                phoneNumber = telephony.simSerialNumber
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    if (phoneNumber.startsWith("+82")) {
        phoneNumber = phoneNumber.replace("+82", "0")
    }
    phoneNumber = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        PhoneNumberUtils.formatNumber(
            phoneNumber,
            Locale.getDefault().country
        )
    } else {
        PhoneNumberUtils.formatNumber(phoneNumber)
    }
    return phoneNumber
}


블로그 이미지

Link2Me

,
728x90

안드로이드 연락처(Contacts) 에 있는 데이터를 메모리로 읽어오기 위한 방법은 ArrayList 를 여러개 선언하는 방법도 있지만, Contact_Item 클래스를 만들고 HashTable 를 사용해서 메모리에 저장하는 방법이 좋다.


Contacts_Item 클래스를 정의하는 방법은 http://link2me.tistory.com/1251 게시글을 참조하면 된다.

여기서는 결과를 적는다.

단순하게 연락처에 있는 데이터를 가져오는 클래스가 아니라 서버에 있는 데이터를 연락처에 내려받아 저장한 데이터를 가져오기 위한 것이라 형태가 다른 contactKey 를 추가했다.


 public class Contacts_Item {   
    String contactId; // 연락처(Contacts) Contact_ID 로 데이터 수정/삭제 키 값
    String contactName; // 연락처 표시이름
    String contactmobileNO; // 연락처 휴대폰번호
    String contactofficeNO; // 연락처 사무실번호
    String contactKey; // 서버와의 데이터 동기화를 위한 키

    public Contacts_Item() {
    }

    public Contacts_Item(String contactId, String contactName, String contactmobileNO, String contactofficeNO, String contactKey) {
        this.contactId = contactId;
        this.contactName = contactName;
        this.contactmobileNO = contactmobileNO;
        this.contactofficeNO = contactofficeNO;
        this.contactKey = contactKey;
    }

    public String getContactId() {
        return contactId;
    }

    public void setContactId(String contactId) {
        this.contactId = contactId;
    }

    public String getContactName() {
        return contactName;
    }

    public void setContactName(String contactName) {
        this.contactName = contactName;
    }

    public String getContactmobileNO() {
        return contactmobileNO;
    }

    public void setContactmobileNO(String contactmobileNO) {
        this.contactmobileNO = contactmobileNO;
    }

    public String getContactofficeNO() {
        return contactofficeNO;
    }

    public void setContactofficeNO(String contactofficeNO) {
        this.contactofficeNO = contactofficeNO;
    }

    public String getContactKey() {
        return contactKey;
    }

    public void setContactKey(String contactKey) {
        this.contactKey = contactKey;
    }
}


연락처 Hashtable 를 선언, 등록, 사용하는 방법이다.

HashMap 에 대한 기본 개념은 http://link2me.tistory.com/1210 참조하면 된다.


선언

HashMap<String, Contacts_Item> contactMap = new HashMap<String, Contacts_Item>();


등록

temp_ID 와 temp_keyIDX 는 개념 설명이므로 실 코드는 기록하지 않는다.

Contacts_Item item = new Contacts_Item(); 객체를 생성하고 데이터를 저장한 다음, 선언한 HashMap 에 저정한다. contactMap.put(temp_key, item);


public void Contacts2ArrayList() {
    contactMap.clear(); // 메모리 초기화
    Cursor cursor = ContactHelper.LoadContactsCursor(context.getContentResolver(), search_name);
    cursor.moveToFirst();
    System.out.println("연락처 개수 = " + cursor.getCount());
    while (!cursor.isAfterLast()) {
        String ContactId = cursor.getString(0);
        String temp_key = "";
        if (temp_ID.indexOf(ContactId) > -1) {
            temp_key = temp_keyIDX.get(temp_ID.indexOf(ContactId));
        }
        if (!temp_key.equals("")) { // if 문은 상황에 따라 사용여부 결정하면 된다.
            Contacts_Item item = new Contacts_Item();
            item.setContactId(ContactId);
            item.setContactName(cursor.getString(1));
            item.setContactmobileNO(cursor.getString(2));
            item.setContactofficeNO(cursor.getString(3));
            item.setContactKey(temp_key);
            contactMap.put(temp_key, item);
        }
        cursor.moveToNext();
    }
    cursor.close();
}


검색

if (contactMap.containsKey(idx)) {
    Contacts_Item item = contactMap.get(idx);
    String contactName = item.getContactName();
    String contactId = item.getContactId();
    String contactmNO = item.getContactmobileNO();
    String contactoNO = item.getContactofficeNO();

   

    // 실제 처리할 메소드 추가하면 된다.

}


블로그 이미지

Link2Me

,
728x90

안드로이드 연락처(Contacts)를 추가시 사진 이미지를 다운로드 하는 메소드를 추가했다.

안드로이드에서 이미지를 다루기 위한 객체로 Bitmap을 많이 사용한다.
실질적으로 파일을 저장할 때 jpeg을 많이 사용하므로 관련 코드를 고려했다.


 public class ContactHelper {
    // 신규 추가(성명, 휴대폰번호, 사무실번호, 이메일, 사진, IDX, groupId)
    public static void insertPhoneContacts(Context context, String display_name, String mobileNO, String officeNO,
            String strEmail, String strPhoto, String strIDX, long groupId) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
        ops.add(op.build());

        // DISPLAY NAME(성명)
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, display_name);
        ops.add(op.build());

        // 그룹 세팅
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
        ops.add(op.build());

        // 휴대폰 번호
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mobileNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, strIDX)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
        ops.add(op.build());

        // 사무실 번호
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, officeNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);

        op.withYieldAllowed(true);
        ops.add(op.build());

        // EMAIL
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.DATA, strEmail)
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK);
        ops.add(op.build());

        // Photo Image
        Bitmap cachedImage = DownloadImageFromPath(strPhoto);
        if (cachedImage != null) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            cachedImage.compress(CompressFormat.JPEG, 100, out);

            byte[] b = out.toByteArray();

            op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b);
            ops.add(op.build());

        }

        try {
            context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }

    }

    // 이미지 다운로드
    private static Bitmap DownloadImageFromPath(String path) {
        InputStream instream = null;
        Bitmap image = null;
        int responseCode = -1;
        try {

            URL url = new URL(path); // "http://192.168.xx.xx/imagepath/img1.jpg
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.connect();
            responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // download
                instream = conn.getInputStream();
                image = BitmapFactory.decodeStream(instream);
                instream.close();
            }

        } catch (Exception ex) {
            Log.e("Exception", ex.toString());
        }
        return image;
    }
   
}


이미지 크기와 높이를 조정하는 코드는 https://stackoverflow.com/questions/18210700/best-method-to-download-image-from-url-in-android 참조하면 된다.

블로그 이미지

Link2Me

,
728x90

안드로이드 연락처에 그룹명을 생성하고, 그룹에 인원을 추가하는 코드다.


사용법

String group_name ="그룹명";
long groupId = ContactHelper.getGroupId(getContentResolver(), group_name);
if(groupId == 0){ // 해당 그룹이 없으면 추가
    ContactHelper.createNewGroup(getContentResolver(), group_name);

    groupId = ContactHelper.getGroupId(getContentResolver(), group_name);

}
long rawId = ContactHelper.getrawIdFromContactId(getContentResolver(),30255);

// 그룹에 인원 추가
ContactHelper.addContactToGroup(getContentResolver(),rawId,groupId);

※ 이 코드를 계속 실행하면 데이터가 계속 추가되는 현상이 있는데 해결 코드를 추가로 구현해야 할 거 같다.


//****************** Contact Group ***************************/
// 그룹에 인원 추가하기
public static boolean addContactToGroup(ContentResolver contactHelper,long rawId, long groupId) {
    try {
        ContentValues values = new ContentValues();
        values.put(RawContacts.Data.RAW_CONTACT_ID, rawId);
        values.put(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
        values.put(RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
        contactHelper.insert(ContactsContract.Data.CONTENT_URI, values);
        return true;
    } catch (Exception e){
        e.printStackTrace();
    }
    return false;
}

// 그룹 ID 조회
public static long getGroupId(ContentResolver contactHelper, String group_name) {
    long group_id = 0;

    Uri contactUri = ContactsContract.Groups.CONTENT_URI;
    String[] projection = {ContactsContract.Groups._ID};
    String where = ContactsContract.Groups.TITLE + " = ?";
    String[] whereParams = {group_name};

    Cursor cursor = contactHelper.query(contactUri, projection, where, whereParams, null);
    if (cursor.moveToFirst()) {
        do {
            group_id = cursor.getLong(0);
            Log.e("title", group_name);
            Log.e("id", Long.toString(group_id));
        } while (cursor.moveToNext());
    }

    return group_id;
}

// 그룹 추가
public static void createNewGroup(ContentResolver contactHelper, String group_name) {
    ContentValues cv = new ContentValues();
    cv.put(ContactsContract.Groups.TITLE, group_name);
    cv.put(ContactsContract.Groups.DELETED, 0);
    cv.put(ContactsContract.Groups.SHOULD_SYNC, true);
    cv.put(ContactsContract.Groups.GROUP_VISIBLE, 1);
    contactHelper.insert(ContactsContract.Groups.CONTENT_URI, cv);
}

// 그룹명 수정
public static void updateGroup(ContentResolver contactHelper, String name, long groupId) {
    ContentValues cv = new ContentValues();
    cv.put(ContactsContract.Groups.TITLE, name);
    contactHelper.update(ContactsContract.Groups.CONTENT_URI, cv,
            ContactsContract.Groups._ID + " = " + groupId, null);
}

// 그룹 삭제
public static void deleteGroup(ContentResolver contactHelper, long groupId) {
    Uri contactUri = ContactsContract.Groups.CONTENT_URI;
    String where = ContactsContract.Groups._ID + " = " + groupId;
    contactHelper.delete(contactUri, where, null);
}

public static long getrawIdFromContactId(ContentResolver contactHelper, long contactId) {
    // ContactsContract.RawContacts._ID = ContactsContract.Data.RAW_CONTACT_ID
    long rawId = -1;
    Uri contactUri = ContactsContract.RawContacts.CONTENT_URI;
    String[] projection = {RawContacts._ID};
    String where = RawContacts.CONTACT_ID + "=?";
    String[] whereParams = new String[]{String.valueOf(contactId)};
    Cursor cursor = null;

    try {
        cursor = contactHelper.query(contactUri, projection, where, whereParams, null);
        if (cursor.moveToFirst()) {
            rawId = cursor.getLong(cursor.getColumnIndex(RawContacts._ID));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return rawId;
}




블로그 이미지

Link2Me

,
728x90

안드로이드 연락처(Contacts)를 신규 추가하는 코드다.

메소드 Overloading 을 사용해서 신규 저장하는 코드를 여러개 만들었다.

※ 메소드 오버로딩 : 같은 클래스내 같은 메소드명, 매개변수명이 다르거나 개수가 다르다.


본 코드가 구글 검색으로 찾은 코드와 다른 점 한가지가 있다.

.withValue(ContactsContract.CommonDataKinds.Phone.LABEL, strIDX)

서버 데이터를 Contacts 에 저장하고 비교를 해서 없는 것은 추가하고 있는 것은 달라진 정보만 업데이트하는 로직으로 구현하려고 이름 + 휴대폰번호 정보를 key 로 사용하고자 했으나,

서버 데이터에서 이름 + 휴대폰번호 중 한가지 정보가 달라지면 Contacts 에서는 처리하기가 어려울 거 같았다.

그래서 Contacts 에서 key로 사용할 칼럼을 고민하다가 휴대폰 번호가 가장 검색하기가 쉬운 점에 착안하여 위 칼럼을 key 로 사용했고, 결과는 대성공이다.


import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.RawContacts;
import android.util.Log;

public class ContactHelper {

    // 연락처 신규 저장
    public static void insertPhoneContacts(Context context, String strName, String mobileNO, String officeNO, String strIDX) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
        ops.add(op.build());

        // DISPLAY NAME(성명)
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName);
        ops.add(op.build());

        // 휴대폰 번호
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mobileNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, strIDX)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
        ops.add(op.build());

        // 사무실 번호
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, officeNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);

        op.withYieldAllowed(true);
        ops.add(op.build());

        try {
            context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }

    }

    public static void insertPhoneContacts(Context context, String strName, String mobileNO, String officeNO,
            String strEmail, String strTeam, String strPosition, String strMission, String strPhoto, String strIDX) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
        ops.add(op.build());

        // DISPLAY NAME(성명)
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName);
        ops.add(op.build());

        // 휴대폰 번호
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mobileNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, strIDX)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
        ops.add(op.build());

        // 사무실 번호
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, officeNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
        ops.add(op.build());

        // EMAIL
        op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.DATA, strEmail)
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK);
        ops.add(op.build());

        // Photo Image
        MemoryCache memoryCache = new MemoryCache();
        Bitmap cachedImage = memoryCache.get(strPhoto);
        if (cachedImage != null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            cachedImage.compress(CompressFormat.JPEG, 100, baos);

            byte[] b = baos.toByteArray();

            op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b);
            ops.add(op.build());
        }

        /* Organization */
        op = ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, strPosition)
                .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, "회사명")
                .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, strTeam)
                .withValue(ContactsContract.CommonDataKinds.Organization.JOB_DESCRIPTION, strPosition)
                .withValue(ContactsContract.CommonDataKinds.Organization.TYPE,
                        ContactsContract.CommonDataKinds.Organization.TYPE_WORK);
        op.withYieldAllowed(true);
        ops.add(op.build());

        try {
            context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }

    }
    
    // 연락처 신규 저장
    public static void insertPhoneContacts(Context context, String strName, String mobileNO, String officeNO, String strEmail,
            String strTeam, String strPosition, String strMission, String strPhoto, String strNote, String strIDX) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build());
        // DISPLAY NAME(성명)
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName).build());
        // 휴대폰 번호
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mobileNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, strIDX)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
                .build());
        // 사무실 번호
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, officeNO)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK).build());
        // EMAIL
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.DATA, strEmail)
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK).build());

         //메모
         ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
         .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
         .withValue(ContactsContract.Data.MIMETYPE,
         ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
         .withValue(ContactsContract.CommonDataKinds.Note.NOTE, strNote).build());

        /* Organization */
        ops.add(ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, strPosition)
                .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, "회사명")
                .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, strTeam)
                .withValue(ContactsContract.CommonDataKinds.Organization.JOB_DESCRIPTION, strPosition)
                .withValue(ContactsContract.CommonDataKinds.Organization.TYPE,
                        ContactsContract.CommonDataKinds.Organization.TYPE_WORK).build());

        // Photo Image
        MemoryCache memoryCache = new MemoryCache();
        Bitmap cachedImage = memoryCache.get(strPhoto);
        if (cachedImage != null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            cachedImage.compress(CompressFormat.JPEG, 100, baos);

            byte[] b = baos.toByteArray();

            ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b).build());
        }

        try {
            // 연락처 제공자는 applyBatch()에서의 모든 작업을 하나의 트랜잭션으로서 수행
            context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }

    }
}



블로그 이미지

Link2Me

,
728x90

성명(표시이름)과 휴대폰번호가 동일한 자료 기준으로 다른 정보들이 다를 경우, 없을 경우 수정(Update)하는 메소드다.

본 코드는 테스트시 성공적으로 잘 업데이트되는 걸 확인하고 적어둔다.

contactId, rawContactId 구하는 메소드는 다른 게시글에 올려져 있다.


public static boolean UpdateContactsInfo(ContentResolver contactHelper, String display_name, String mobileNO,
                                         String officeNO, String email, String OgnizationTitle, String OgnizationData, String contactNote) {
    if (mobileNO.equals("")) {
        return false;
    }
    long contactId = -1;

    // 성명과 휴대폰번호 기준으로 rawContactId 를 구한다.
    contactId = getContactIdFromNameAndNumber(contactHelper, display_name, mobileNO);
    if (contactId < 1) return false; // 데이터가 존재하지 않으면 바로 빠져나온다.
    long rawContactId = getrawIdFromContactId(contactHelper, contactId);

    ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    Uri contactUri = ContactsContract.Data.CONTENT_URI;
    String where = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Contacts.Data.MIMETYPE + "=?";

    // work number
    if (!officeNO.equals("")) {
        // 사무실 전화의 where 조건은 달라서 별도로 지정
        String selectPhone = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" +
                Phone.CONTENT_ITEM_TYPE + "'" + " AND " + Phone.TYPE + "=?";
        String[] phoneNumParams = new String[]{String.valueOf(contactId), String.valueOf(Phone.TYPE_WORK)};
        Cursor phoneNumCursor = contactHelper.query(contactUri, null, selectPhone, phoneNumParams, null);
        if (phoneNumCursor.getCount() > 0) {
            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                    .withSelection(selectPhone, phoneNumParams)
                    .withValue(Phone.NUMBER, officeNO)
                    .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK)
                    .build());
        } else {
            ContentValues cv = new ContentValues();
            cv.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
            cv.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
            cv.put(ContactsContract.CommonDataKinds.Phone.DATA, officeNO);
            cv.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
            ops.add(android.content.ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
                    .withValues(cv).build());
        }
    }

    // email
    if (!email.equals("")) {
        String[] emailParams = new String[]{String.valueOf(contactId), ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE};
        Cursor emailCursor = contactHelper.query(contactUri, null, where, emailParams, null);
        if (emailCursor.getCount() > 0) {
            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                    .withSelection(where, emailParams)
                    .withValue(ContactsContract.CommonDataKinds.Email.DATA, email)
                    .build());
        } else {
            ContentValues cValues = new ContentValues();
            cValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
            cValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
            cValues.put(ContactsContract.CommonDataKinds.Email.DATA, email);
            ops.add(android.content.ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
                    .withValues(cValues)
                    .build());
        }
    }

    // 조직(organization)
    if (OgnizationData != "" || OgnizationTitle != "") {
        String[] orgParams = new String[]{String.valueOf(contactId), ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE};
        Cursor orgCursor = contactHelper.query(contactUri, null, where, orgParams, null);
        if (orgCursor.getCount() > 0) {
            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                    .withSelection(where, orgParams)
                    .withValue(ContactsContract.CommonDataKinds.Organization.DATA, OgnizationData)
                    .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, OgnizationTitle)
                    .build());
        } else {
            ContentValues cValues = new ContentValues();
            cValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
            cValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
            cValues.put(ContactsContract.CommonDataKinds.Organization.DATA, OgnizationData);
            cValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, OgnizationTitle);
            ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
                    .withValues(cValues)
                    .build());
        }
    }

    // note
    if (!contactNote.equals("")) {
        String[] noteParams = new String[]{String.valueOf(contactId), ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE};
        Cursor noteCursor = contactHelper.query(contactUri, null, where, noteParams, null);
        if (noteCursor.getCount() > 0) {
            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                    .withSelection(where, noteParams)
                    .withValue(ContactsContract.CommonDataKinds.Note.NOTE, contactNote)
                    .build());
        } else {
            ContentValues cValues = new ContentValues();
            cValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
            cValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
            cValues.put(ContactsContract.CommonDataKinds.Note.NOTE, contactNote);
            ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
                    .withValues(cValues)
                    .build());
        }
    }

    try {
        // 연락처 제공자는 applyBatch()에서의 모든 작업을 하나의 트랜잭션으로서 수행
        contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        return true;
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (OperationApplicationException e) {
        e.printStackTrace();
    }
    return false;
} 


블로그 이미지

Link2Me

,
728x90

연락처 수정 기능 테스트를 하다보니 rawId를 구해야 하는 경우가 있어서 코드를 추가했다.

ContactsContract.RawContacts._ID = ContactsContract.Data.RAW_CONTACT_ID


public static long getrawIdFromContactId(ContentResolver contactHelper, long contactId) {
    // ContactsContract.RawContacts._ID = ContactsContract.Data.RAW_CONTACT_ID
    long rawId = -1;
    Uri contactUri = ContactsContract.RawContacts.CONTENT_URI;
    String[] projection = {RawContacts._ID};
    String where = RawContacts.CONTACT_ID + "=?";
    String[] whereParams = new String[]{String.valueOf(contactId)};
    Cursor cursor = null;

    try {
        cursor = contactHelper.query(contactUri, projection, where, whereParams, null);
        if (cursor.moveToFirst()) {
            rawId = cursor.getLong(cursor.getColumnIndex(RawContacts._ID));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(cursor != null){
            cursor.close();
        }
    }
    return rawId;
}

 public static long getContactIDFromrawId(ContentResolver contactHelper, long rawId) {
    long rawContactId = -1;
    Uri contactUri = ContactsContract.RawContacts.CONTENT_URI;
    String[] projection = {RawContacts.CONTACT_ID};
    String where = RawContacts._ID + "=?";
    String[] whereParams = new String[]{String.valueOf(rawId)};
    Cursor cursor = null;

    try {
        cursor = contactHelper.query(contactUri, projection, where, whereParams, null);
        if (cursor.moveToFirst()) {
            rawContactId = cursor.getLong(cursor.getColumnIndex(RawContacts.CONTACT_ID));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(cursor != null){
            cursor.close();
        }
    }
    return rawContactId;
}


블로그 이미지

Link2Me

,
728x90

안드로이드 연락처(Contacts) 정보를 수정(update)하는 메소드 중에서 휴대폰번호를 수정하는 코드를 테스트해보고 적어둔다.


ContactId 구하는 방법은 http://link2me.tistory.com/1313 에 있다.

사용법(Usage) : ContactHelper.updateContact(getContentResolver(), 17906, "010-1111-0000");

간단하게 수동으로 직접 적어서 테스트했다.


// CONTACT_ID 를 알고 있을 경우 휴대폰번호를 수정(update)하는 메소드
public static void updateContact(ContentResolver contactHelper, long contactId, String newNumber) {
    ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    String wherePHone = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='"
            + Phone.CONTENT_ITEM_TYPE + "' AND " + Phone.TYPE + "=?";

    String[] phoneArgs = new String[] { String.valueOf(contactId), String.valueOf(Phone.TYPE_MOBILE) };
    ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
            .withSelection(wherePHone, phoneArgs)
            .withValue(Phone.NUMBER, newNumber).build());
    try {
        contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (OperationApplicationException e) {
        e.printStackTrace();
    }
}



블로그 이미지

Link2Me

,
728x90

안드로이드 연락처(Contacts)에서 ContactId 를 구하는 방법 테스트한 것을 적어둔다.


 Contacts._ID = PhoneLookup._ID = Phone.CONTACT_ID = RawContacts.CONTACT_ID

import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract;

Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
// 검색할 칼럼 정하기, null 이면 모든 필드
String[] projection = {Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER, Phone.TYPE};
String where = Phone.DISPLAY_NAME + " like \'%" + display_name + "%\' AND " + Phone.TYPE + "=2";
String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor cursor = cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
long rawContactId = cursor.getLong(cursor.getColumnIndex(Phone.CONTACT_ID));

Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
// 검색할 칼럼 정하기, null 이면 모든 필드
String[] projection = {PhoneLookup._ID, PhoneLookup.DISPLAY_NAME, PhoneLookup.NUMBER};
Cursor cursor = contactHelper.query(contactUri, projection, null, null, null);
long rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));

Uri contactUri = ContactsContract.RawContacts.CONTENT_URI;
String[] projection = {RawContacts.CONTACT_ID};
String where = RawContacts._ID + "=?";
String[] whereParams = new String[]{String.valueOf(_ID)};
Cursor cursor = cursor = contactHelper.query(contactUri, projection, where, whereParams, null);
long rawContactId = cursor.getLong(cursor.getColumnIndex(RawContacts.CONTACT_ID));

ContentResolver cr = getContentResolver();
Uri contactUri = Contacts.CONTENT_URI;
String[] projection = new String[] {
        Contacts._ID,
        Contacts.DISPLAY_NAME,
        Contacts.STARRED,
        Contacts.TIMES_CONTACTED,
        Contacts.CONTACT_PRESENCE,
        Contacts.PHOTO_ID,
        Contacts.LOOKUP_KEY,
        Contacts.HAS_PHONE_NUMBER,
};
String where = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + " == 1))";
String sortOrder = Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";;
Cursor cursor = cr.query(contactUri, projection, where, null, sortOrder);
if (cursor.getCount() > 0) {
    while (cursor.moveToNext()) {
        String contactId = cursor.getString(cursor.getColumnIndex(Contacts._ID));
        String name = cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME));
        System.out.println("contactId : " + contactId + " name : " + name);
        String mobileNO = null;
        String officeNO = null;
        if (Integer.parseInt(cursor.getString(cursor.getColumnIndex(Contacts.HAS_PHONE_NUMBER))) > 0) {
            Uri phonetUri = Phone.CONTENT_URI;
            Cursor pCur = cr.query(phonetUri, null, Phone.CONTACT_ID + " = ?", new String[]{contactId}, null);
            while (pCur.moveToNext()) {
                int phoneType = pCur.getInt(pCur.getColumnIndex(Phone.TYPE));
                String phoneNumber = pCur.getString(pCur.getColumnIndex(Phone.NUMBER));
                switch (phoneType) {
                    case Phone.TYPE_MOBILE:
                        mobileNO = phoneNumber;
                        break;
                    case Phone.TYPE_HOME:
                        break;
                    case Phone.TYPE_WORK:
                        officeNO = phoneNumber;
                        break;
                    case Phone.TYPE_OTHER:
                        break;
                    default:
                        break;
                }
            }
            pCur.close();
        }
    }
}

Contacts._ID 를 기준으로 구할 경우에는 휴대폰 번호가 바로 나오지 않기 때문에 또한번 Cursor를 사용하기 때문에 속도가 매우 늦다. 2,000개 정도 되는 연락처를 가져오는데 30초 정도 소요된다.


 ContactsContract.RawContacts 의 _ID 로 RawContacts.CONTACT_ID 구하는 코드

public static long getContactIDFrom_ID(ContentResolver contactHelper, long _ID) {
    long rawContactId = -1;
    Uri contactUri = ContactsContract.RawContacts.CONTENT_URI;
    String[] projection = {RawContacts.CONTACT_ID};
    String where = RawContacts._ID + "=?";
    String[] whereParams = new String[]{String.valueOf(_ID)};
    Cursor cursor = null;

    try {
        cursor = contactHelper.query(contactUri, projection, where, whereParams, null);
        if (cursor.moveToFirst()) {
            rawContactId = cursor.getLong(cursor.getColumnIndex(RawContacts.CONTACT_ID));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        cursor.close();
    }
    return rawContactId;
}
 



구한 ID 기준으로 연락처 삭제

// 구한 CONTACT_ID 기준으로 연락처 삭제
public static void deleteContactFromContactId(ContentResolver contactHelper, long ContactId) {
    Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection = null;
    String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
    String[] whereParams = new String[]{String.valueOf(ContactId)};
    String sortOrder = null;

    Cursor cursor = contactHelper.query(contactUri, projection, where, whereParams, sortOrder);
    if (cursor.moveToFirst()) {
        try {
            do {
                String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
                Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
                contactHelper.delete(uri, null, null);
            } while (cursor.moveToNext());
        } catch (Exception e) {
            e.getStackTrace();
        }
    }
}



블로그 이미지

Link2Me

,
728x90

연락처(Contacts)를 읽어오는 코드를 구현 테스트 중이다.

아래 코드를 테스트하면서 교보문고에 가서 책을 보니까 많은 시간이 걸리는 코드가 책에도 있더라.

읽어오는 연락처 데이터 개수가 적으면 아래 코드로도 빠른 응답 결과를 보여준다.

읽어올 데이터가 많다면 속도 문제 해결이 안되므로 해결을 위한 강구를 해야 한다.

해법은 데이터를 각각 읽어와서 메모리상에서 Join 하면 2천개 데이터를 가져오는데 1.5초 소요된다.


앱이 ContentProvider를 통해서 데이터에 접근할 때에는 ContentResolver를 통해서 접근하게 된다.
이 객체는 ContentProvider를 상속받아 특정 함수들을 보유하고 객체이다.
ContentResolver는 기존적인 CRUD(Create Retreive Update Delete) 함수들을 보유하고 있다.


Contacts 테이블에 있는 정보만 읽어오는 로직으로 구현시에는 2,000개의 데이터를 읽어오는 시간이 0.5초도 걸리지 않는다.

 public static Cursor LoadContactsCursor(ContentResolver contactHelper) {
    Uri contactUri = ContactsContract.Contacts.CONTENT_URI;
    String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " ASC";
    Cursor cursor = null;
    try {
        cursor = contactHelper.query(contactUri, null, null, null, sortOrder);
    } catch (Exception e){
        e.printStackTrace();
    }
    return cursor;
}

private ArrayList<String> contactRawContactID;
private ArrayList<String> contactNames;

contactRawContactID = new ArrayList<String>();
contactNames = new ArrayList<String>();

final SimpleDateFormat FORMATTER = new SimpleDateFormat("mm:ss:SSS");
long startTime = System.currentTimeMillis();
cursor = ContactHelper.LoadContactsCursor(getContentResolver());
System.out.println("연락처 개수 = " + cursor.getCount());
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
    contactRawContactID.add(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)));
    contactNames.add(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
    cursor.moveToNext();
}
cursor.close();
System.out.println("걸린시간 : " + FORMATTER.format(new Date(System.currentTimeMillis() - startTime)));



전화번호를 추가로 읽는 로직

 전화번호를 추가로 읽는 로직은 38초 소요된다.
 전화번호는 휴대폰번호, 사무실번호 2번 반복함에 따라 contactId 는 동일하지만 ArrayList 에 저장할 때 데이터가 따로 저장되므로 로직 구현을 고민해야 할 거 같다.

ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0) {
    int nCount=0; int mCount = 0;
    while (cur.moveToNext()) {
        nCount++;
        String contactId = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
        String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
        if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
            Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
            Cursor pCur = cr.query(contactUri, null, Phone.CONTACT_ID + " = ?", new String[]{contactId}, null);
            while (pCur.moveToNext()) {
                mCount++;
                int phoneType = pCur.getInt(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
                String phoneNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                switch (phoneType) {
                    case Phone.TYPE_MOBILE:
                        Log.e("nNo:"+nCount+" " + "mNo:"+mCount+" " +name + "(mobile number)", phoneNumber);
                        break;
                    case Phone.TYPE_HOME:
                        Log.e("nNo:"+nCount+" " + "mNo:"+mCount+" " +name + "(home number)", phoneNumber);
                        break;
                    case Phone.TYPE_WORK:
                        Log.e("nNo:"+nCount+" " + "mNo:"+mCount+" " +name + "(work number)", phoneNumber);
                        break;
                    case Phone.TYPE_OTHER:
                        Log.e("nNo:"+nCount+" " + "mNo:"+mCount+" " +name + "(other number)", phoneNumber);
                        break;
                    default:
                        break;
                }
            }
            pCur.close();
        }
    }
}



블로그 이미지

Link2Me

,
728x90

안드로이드 연락처 정보를 Update 하거나 Delete 할 경우에 성명 + 휴대폰번호 기준으로 조건에 충족하는 Contact_ID 를 구하는 메소드를 구현했다.

동일한 성명이 여러개 존재하거나, 휴대폰번호가 동일한 것이 2개 이상 존재할 수도 있다.

자료 결과 반환 조건은 성명 + 전화번호는 unique 하다는 가정하에 테스트를 진행했다.


Phone.TYPE = 2 (휴대폰번호, Phone.TYPE_MOBILE) 

Phone.TYPE = 3 (사무실번호, Phone.TYPE_WORK)


// 표시 이름과 휴대폰번호를 기준으로 ContactId 구하기
public static long getContactIDFromNameAndNumber(ContentResolver contactHelper, String display_name, String number) {
    long rawContactId = -1;

    Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection = {Phone.CONTACT_ID, Phone.NUMBER};
    String where = Phone.DISPLAY_NAME + " = '" + display_name + "' AND " + Phone.NUMBER + " =? AND " + Phone.TYPE + " =2";
    String[] whereParams = new String[]{number};
    String sortOrder = Phone.DISPLAY_NAME + " ASC";
    Cursor cursor = null;
    try {
        cursor = contactHelper.query(contactUri, null, where, whereParams, sortOrder);
        if (cursor.moveToFirst()) {
            do {
                rawContactId = cursor.getLong(cursor.getColumnIndex(Phone.CONTACT_ID));
            } while (cursor.moveToNext());
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return rawContactId;
}


위 코드는 문제점이 휴대폰번호를 010-1111-0000 과 01011110000 을 다르게 인식하여 결과가 다르게 나온다.


그래서 코드를 다시 수정 테스트를 했다.

아래 코드는 휴대폰번호 010-1111-0000 과 01011110000 을 동일하게 인식하고 같은 rawContactId 를 반환한다.

// 표시 이름과 휴대폰번호를 기준으로 ContactId 구하기
public static long getContactIdFromNameAndNumber(ContentResolver contactHelper, String display_name, String number) {
    long rawContactId = -1;

    Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
    String[] projection = {PhoneLookup._ID, PhoneLookup.TYPE, PhoneLookup.DISPLAY_NAME};
    Cursor cursor = null;
    try {
        cursor = contactHelper.query(contactUri, projection, null, null, null);
        if (cursor.moveToFirst()) {
            do {
                String PhoneName = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
                if(display_name.equals(PhoneName)){
                    rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
                }
            } while (cursor.moveToNext());
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return rawContactId;
}


블로그 이미지

Link2Me

,
728x90

CONTACT_ID 를 구했다는 가정하에 연락처를 삭제하는 메소드이다.

메소드는 2개 모두 잘 동작함을 확인하고 적어둔다.

// 구한 ID 기준으로 연락처 삭제
public static void deleteContactFromRawContactID(ContentResolver contactHelper, long CONTACT_ID) {
    String where = RawContacts.CONTACT_ID + " = " + String.valueOf(CONTACT_ID);
    contactHelper.delete(RawContacts.CONTENT_URI, where, null);
} 

 // 구한 ID 기준으로 연락처 삭제
public static void deleteContactFromContactId(ContentResolver contactHelper, long ContactId) {
    Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection = null;
    String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
    String[] whereParams =new String[] { String.valueOf(ContactId) };
    String sortOrder = null;

    Cursor cursor = contactHelper.query(contactUri, projection, where, whereParams, sortOrder);
    if(cursor.moveToFirst()){
        try {
            do {
                String lookupKey = cursor .getString(cursor .getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
                Uri uri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
                contactHelper.delete(uri, null, null);
            } while (cursor.moveToNext());
        } catch (Exception e){
            e.getStackTrace();
        }
    }
}


전화번호로 CONTACT_ID 를 구하는 메소드

// 전화번호에서 구한 PhoneLookup._ID 가 RawContacts.ContactID 와 동일함
public static long getContactIDFromNumber(ContentResolver contactHelper, String number) {
    long rawContactId = -1;
    Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
    String[] projection = {PhoneLookup._ID};
    Cursor cursor = null;

    try {
        cursor = contactHelper.query(contactUri, projection, null, null, null);
        if (cursor.moveToFirst()) {
            System.out.println("PhoneLookup._ID from number : " + cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID)));
            rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(cursor != null) {
            cursor.close();
        }
    }
    return rawContactId;
}



블로그 이미지

Link2Me

,
728x90

안드로이드 연락처 앱에 있는 연락처를  선택한 것만 삭제하는 메소드(bulkDelete) 와 모든 연락처를 삭제하는 메소드다.


public class ContactHelper {

    // 연락처 총개수 파악
    public static int getContactsTotalCount(ContentResolver contactHelper) {
        Cursor cursor = contactHelper.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
        return cursor.getCount();
    }

    public static void bulkDelete(ContentResolver contactHelper,long[] ids){
        if (ids.length == 0) { // 삭제할 데이터가 없으면
            return;
        }
        StringBuilder where=new StringBuilder();
        where.append(RawContacts.CONTACT_ID);
        where.append(" IN (");
        where.append(Long.toString(ids[0]));
        for (int i=1; i < ids.length; i++) {
            where.append(',');
            where.append(Long.toString(ids[i]));
        }
        where.append(')');
        try {
            contactHelper.delete(RawContacts.CONTENT_URI,where.toString(),null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 모든 연락처 삭제
    public static void deleteAllContact(ContentResolver contactHelper) {
        contactHelper.delete(RawContacts.CONTENT_URI, null, null);
    }
}


사용법

long[] ids = new long[]{16258,15265,15441,15542,16278};
ContactHelper.bulkDelete(getContentResolver(), ids);


위와 같이 수동으로 해당 CONTACT_ID를 직접 적어주고 테스트를 했다.

하지만 앱으로 구현한다면, CustomListView 에서 체크박스를 선택한 것만 삭제되도록 구현하면 될 것이다.

체크한 것만 ArrayList 에 담고 ArrayList 를 배열로 변환한 다음에

ContactHelper.bulkDelete(getContentResolver(), ids);

를 실행하면 될 것이다.

다만 IN 안에 들어가는 인수의 개수를 어느 범위까지 허용하는지 여부는 테스트를 안해봐서 장담할 수가 없다.


성명(display_name) 과 전화번호, CONTACT_ID 를 구할 수 있는 Cursor 메소드

    // Display Name 이 포함된 모든 Cursor 반환
    public static Cursor getContactCursorFromDisplayNameLIKE(ContentResolver contactHelper, String display_name) {

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = {Phone.CONTACT_ID,Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER};
        // Cursor를 얻기 위한 쿼리 조건
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, where, null,
                        sortOrder);
            } else {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
            }
            cursor.moveToFirst();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return cursor;
    }

 public class MainActivity extends AppCompatActivity {
    private ArrayList<String> contactRawContactID;
    private ArrayList<String> contactDataID;
    private ArrayList<String> contactNames;
    private ArrayList<String> contactNumbers;
    ArrayAdapter<String> adapter;
    ListView listView;
    private Cursor cursor;

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

        listView = (ListView) findViewById(R.id.list);
        TextView tv_getCount = (TextView) findViewById(R.id.tv_getContactCount);
        tv_getCount.setText("총 " + String.valueOf(ContactHelper.getContactsTotalCount(getContentResolver())) + " 개");

        contactRawContactID = new ArrayList<String>();
        contactDataID = new ArrayList<String>();
        contactNames = new ArrayList<String>();
        contactNumbers = new ArrayList<String>();

        cursor = ContactHelper.getContactCursorFromDisplayNameLIKE(getContentResolver(), "");
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            contactRawContactID.add(cursor.getString(0));
            contactDataID.add(cursor.getString(1));
            contactNames.add(cursor.getString(2));
            contactNumbers.add(cursor.getString(3));
            cursor.moveToNext();
        }

        adapter = new MyAdapter(this, android.R.layout.simple_list_item_1, R.id.tvNameMain, contactNames);
        listView.setAdapter(adapter);

    }

    private class MyAdapter extends ArrayAdapter<String> {

        public MyAdapter(Context context, int resource, int textViewResourceId, ArrayList<String> conNames) {
            super(context, resource, textViewResourceId, conNames);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = setList(position, parent);
            return row;
        }

        private View setList(final int position, ViewGroup parent) {
            LayoutInflater inf = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            View row = inf.inflate(R.layout.liststyle, parent, false);

            TextView tvRawContactID = (TextView) row.findViewById(R.id.tvRawContactID);
            TextView tvDataID = (TextView) row.findViewById(R.id.tvDataID);
            TextView tvName = (TextView) row.findViewById(R.id.tvNameMain);
            TextView tvNumber = (TextView) row.findViewById(R.id.tvNumberMain);

            tvRawContactID.setText("RawContact_ID : " + contactRawContactID.get(position));
            tvDataID.setText("Data_ID : " + contactDataID.get(position));
            tvName.setText(contactNames.get(position));
            tvNumber.setText("No: " + contactNumbers.get(position));

            return row;
        }
    }
}


블로그 이미지

Link2Me

,
728x90

성명 + 전화번호 기준으로 일치되는 데이터를 삭제하는 메소드 구현을 적어둔다.

좀 더 나은 방법을 구현하면 업데이트해서 수정할 생각이다.


수정 구현 사항

// 성명 + 휴대폰번호 기준으로 연락처 삭제 (동명이인 고려)
public static void deleteContactFromNameAndNumber(ContentResolver contactHelper, String display_name, String number) {
    // 로직 개념 : 이름 검색으로 전화번호를 구한 다음에, 전화번호 일치여부 확인후 삭제 순서로 로직 구현
    number = number.replaceAll("[^0-9]", ""); // 숫자만 추출
    Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection = {Phone.CONTACT_ID, Phone.NUMBER};
    String where = Phone.DISPLAY_NAME + " = '" + display_name + "' AND " + Phone.TYPE + "=2";
    String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
    Cursor cursor = null;
    try {
        if (display_name != null && !display_name.equals("") && number != null && !number.equals("")) {
            cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
            if (cursor.moveToFirst()) {
                do {
                    String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                    phoneNO = phoneNO.replaceAll("[^0-9]", ""); // 숫자만 추출
                    if (number.equals(phoneNO)) {
                        // 이름으로 찾은 전화번호와 입력된 전화번호가 서로 같으면 해당 연락처 삭제 처리
                        long rawContactId = cursor.getLong(cursor.getColumnIndex(Phone.CONTACT_ID));
                        contactHelper.delete(RawContacts.CONTENT_URI,RawContacts.CONTACT_ID + "=" + rawContactId,null);
                    }
                } while (cursor.moveToNext());
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(cursor != null) {
            cursor.close();
        }
    }
}



기존 구현 사항

public class ContactHelper {
    public ContactHelper() {
    }

    // 전화번호에서 ContactID 획득
    private static long getContactIDFromNumber(ContentResolver contactHelper, String number) {
        long rawContactID = -1;
        number = number.replaceAll("[^0-9]", ""); // 숫자만 추출
        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

        String[] projection = { PhoneLookup._ID };
        Cursor cursor = null;

        try {
            cursor = contactHelper.query(contactUri, projection, null, null, null);
            if (cursor.moveToFirst()) {
                rawContactID = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            cursor.close();
        }
        return rawContactID;
    }

    // 전화번호 기준으로 연락처 삭제
    public static void deleteContactFromNumber(ContentResolver contactHelper, String number) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        String[] WhereArgs = new String[] { String.valueOf(getContactIDFromNumber(contactHelper, number)) };

        ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
                .withSelection(RawContacts.CONTACT_ID + "=?", WhereArgs).build());
        try {
            contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
    }

    // 성명 + 전화번호 기준으로 연락처 삭제 (동명이인 고려)
    public static void deleteContactFromNameAndNumber(ContentResolver contactHelper, String display_name, String number) {
        // 로직 개념 : 이름 검색 --> 전화번호 --> ContactID 를 구하는 순서로 로직 구현
        number = number.replaceAll("[^0-9]", ""); // 숫자만 추출
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone.NUMBER };
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("") && number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.moveToFirst()) {
                    do {
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        phoneNO = phoneNO.replaceAll("[^0-9]", ""); // 숫자만 추출
                        if (number.equals(phoneNO)) {
                            // 이름으로 찾은 전화번호와 입력된 전화번호가 서로 같으면 해당 연락처 삭제 처리
                            deleteContactFromNumber(contactHelper, phoneNO);
                        }
                    } while (cursor.moveToNext());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}



블로그 이미지

Link2Me

,
728x90

성명으로 검색한 연락처(Contacts)를 모두 삭제하는 메소드 구현사항을 적어둔다.

좀 더 효율적인 방법을 찾기 위해서 지속 수정 테스트로 내용 변경이 발생하다보니 기존 구현 메소드도 필요할 때가 있을거 같아서 적어둔다.


삭제 기본지식 이해

연락처를 읽거나 쓰기(수정/삭제) 위해서는 아래와 같은 퍼미션이 필요하다.
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>


연락처 삭제 메소드 중의 하나
static public void deleteContact(Context context, long rawContactId) {
  context.getContentResolver().delete(RawContacts.CONTENT_URI, RawContacts.CONTACT_ID + " = " + rawContactId, null);
}


RawContacts 를 삭제하면 종속된 data 는 자동으로 삭제가 된다.
Contacts 를 지우면 종속된 RawContacts 를 자동으로 삭제한다.
ContactsProvider 를 이용해서 RawContacts 를 삭제하면 데이터베이스에서 바로 지워지지 않는다.
RawContacts 테이블의 deleted 필드를 1로 세팅한다.
그리고 SyncAdapter 에 의해 실제 삭제가 이루어진다. 


성명(display_name)으로 검색한 동일한 이름을 포함하는 모든 데이터는 삭제를 한다.


수정 구현 사항

// 성명 포함 연락처 삭제 (구현 완료)
public static void deleteContactFromNameLIKE(ContentResolver contactHelper, String display_name) {
    System.out.println("Contact Name Search : " + display_name);
    Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection = {Phone.CONTACT_ID, Phone.NUMBER}; // 검색
    String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
    String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
    Cursor cursor = null;
    try {
        if (display_name != null && !display_name.equals("")) {
            cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
            if (cursor.moveToFirst()) {
                int count = 0;
                do {
                    long rawContactId = cursor.getLong(cursor.getColumnIndex(Phone.CONTACT_ID));
                    contactHelper.delete(RawContacts.CONTENT_URI,RawContacts.CONTACT_ID + "=" + rawContactId,null);
                    count++;
                } while (cursor.moveToNext());
                System.out.println("Delete Contact Number Count = " + count);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(cursor != null) {
            cursor.close();
        }
    }
}



기존 구현 사항

public class ContactHelper {
    public ContactHelper() {
    }

    // 성명 포함 연락처 삭제
    public static void deleteContactFromNameLIKE(ContentResolver contactHelper, Context context, String display_name) {
        System.out.println("Contact Name Search : " + display_name);
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone.NUMBER };
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.moveToFirst()) {
                    int count = 0;
                    do {
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        deleteContactFromNumber(contactHelper, phoneNO);
                        count++;
                    } while (cursor.moveToNext());
                    System.out.println("Delete Contact Number Count = " + count);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void deleteContactFromNumber(ContentResolver contactHelper, String number) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        String[] WhereArgs = new String[] { String.valueOf(getContactIDFromNumber(contactHelper, number)) };

        ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
                .withSelection(RawContacts.CONTACT_ID + "=?", WhereArgs).build());
        try {
            contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
    }

    // 전화번호에서 ContactID 획득
    private static long getContactIDFromNumber(ContentResolver contactHelper, String number) {
        long rawContactID = -1;
        number = number.replaceAll("[^0-9]", ""); // 숫자만 추출
        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

        String[] projection = { PhoneLookup._ID };
        Cursor cursor = null;

        try {
            cursor = contactHelper.query(contactUri, projection, null, null, null);
            if (cursor.moveToFirst()) {
                System.out.println("ContactID from number : " + cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID)));
                rawContactID = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
                cursor.close();
        }

        return rawContactID;
    }
}


사용법

btn_delte.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 전화번호 삭제
                ContactHelper.deleteContactFromNameLIKE(getContentResolver(), MainActivity.this, "홍길동");
            }
        });

        // 현재 Activity 갱신처리
        finish();
        startActivity(getIntent());

    }
});



블로그 이미지

Link2Me

,
728x90

연락처(Contacts) ContactHelper Class  메소드를 세부적으로 추가했다.

첨부된 파일의 소스는 한명의 데이터가 분리되어 표기되기 때문에 실제 연락처 소스로 활용하기에는 부족하다. 테스트 용도로는 매우 좋다.

Cursor 쿼리 중심으로 이해하기 쉽게 코드를 수정 보완해서 작성했다.

SQLiteHelper 에서 사용하는 Cursor 와는 개념은 비슷한데 약간 다르다.

아래 코드 중에서 100% 완료 상태가 아닌 테스트 중인 것을 그대로 올린 것도 있으므로 필요하신 분은 수정해서 사용하면 될 것으로 본다.

구글링을 하고 본인의 생각을 담아서 코드를 추가하면 유용하게 사용할 수 있는 좋은 자료라고 본다.


import java.util.ArrayList;

import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.RawContacts;
import android.widget.Toast;

public class ContactHelper {

    // Display Name 이 포함된 모든 Cursor 반환
    public static Cursor getContactCursorFromDisplayNameLIKE(ContentResolver contactHelper, String display_name) {

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER };
        // Cursor를 얻기 위한 쿼리 조건
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, where, null,
                        sortOrder);
            } else {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
            }
            cursor.moveToFirst();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return cursor;
    }

    // Display Name 으로 모든 Cursor 반환
    public static Cursor getContactCursorFromDisplayName(ContentResolver contactHelper, String display_name) {

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER };
        // Cursor를 얻기 위한 쿼리 조건
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ='" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, where, null,
                        sortOrder);
            }
            cursor.moveToFirst();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return cursor;
    }

    public static Cursor getDisplayNameFromNumber(ContentResolver contactHelper, String number) {

        // 참조 https://developer.android.com/reference/android/provider/ContactsContract.PhoneLookup.html
        // Android 2.0 and later
        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = { PhoneLookup._ID, PhoneLookup.DISPLAY_NAME, PhoneLookup.NUMBER };

        Cursor cursor = null;

        try {
            if (number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, null, null, null);
                if (cursor.getCount() > 0) {
                    while (cursor.moveToNext()) {
                        long rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
                        System.out.println("Contact ID from number : " + rawContactId);
                        System.out.println("Contact DISPLAY_NAME : "
                                + cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME)));
                        System.out.println("Contact NUMBER : " + cursor.getString(cursor.getColumnIndex(PhoneLookup.NUMBER)));
                    }
                    return cursor;
                }

            } else {
                System.out.println("전화번호 검색어가 입력되지 않았습니다 ");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static long getContactIDFromName(ContentResolver contactHelper, String display_name) {
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        String[] projection = { ContactsContract.Contacts._ID };
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String[] whereParams = null; // new String[] {display_name};
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            cursor = contactHelper.query(contactUri, null, where, whereParams, sortOrder);

            if (cursor.moveToFirst()) {
                System.out.println("ContactID from display_name : "
                        + cursor.getLong(cursor.getColumnIndex(ContactsContract.Contacts._ID)));
                return cursor.getLong(cursor.getColumnIndex(ContactsContract.Contacts._ID));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }

        return -1;
    }

    // 전화번호에서 ContactID 획득
    private static long getContactIDFromNumber(ContentResolver contactHelper, String number) {
        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

        String[] projection = { PhoneLookup._ID };
        Cursor cursor = null;

        try {
            cursor = contactHelper.query(contactUri, projection, null, null, null);

            if (cursor.moveToFirst()) {
                System.out.println("ContactID from number : " + cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID)));
                return cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
            }

            return -1;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }

        return -1;
    }

    // 연락처 추가 (이름 + 전화번호), 기존 개발자 구현 완료사항
    public static boolean insertContact(ContentResolver contactHelper, String firstName, String mobileNumber) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName).build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mobileNumber)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, Phone.TYPE_MOBILE).build());

        try {
            // 연락처 제공자는 applyBatch()에서의 모든 작업을 하나의 트랜잭션으로서 수행
            contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    // 구한 ID 기준으로 연락처 삭제
    // 성명 검색으로 구한 ContactID는 삭제가 안되고, Phone Number 로 구한 ContactID는 삭제가 정상처리됨
    public static void deleteContactFromgetContactID(ContentResolver contactHelper, long getContactId) {
        System.out.println("Contact ID : " + getContactId);
        String where = RawContacts.CONTACT_ID + " = " + getContactId;
        contactHelper.delete(RawContacts.CONTENT_URI, where, null);
    }

    // 전화번호 기준으로 연락처 삭제 (구현 완료)
    public static void deleteContactFromNumber(ContentResolver contactHelper, String number) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        String[] WhereArgs = new String[] { String.valueOf(getContactIDFromNumber(contactHelper, number)) };

        ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
                .withSelection(RawContacts.CONTACT_ID + "=?", WhereArgs).build());
        try {
            contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
    }

    // 성명 기준으로 동일한 성명을 가진 모든 연락처 삭제 (구현 완료)
    public static void deleteAllContactFromName(ContentResolver contactHelper, String display_name) {
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        contactHelper.delete(RawContacts.CONTENT_URI, where, null);
    }

    // 성명 기준으로 동일한 성명을 가진 모든 연락처 삭제 -- 진행중
    public static void deleteAllContactFromName2(ContentResolver contactHelper, String display_name) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
       
        Cursor cursor = null;
        cursor = getContactCursorFromDisplayName(contactHelper, display_name);
        if (cursor != null && cursor.getCount() > 0) {
            cursor.moveToFirst();
            while (cursor.moveToNext()) {
                String number = cursor.getString(2); // 전화번호 구하기
                // 전화번호 기준으로 ContactID 구하기
                System.out.println("Contact Phone Number : " + number);
                long rawContactId = getContactIDFromNumber(contactHelper, number);
                if (rawContactId > 0) {
                    String where = RawContacts.CONTACT_ID + "=" + rawContactId;
                    //contactHelper.delete(RawContacts.CONTENT_URI, where, null);
                   
                    ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
                            .withSelection(where, null).build());
                    try {
                        contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    } catch (OperationApplicationException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    // 성명 포함 연락처 삭제 (구현 완료)
    public static void deleteContactFromNameLIKE(ContentResolver contactHelper, String display_name) {
        System.out.println("Contact Name Search : " + display_name);
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 검색할 칼럼 정하기
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.getCount() > 0) {
                    // cursor.moveToFirst();
                    while (cursor.moveToNext()) {
                        long rawContactId = cursor.getLong(cursor.getColumnIndex(Phone._ID));
                        System.out.println("Contact ID from number : " + rawContactId);
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        System.out.println("Contact Phone Number : " + phoneNO);
                        deleteContactFromNumber(contactHelper, phoneNO);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 성명 + 전화번호 기준으로 ContactId 구하기 -- 구현중
    public static long getContactIdFromNameAndNumber(ContentResolver contactHelper, String display_name, String number) {
        long rawContactId;
        // 먼저 이름기준으로 Cursor 를 구한 다음에 폰 번호 기준 ID 구한다.
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 검색할칼럼 정하기
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("") && number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.getCount() > 0) {
                    while (cursor.moveToNext()) {
                        long getContactId = cursor.getLong(cursor.getColumnIndex(Phone._ID));
                        System.out.println("Contact ID from number : " + getContactId);
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        System.out.println("Contact Phone Number : " + phoneNO);
                        rawContactId = getContactIDFromName(contactHelper, phoneNO);
                        System.out.println("Contact ID from Phone Number : " + rawContactId);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

    // 성명 + 전화번호 기준으로 연락처 삭제 (동명이인 고려) -- 진행중
    public static void deleteContactFromNameAndNumber(ContentResolver contactHelper, Context context, String display_name,
            String number) {
        // 로직 개념 : 이름 검색으로 전화번호를 구한 다음에, 전화번호 기준으로 ContactID 를 구하는 순서로 로직 구현
        number = number.replaceAll("[^0-9]", ""); // 숫자만 추출
        // 이름 + 전화번호 조건으로 처리하는 로직이 없는 듯....
        // String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME +
        // " = '" + display_name + "' AND "
        // + ContactsContract.CommonDataKinds.Phone.NUMBER + " = '" + number +
        // "' AND "
        // + ContactsContract.CommonDataKinds.Phone.TYPE + "=" +
        // ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE + "";
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 검색할 칼럼 정하기
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("") && number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.getCount() > 0) {
                    // cursor.moveToFirst();
                    while (cursor.moveToNext()) {
                        long getContactId = cursor.getLong(cursor.getColumnIndex(Phone._ID));
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        System.out.println("Contact Phone Number : " + phoneNO);
                        long rawContactId = getContactIDFromNumber(contactHelper, phoneNO);
                        System.out.println("Contact ID from Number : " + rawContactId);
                        deleteContactFromNumber(contactHelper, phoneNO);
                        Toast.makeText(context, "getIDFromName : " + getContactId + " getIDFromNumber : " + rawContactId,
                                Toast.LENGTH_LONG).show();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 모든 연락처 삭제(구현완료)
    public static void deleteAllContact(ContentResolver contactHelper) {
        contactHelper.delete(RawContacts.CONTENT_URI, null, null);
    }

}



MainActivity.java 에서 사용법 예제

예제라고 할 순 없고 테스트 중인 것을 적었다.

public class MainActivity extends ListActivity {

    private ArrayList<String> contactID;
    private ArrayList<String> contactNames;
    private ArrayList<String> contactNumbers;
    ArrayAdapter<String> adapter;
    private Cursor cursor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button btn_Test1 = (Button) findViewById(R.id.btn_CustomDelete1);
        Button btn_Test2 = (Button) findViewById(R.id.btn_CustomDelete2);

        contactID = new ArrayList<String>();
        contactNames = new ArrayList<String>();
        contactNumbers = new ArrayList<String>();

        cursor = ContactHelper.getContactCursorFromDisplayNameLIKE(getContentResolver(), "");
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            contactID.add(cursor.getString(0));
            contactNames.add(cursor.getString(1));
            contactNumbers.add(cursor.getString(2));
            cursor.moveToNext();
        }

        adapter = new MyAdapter(this, android.R.layout.simple_list_item_1, R.id.tvNameMain, contactNames);
        setListAdapter(adapter);

        // 추가 테스트
        // Cursor cursor1 =
        // ContactHelper.getDisplayNameFromNumber(getContentResolver(), "010-1234-0401");
        // System.out.println("Contact Cursor Return !!");
        // if (cursor1 != null) {
        // cursor1.moveToFirst();
        // while (!cursor1.isAfterLast()) {
        // System.out.println("ContactId =" + cursor1.getString(0) + " 성명: " +
        // cursor1.getString(1) + " 휴대폰번호:"
        // + cursor1.getString(2));
        // cursor1.moveToNext();
        // }
        // }

        btn_Test1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 성명 포함 삭제 테스트
                // 이름 검색으로 구한 ContactID 로는 삭제가 안되나, Number 로 구한 ContactID로는 삭제가
                // 됨
                // ContactHelper.deleteContactFromNameLIKE(getContentResolver(),
                // "개발");
                // ContactHelper.deleteContactFromgetContactID(getContentResolver(),53360);
                ContactHelper.deleteContactFromgetContactID(getContentResolver(), 10674);
                adapter.notifyDataSetChanged();
                // 현재 Activity 갱신처리
                finish();
                startActivity(getIntent());
            }
        });

        btn_Test2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // 전화번호 삭제 테스트
                        // ContactHelper.deleteContactFromNameAndNumber(getContentResolver(), MainActivity.this, "테스트", "010-1212-7710");
                        ContactHelper.deleteAllContactFromName(getContentResolver(), "개발자");
                    }
                });

                // 현재 Activity 갱신처리
                finish();
                startActivity(getIntent());

            }
        });

    }

    private class MyAdapter extends ArrayAdapter<String> {

        public MyAdapter(Context context, int resource, int textViewResourceId, ArrayList<String> conNames) {
            super(context, resource, textViewResourceId, conNames);

        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            View row = setList(position, parent);
            return row;
        }

        private View setList(int position, ViewGroup parent) {
            LayoutInflater inf = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            View row = inf.inflate(R.layout.liststyle, parent, false);

            TextView tvID = (TextView) row.findViewById(R.id.tvContactID);
            TextView tvName = (TextView) row.findViewById(R.id.tvNameMain);
            TextView tvNumber = (TextView) row.findViewById(R.id.tvNumberMain);

            Button btn_Add = (Button) row.findViewById(R.id.btn_AddContact);
            Button btn_Del = (Button) row.findViewById(R.id.btn_deleteContact);

            tvID.setText("ContactID : " + contactID.get(position));
            tvName.setText(contactNames.get(position));
            tvNumber.setText("No: " + contactNumbers.get(position));

            btn_Add.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, AddContact.class);
                    startActivity(intent);
                }
            });

            btn_Del.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, DeleteContacts.class);
                    startActivity(intent);
                }
            });

            return row;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater imf = getMenuInflater();
        imf.inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.item1) {
            Intent intent = new Intent(MainActivity.this, AddContact.class);
            startActivity(intent);
        } else if (item.getItemId() == R.id.item2) {
            Intent intent = new Intent(MainActivity.this, DeleteContacts.class);
            startActivity(intent);
        }
        return super.onOptionsItemSelected(item);
    }
}
 


테스트에 사용한 파일

본 파일은 구글링으로 구한 파일을 가지고 이해하기 쉽게 코드를 상당히 수정하고, 연락처 삭제 중심으로 코드를 추가 구현했다.

테스트 환경 : Eclipse

안드로이드 스튜디오에서 테스트하려면 코드가 복잡한 것이 없으므로 변환하면 될 것으로 본다.

Android-Contacts.zip


Android Studio 버전으로 수정한 코드는 http://link2me.tistory.com/1305 에 올려져 있다.

보완해서 테스트 하고 있는 중이라 약간 더 코드가 수정되었다.

블로그 이미지

Link2Me

,
728x90

Android Contacts 를 검색하고 동일 정보가 있으면 삭제하고 신규로 데이터를 저장하는 로직이 있어서 아무 생각없이 잘 될 것이라는 믿음(?)으로 소스를 사용하다가 주소록을 2,000 개 이상 동시 저장하는 걸 테스트 하는데 너무 느려서 구글링으로 예제 소스 하나 받아서 테스트를 해보니 동일한 자료가 엄청나게 저장되어 있는 걸 알았다.

삼성폰이 기본 제공하는 연락처 앱에서는 데이터가 딱 저장한 개수만큼만 보인다.

데이터 삭제가 제대로 되는지 확인해봤더니 삭제가 안되고 있더라.

계속 삽질을 하다가 Easy Contacts Delete 라는 어플을 받아서 전체를 선택하고 삭제를 했더니 모든 데이터가 삭제되었다.


연락처(Contacts) 에 대한 기본 개념이 부족해서 해결이 제대로 안되는 것이라 집중적으로 관련 자료를 검색하고 책을 보면서 정리하고 테스트 해보고 있다.

Display_Name 으로 검색한 ContactID 와 Phone Number 로 검색한 ContactID 를 정확하게 구현해주어야 한다는 걸 테스트를 통해서 알게되었고, Phone Number 기준으로 얻은 ContactID 로 삭제가 잘 된다는 걸 알았다.


도전의 절반은 스키마를 마스터하고, 각 테이블이 다른 테이블과 어떻게 상호 작용하는지를 이해하는데 있다.


주소록 DB는 /data/data/com.android.providers.contacts/databases/contacts2.db 에 있는데 접근이 불가능하다.

contacts database는 Provider URI 를 통해서 접근할 수 있다.

Stackoverflow 보면 https://developer.android.com/guide/topics/providers/contacts-provider.html 사이트 참조하라고 나온다.


Contacts API 2.0 에서는, 연락처(Contacts)은 다음 세 테이블로 구성되어 있다.


  ContactsContract.Contacts table

 - 고유한 사용자(people) 정보를 표시하는 테이블

 - https://developer.android.com/reference/android/provider/ContactsContract.Contacts.html 칼럼 확인


  ContactsContract.RawContacts table

 - user account and type 을 기준으로, 한 사용자 정보 요약을 포함하는 테이블

 - https://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html 에서 칼럼 확인

 - ContactsContract.RawContacts.CONTACT_ID = Contacts._ID 값과 일치


  ContactsContract.Data table

 - E-Mail 주소나 휴대폰번호 같은 RawContacts 테이블의 세부 정보를 포함하는 테이블
 - ContactsContract.Data.RAW_CONTACT_ID = ContactsContract.RawContacts._ID 값과 일치

 - https://developer.android.com/reference/android/provider/ContactsContract.Data.html 에서 칼럼 확인

 - 15개의 일반 열 중에서 DATA1부터 DATA15까지는 일반적으로 이용할 수 있고 이외에 추가로 마련된 네 개의 일반 열, 즉 SYNC1부터 SYNC4까지는 동기화 어댑터 전용이다.

 - 표시 이름, 전화 번호, 이메일, 우편 주소, 사진 및 웹사이트 세부 정보 행은 모두 ContactsContract.Data 테이블에서 찾을 수 있다.


모든 테이블에는 테이블명._ID 가 있다.


위 도식도에 나온 ID 칼럼이 서로 어떻게 연관되어 있는지를 아는것이 가장 중요하다.

데이터를 수정(Update)하거나 삭제(Delete)할 때 정확하게 정보를 업데이트할 수 있다.

즉 rawContactId 값을 구하는 걸 잘못 구하면 데이터 수정/삭제가 제대로 안된다는 것이다.

이 개념 이해하느라고 정말 많은 시간을 할애하였다.

구글링해도 이런 내용은 나오지 않고 그냥 소스 코드 예제만 좀 나온다.

검색 키워드 찾는 방법을 잘못하니까 예제 찾기도 쉽지 않더라.


원시 연락처의 이름은 ContactsContract.RawContacts에 있는 자신의 행에 저장되지 않고,

ContactsContract.CommonDataKinds.StructuredName 행에 있는 ContactsContract.Data 테이블에 저장된다.
원시 연락처의 데이터는 원시 연락처의 _ID 값과 연결된ContactsContract.Data 행에 저장된다.
하나의 원시 연락처에 같은 유형 데이터의 인스턴스가 여러 개 있을 수 있다.
ㅇ MIMETYPE
  - 사용자 지정 MIME 유형으로 표현된다.
  - 연락처 제공자는 ContactsContract.CommonDataKinds의 서브클래스에서 정의된 MIME 유형을 사용한다.

ㅇ 연락처 제공자는 기존 연락처 어느 것과도 일치하지 않는 새로운 원시 연락처가 추가되면 새로운 연락처를 생성한다.
  애플리케이션이나 동기화 어댑터가 기존 연락처와 일치하는 새로운 원시 연락처를 생성하면, 새로운 원시 연락처는 기존 연락처에 통합된다.
ㅇ 연락처 제공자가 연락처를 자동으로 관리하므로, 통합이나 동기화에 응답하여 연락처 행의 _ID 값을 변경할 수도 있다.
ㅇ 사용자 프로필에 액세스하기 위한 상수는 ContactsContract.Profile 클래스에서 이용할 수 있다.
  - 사용자 프로필에 액세스하려면 특수 권한이 필요하다.
  - android.Manifest.permission#READ_PROFILE과 android.Manifest.permission#WRITE_PROFILE 권한이 필요
  - 권한 android.Manifest.permission#READ_PROFILE을 사용하면 개발자가 기기 사용자의 개인 식별 데이터에 액세스할 수 있게 해준다.



참고

특정 블로그에서만 찾은 자료가 아닌지라 출처는 생각나는 것만 남긴다.

http://www.javased.com/index.php?source_dir=android-client_1/src/com/googlecode/asmack/contacts/ContactDataMapper.java

안드로이드 연락처 초성검색 소스 : http://www.androidpub.com/45681

http://blog.mready.net/2012/09/android-contacts/ 에 나온 예제를 가지고 ContactHelper.java 클래스 파일을 만드는데 활용하면 좋을 거 같다.

블로그 이미지

Link2Me

,