Android通话记录CallLog简单摘要

            最近做些和通讯相关的东西,源于网上这块知识比较匮乏,所以我就整理下自己的思路,正好梳理下流程,以备不需之用;俗话说得好“好脑子比不了烂笔头”;

      通话记录有几种动作,插入(insert),删除(delete) ,查询(query),因为通话记录不需要更改,所以就不用update(更新了);

     一、先来看看Insert插入

     首先通话记录是在电话挂断以后,才进行的操作,这个操作是异步的操作,在后台悄悄的插入到Calls中去的,通话记录的Uri是“content://call_log/calls”;

     Step 1:电话挂断后,即在CallNotifier.java类(管理电话通话状态的类)的onDisconnect()方法中:

onDisconnect()是电话主动挂断、被动挂断后调用的方法,即和通话方已经断开连接后触发的方法。在这个方法中有

段代码如下:

 if (okToLogThisCall) {
                    CallLogAsync.AddCallArgs args;
                    int simIdEx = CALL_TYPE_NONE;

                    if (!GeminiUtils.isGeminiSupport() || isSipCall) { //Single Card
                        if (isSipCall) {
                            simIdEx = CALL_TYPE_SIP;
                        } else {
                            simIdEx = CALL_TYPE_NONE;
                            if (PhoneGlobals.getInstance().phoneMgr.hasIccCard()) {
                                SimInfoRecord info = SIMInfoWrapper.getDefault().getSimInfoBySlot(0);
                                if (info != null) {
                                    simIdEx = (int)info.mSimInfoId;
                                } else {
                                    //Give an default simId, in most case, this is invalid
                                    simIdEx = 1;
                                }
                            }
                        }
                        if (FeatureOption.MTK_VT3G324M_SUPPORT) {
                            args = new CallLogAsync.AddCallArgs(
                                mApplication, ci, logNumber, presentation,
                                callLogType, date, duration, simIdEx, vtCall);
                        } else {
                            args = new CallLogAsync.AddCallArgs(
                                mApplication, ci, logNumber, presentation,
                                callLogType, date, duration, simIdEx);
                        }
                    } else { //dual SIM

CallLogAsync.AddCallArgs这个类即为管理增加通话记录的类;

args = new CallLogAsync.AddCallArgs(
                                mApplication, ci, logNumber, presentation,
                                callLogType, date, duration, simIdEx, vtCall);

这个方法即为初始化的证据。插入的证据在这:

try {
                        mCallLog.addCall(args);
                    } catch (SQLiteDiskIOException e) {
                        // TODO Auto-generated catch block
                        Log.e(LOG_TAG, "Error!! - onDisconnect() Disk Full!");
                        e.printStackTrace();
                    }
addCall(),即为插入DB的证据;


        Step 2:在addCall()方法中执行的代码如下:

 public AsyncTask addCall(AddCallArgs args) {
        assertUiThread();
        return new AddCallTask().execute(args);
    }
这个就是后台悄悄的插入DB的罪魁祸首:
 private class AddCallTask extends AsyncTask<AddCallArgs, Void, Uri[]> {
        @Override
        protected Uri[] doInBackground(AddCallArgs... callList) {
            int count = callList.length;
            Uri[] result = new Uri[count];
            for (int i = 0; i < count; i++) {
                AddCallArgs c = callList[i];

                try {
                    // May block.
                    result[i] = Calls.addCall(
                            c.ci, c.context, c.number, c.presentation,
                            c.callType, c.timestamp, c.durationInSec, c.simId, c.vtCall);
                } catch (Exception e) {
                    // This must be very rare but may happen in legitimate cases.
                    // e.g. If the phone is encrypted and thus write request fails, it may
                    // cause some kind of Exception (right now it is IllegalArgumentException, but
                    // might change).
                    //
                    // We don‘t want to crash the whole process just because of that.
                    // Let‘s just ignore it and leave logs instead.
                    Log.e(TAG, "Exception raised during adding CallLog entry: " + e);
                    result[i] = null;
                }

                
                Log.d(TAG, "Calls.addCall, number=" + c.number + " vtCall=" + c.vtCall
                        + " presentation:" + c.presentation + " callType:" + c.callType
                        + " timestamp:" + c.timestamp + " durationInSec:" + c.durationInSec
                        + " simId: " + c.simId + " vtCall:" + c.vtCall);
            }
            return result;
        }

        // Perform a simple sanity check to make sure the call was
        // written in the database. Typically there is only one result
        // per call so it is easy to identify which one failed.
        @Override
        protected void onPostExecute(Uri[] result) {
            for (Uri uri : result) {
                if (uri == null) {
                    Log.e(TAG, "Failed to write call to the log.");
                }
            }
        }
    }

        Step 3:Calls.addCall()这个方法调用的地方在framework层了,CallLog.java这个类中:

路径:frameworks/base/core/java/android/provider/CallLog.java.

方法如下:

public static Uri addCall(CallerInfo ci, Context context, String number,
                int presentation, int callType, long start, int duration, int simId, int vtCall) {
            final ContentResolver resolver = context.getContentResolver();


            // If this is a private number then set the number to Private, otherwise check
            // if the number field is empty and set the number to Unavailable
            if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
                number = CallerInfo.PRIVATE_NUMBER;
                if (ci != null) ci.name = "";
            } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
                number = CallerInfo.PAYPHONE_NUMBER;
                if (ci != null) ci.name = "";
            } else if (TextUtils.isEmpty(number)
                    || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
                number = CallerInfo.UNKNOWN_NUMBER;
                if (ci != null) ci.name = "";
            }


            ContentValues values = new ContentValues(5);


            values.put(NUMBER, number);
            values.put(TYPE, Integer.valueOf(callType));
            values.put(DATE, Long.valueOf(start));
            values.put(DURATION, Long.valueOf(duration));
            values.put(NEW, Integer.valueOf(1));
            if (callType == MISSED_TYPE) {
                values.put(IS_READ, Integer.valueOf(0));
            }
            if (ci != null) {
                values.put(CACHED_NAME, ci.name);
                values.put(CACHED_NUMBER_TYPE, ci.numberType);
                values.put(CACHED_NUMBER_LABEL, ci.numberLabel);
            }
            /// M: @{
            values.put(SIM_ID, simId);
            if (vtCall >= 0) {
                values.put(VTCALL, vtCall);
            }
            /// @}
            if ((ci != null) && (ci.person_id > 0)) {
                // Update usage information for the number associated with the contact ID.
                // We need to use both the number and the ID for obtaining a data ID since other
                // contacts may have the same number.


                final Cursor cursor;


                // We should prefer normalized one (probably coming from
                // Phone.NORMALIZED_NUMBER column) first. If it isn‘t available try others.
                if (ci.normalizedNumber != null) {
                    final String normalizedPhoneNumber = ci.normalizedNumber;
                    cursor = resolver.query(Phone.CONTENT_URI,
                            new String[] { Phone._ID },
                            Phone.CONTACT_ID + " =? AND " + Phone.NORMALIZED_NUMBER + " =?",
                            new String[] { String.valueOf(ci.person_id), normalizedPhoneNumber},
                            null);
                } else {
                    final String phoneNumber = ci.phoneNumber != null ? ci.phoneNumber : number;
                    cursor = resolver.query(
                            Uri.withAppendedPath(Callable.CONTENT_FILTER_URI,
                                    Uri.encode(phoneNumber)),
                            new String[] { Phone._ID },
                            Phone.CONTACT_ID + " =?",
                            new String[] { String.valueOf(ci.person_id) },
                            null);
                }


                if (cursor != null) {
                    try {
                        if (cursor.getCount() > 0 && cursor.moveToFirst()) {
                            final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
                                    .appendPath(cursor.getString(0))
                                    .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
                                                DataUsageFeedback.USAGE_TYPE_CALL)
                                    .build();
                            resolver.update(feedbackUri, new ContentValues(), null, null);
                        }
                    } finally {
                        cursor.close();
                    }
                }
            }


            /// M: new feature:IP dial enhancement start @{
            String ipPrefix = null;
            if (FeatureOption.MTK_GEMINI_SUPPORT) {
                ipPrefix = Settings.System.getString(resolver, "ipprefix" + simId);
            } else {
                ipPrefix = Settings.System.getString(resolver, "ipprefix");
            }
            if (null != ipPrefix && null != number && number.startsWith(ipPrefix)
                    && !number.equals(ipPrefix) && callType == Calls.OUTGOING_TYPE) {
                values.put(IP_PREFIX, ipPrefix);
                String tmpNumber = number.substring(ipPrefix.length(), number.length());
                values.put(NUMBER, tmpNumber);
            }
            /// @}


            //这个才是Insert的地方,和我们普通的insert是一样的
            Uri result = resolver.insert(CONTENT_URI, values);


            removeExpiredEntries(context);


            return result;
        }

   这个insert就说到这里,未完待续。。。 。。。





Android通话记录CallLog简单摘要,布布扣,bubuko.com

Android通话记录CallLog简单摘要

上一篇:Java(Android)线程池


下一篇:Android 程序代码实现apk的安装和卸载