最近做些和通讯相关的东西,源于网上这块知识比较匮乏,所以我就整理下自己的思路,正好梳理下流程,以备不需之用;俗话说得好“好脑子比不了烂笔头”;
通话记录有几种动作,插入(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就说到这里,未完待续。。。 。。。