Android相关

Android通讯录,通话记录,短信

2017-08-13  本文已影响567人  你怕是很皮哦

最近数据部需要上传用户的通讯录,通话记录,短信等内容做分析,于是整理下这方面的知识。说句实话,其实获取的方式都是一个样子的,都是通过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

嗯,大致上就是这些,其实都很简单。大家写的时候别忘了相应的权限。---我在成长!

上一篇 下一篇

猜你喜欢

热点阅读