最近数据部需要上传用户的通讯录,通话记录,短信等内容做分析,于是整理下这方面的知识。说句实话,其实获取的方式都是一个样子的,都是通过ContentProvider,知其一就可以举一反三了。
首先定义了一个接口,包含查询数据,解析数据和关闭cursor,如下
public interface IResolverHelper {
/**
* 查询手机相关db,获取cursor
*
* @param context
* @return
*/
Cursor query(Context context);
/**
* 从cursor中读取数据
*/
void readData();
/**
* 关闭cursor
*/
void close();
}
然后写了个实现类,如下所示
public abstract class ResolverHelperImpl<T> implements IResolverHelper {
protected Handler mHandler;
protected Uri contentUri/*读取哪个表的数据*/
protected String[] mColumns;/*读取哪些列*/
protected String mCondition;/*限制条件*/
protected String[] mArgs;/*参数*/
protected String mSort;/*排序方式*/
protected T mData;
protected Cursor mCursor;
public ResolverHelperImpl(Context context, Handler handler) {
mHandler = handler;
initParams();
mCursor = query(context);
}
protected abstract void initParams();
@Override
public Cursor query(Context context) {
ContentResolver resolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = resolver.query(contentUri, mColumns, mCondition, mArgs, mSort);
} catch (Exception e) {
e.printStackTrace();
}
return cursor;
}
@Override
public void readData() {
new Thread() {
@Override
public void run() {
try {
parseData();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mHandler != null) {
Message msg = mHandler.obtainMessage();
msg.what = getMsgWhat();
msg.obj = mData;
mHandler.sendMessage(msg);
}
close();
}
}
}.start();
}
protected abstract void parseData();
protected abstract int getMsgWhat();
@Override
public void close() {
if (mCursor != null) {
try {
mCursor.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
initParams()主要是做一些初始化操作,getMsgWhat()是异步消息传递的what字段的值,主要是parseData()方法,继承这个类重写这个方法,在里面进行数据解析就可以了。
通讯录
通讯录这里分为两部分说,一部分是手机通讯录获取,另外一部分是sim卡通讯录获取。
手机通讯录
public final class ContactHelper extends ResolverHelperImpl<List<ContactItem>> {
public ContactHelper(Context context, Handler handler) {
super(context, handler);
mData = new ArrayList<>();
}
@Override
protected void initParams() {
contentUri = ContactsContract.Data.CONTENT_URI;
mColumns = new String[]{
ContactsContract.Data.RAW_CONTACT_ID,/*联系人id*/
ContactsContract.Data.MIMETYPE,/*data1字段类型*/
ContactsContract.Data.DATA1,/*数据*/
ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP/*时间*/
};
mCondition = ContactsContract.Data.MIMETYPE + " in (?,?)";
mArgs = new String[]{
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
};
mSort = ContactsContract.Data.RAW_CONTACT_ID;
}
@Override
protected void parseData() {
int cid = -1;/*当前联系人id*/
int size = 0;
ContactItem contact = null;
ArrayList<String> phones = null;
while (mCursor != null && mCursor.moveToNext()) {
/*数据库当前操作的联系人id*/
int _id = mCursor.getInt(mCursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID));
String mimetype = mCursor.getString(mCursor.getColumnIndex(ContactsContract.Data.MIMETYPE));
String data1 = mCursor.getString(mCursor.getColumnIndex(ContactsContract.Data.DATA1));
if (_id != cid) {
cid = _id;
if (contact != null) {
/*添加到集合中*/
if (phones != null && phones.size() > 0) {
mData.add(contact);
}
}
/*新的联系人开始了*/
contact = new ContactItem();
phones = new ArrayList<>();
contact.setContactPhones(phones);
size = 0;
/*设置联系人最后修改时间,避免后面重复设置*/
try {
String time = mCursor.getString(mCursor.getColumnIndex(ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP));
time = DateUtils.getFormatTimeFromMillis(Long.parseLong(time));
contact.setCreateDate(time);
} catch (Exception e) {
e.printStackTrace();
}
}
switch (mimetype) {
case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
contact.setContactName(data1);
break;
case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
size++;
if (size > 5) {
continue;
} else {
if (!TextUtils.isEmpty(data1)) {
phones.add(data1.replaceAll("^(\\+86)", "").replaceAll("-", ""));
}
}
break;
}
}
/*添加最后一条数据*/
if (contact != null) {
/*添加到集合中*/
if (phones != null && phones.size() > 0) {
mData.add(contact);
}
}
}
@Override
protected int getMsgWhat() {
return 100000;
}
}
sim卡通讯录
公司的测试机有限,测试的部分测试机在联系人全部存放在sim卡里面时,通过上面的方式也是可以获取的,但是部分测试机获取不到,需要通过下面的方式进行获取,具体Uri在哪里找到的,你们可以看看ICCProvider这个类就知道了,和我们写ContentProvider是一个样的。具体的contentUri是content://icc/adn。代码如下:
public final class SimHelper extends ResolverHelperImpl<List<ContactItem>> {
public SimHelper(Context context, Handler handler) {
super(context, handler);
mData = new ArrayList<>();
}
@Override
protected void initParams() {
contentUri = Uri.parse("content://icc/adn");/*可以参考IccProvider*/
mColumns = new String[]{
"name",/*姓名*/
"number"/*号码*/
};
}
@Override
protected void parseData() {
while (mCursor != null && mCursor.moveToNext()) {
String name = mCursor.getString(mCursor.getColumnIndex("name"));
String phone = mCursor.getString(mCursor.getColumnIndex("number"));
if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(phone)) {
try {
ContactItem d = new ContactItem();
ArrayList<String> phones = new ArrayList();
phones.add(phone.replaceAll("^(\\+86)", "").replaceAll("-", ""));
d.setContactName(name);
d.setContactPhones(phones);
mData.add(d);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
protected int getMsgWhat() {
return 100003;
}
}
短信内容
短信存放的地方和通讯录不一样
image.png在这个表下面。具体代码如下
public final class SmsHelper extends ResolverHelperImpl<List<SmsItem>> {
public SmsHelper(Context context, Handler handler) {
super(context, handler);
mData = new ArrayList<>();
}
@Override
protected void initParams() {
contentUri = Uri.parse("content://sms");
/*筛选列*/
mColumns = new String[]{
Telephony.Sms.ADDRESS,/*短信发送者号码*/
Telephony.Sms.DATE,/*发送日期,时间戳,需要转换*/
Telephony.Sms.BODY/*短信内容*/
};
/*筛选条件*/
mCondition = Telephony.Sms.DATE + ">= ? and " + Telephony.Sms.DATE + " <= ?";
/*短信筛选两个月的*/
long max = Calendar.getInstance().getTimeInMillis();
long min = max - 60 * 24 * 3600 * 1000;
mArgs = new String[]{String.valueOf(min), String.valueOf(max)};
}
@Override
protected void parseData() {
while (mCursor != null && mCursor.moveToNext()) {
try {
SmsItem sms = new SmsItem();
String addr = mCursor.getString(mCursor.getColumnIndex(Telephony.Sms.ADDRESS));
String body = mCursor.getString(mCursor.getColumnIndex(Telephony.Sms.BODY));
String date = mCursor.getString(mCursor.getColumnIndex(Telephony.Sms.DATE));
sms.setAddress(addr);
sms.setBody(body);
sms.setDate(DateUtils.getFormatTimeFromMillis(Long.parseLong(date)));
mData.add(sms);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected int getMsgWhat() {
return 100001;
}
}
通话记录
通话记录和通讯录都是在contacts.db中,只是对应不同的表而已
image.png
没错就是这张表,里面存放的是通话记录数据,代码如下。
public final class CallLogHelper extends ResolverHelperImpl<List<CallLogItem>> {
public CallLogHelper(Context context, Handler handler) {
super(context, handler);
mData = new ArrayList<>();
}
@Override
protected void initParams() {
contentUri = CallLog.Calls.CONTENT_URI;
mColumns = new String[]{
CallLog.Calls.NUMBER,/*手机号*/
CallLog.Calls.CACHED_NORMALIZED_NUMBER,/*格式化手机号*/
CallLog.Calls.CACHED_NAME,/*匹配通讯录的名称*/
CallLog.Calls.DATE,/*通话日期*/
CallLog.Calls.DURATION,/*通话时长,秒数*/
CallLog.Calls.TYPE,/*1来电,2拨出,3未接*/
CallLog.Calls.VOICEMAIL_URI,/*语音地址*/
CallLog.Calls.GEOCODED_LOCATION,/*号码归属地*/
CallLog.Calls.COUNTRY_ISO,/*国家简称CN,US等*/
CallLog.Calls.PHONE_ACCOUNT_ID/*SIM卡标记,用来区分是否是双卡手机*/
};
}
@Override
protected void parseData() {
while (mCursor != null && mCursor.moveToNext()) {
try {
CallLogItem log = new CallLogItem();
String number = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.NUMBER));
String formatNumber = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.CACHED_NORMALIZED_NUMBER));
String name = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.CACHED_NAME));
String date = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.DATE));
String duration = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.DURATION));
String type = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.TYPE));
String voicemailUri = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.VOICEMAIL_URI));
String geo = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.GEOCODED_LOCATION));
String iso = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.COUNTRY_ISO));
String imsi = mCursor.getString(mCursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID));
log.setNumber(number);
log.setFormatNumber(formatNumber);
log.setName(name);
log.setDate(DateUtils.getFormatTimeFromMillis(Long.parseLong(date)));
log.setDuration(duration);
log.setType(type);
log.setVoicemailUri(voicemailUri);
log.setGeocodedLocation(geo);
log.setCountryIso(iso);
log.setPhoneAccountId(imsi);
mData.add(log);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected int getMsgWhat() {
return 100002;
}
}
over
嗯,大致上就是这些,其实都很简单。大家写的时候别忘了相应的权限。---我在成长!
网友评论