当来电或去电时,通过记录里的信息是怎么保存下来的呢?

在CallNotifier.java代码里有这样一个方法:

    private void onDisconnect(AsyncResult r) {        if (VDBG) log("onDisconnect()...  CallManager state: " + mCM.getState());        Connection c = (Connection) r.result;mDisconnectNumber = c.getAddress();if (DBG) log("mDisconnectNumber:" + mDisconnectNumber);if (DBG && c != null) {            log("- onDisconnect: cause = " + c.getDisconnectCause()                + ", incoming = " + c.isIncoming()                + ", date = " + c.getCreateTime());        }        mCdmaVoicePrivacyState = false;        int autoretrySetting = 0;        if ((c != null) && (c.getCall().getPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA)) {            autoretrySetting = android.provider.Settings.System.getInt(mApplication.                    getContentResolver(),android.provider.Settings.System.CALL_AUTO_RETRY, 0);        }        if ((c != null) && (c.getCall().getPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA)) {            // Stop any signalInfo tone being played when a call gets ended            stopSignalInfoTone();            // Resetting the CdmaPhoneCallState members            mApplication.cdmaPhoneCallState.resetCdmaPhoneCallState();            // Remove Call waiting timers            removeMessages(CALLWAITING_CALLERINFO_DISPLAY_DONE);            removeMessages(CALLWAITING_ADDCALL_DISABLE_TIMEOUT);        }        // Stop the ringer if it was ringing (for an incoming call that        // either disconnected by itself, or was rejected by the user.)        //        // TODO: We technically *shouldn't* stop the ringer if the        // foreground or background call disconnects while an incoming call        // is still ringing, but that's a really rare corner case.        // It's safest to just unconditionally stop the ringer here.        // CDMA: For Call collision cases i.e. when the user makes an out going call        // and at the same time receives an Incoming Call, the Incoming Call is given        // higher preference. At this time framework sends a disconnect for the Out going        // call connection hence we should *not* be stopping the ringer being played for        // the Incoming Call        Call ringingCall = mCM.getFirstActiveRingingCall();        if (ringingCall.getPhone().getPhoneType() == Phone.PHONE_TYPE_CDMA) {            if (PhoneUtils.isRealIncomingCall(ringingCall.getState())) {                // Also we need to take off the "In Call" icon from the Notification                // area as the Out going Call never got connected                if (DBG) log("cancelCallInProgressNotification()... (onDisconnect)");                NotificationMgr.getDefault().cancelCallInProgressNotification();            } else {                if (DBG) log("stopRing()... (onDisconnect)");                mRinger.stopRing();            }        } else { // GSM            if (DBG) log("stopRing()... (onDisconnect)");            mRinger.stopRing();        }        // stop call waiting tone if needed when disconnecting        if (mCallWaitingTonePlayer != null) {            mCallWaitingTonePlayer.stopTone();            mCallWaitingTonePlayer = null;        }        // Check for the various tones we might need to play (thru the        // earpiece) after a call disconnects.        int toneToPlay = InCallTonePlayer.TONE_NONE;        // The "Busy" or "Congestion" tone is the highest priority:        if (c != null) {            Connection.DisconnectCause cause = c.getDisconnectCause();            if (cause == Connection.DisconnectCause.BUSY) {                if (DBG) log("- need to play BUSY tone!");                toneToPlay = InCallTonePlayer.TONE_BUSY;            } else if (cause == Connection.DisconnectCause.CONGESTION) {                if (DBG) log("- need to play CONGESTION tone!");                toneToPlay = InCallTonePlayer.TONE_CONGESTION;            } else if (((cause == Connection.DisconnectCause.NORMAL)                    || (cause == Connection.DisconnectCause.LOCAL))                    && (mApplication.isOtaCallInActiveState())) {                if (DBG) log("- need to play OTA_CALL_END tone!");                toneToPlay = InCallTonePlayer.TONE_OTA_CALL_END;            } else if (cause == Connection.DisconnectCause.CDMA_REORDER) {                if (DBG) log("- need to play CDMA_REORDER tone!");                toneToPlay = InCallTonePlayer.TONE_REORDER;            } else if (cause == Connection.DisconnectCause.CDMA_INTERCEPT) {                if (DBG) log("- need to play CDMA_INTERCEPT tone!");                toneToPlay = InCallTonePlayer.TONE_INTERCEPT;            } else if (cause == Connection.DisconnectCause.CDMA_DROP) {                if (DBG) log("- need to play CDMA_DROP tone!");                toneToPlay = InCallTonePlayer.TONE_CDMA_DROP;            } else if (cause == Connection.DisconnectCause.OUT_OF_SERVICE) {                if (DBG) log("- need to play OUT OF SERVICE tone!");                toneToPlay = InCallTonePlayer.TONE_OUT_OF_SERVICE;            } else if (cause == Connection.DisconnectCause.UNOBTAINABLE_NUMBER) {                if (DBG) log("- need to play TONE_UNOBTAINABLE_NUMBER tone!");                toneToPlay = InCallTonePlayer.TONE_UNOBTAINABLE_NUMBER;            } else if (cause == Connection.DisconnectCause.ERROR_UNSPECIFIED) {                if (DBG) log("- DisconnectCause is ERROR_UNSPECIFIED: play TONE_CALL_ENDED!");                toneToPlay = InCallTonePlayer.TONE_CALL_ENDED;            }        }        // If we don't need to play BUSY or CONGESTION, then play the        // "call ended" tone if this was a "regular disconnect" (i.e. a        // normal call where one end or the other hung up) *and* this        // disconnect event caused the phone to become idle.  (In other        // words, we *don't* play the sound if one call hangs up but        // there's still an active call on the other line.)        // TODO: We may eventually want to disable this via a preference.        if ((toneToPlay == InCallTonePlayer.TONE_NONE)            && (mCM.getState() == Phone.State.IDLE)            && (c != null)) {            Connection.DisconnectCause cause = c.getDisconnectCause();            if ((cause == Connection.DisconnectCause.NORMAL)  // remote hangup                || (cause == Connection.DisconnectCause.LOCAL)) {  // local hangup                if (VDBG) log("- need to play CALL_ENDED tone!");                toneToPlay = InCallTonePlayer.TONE_CALL_ENDED;                mIsCdmaRedialCall = false;            }        }        if (mCM.getState() == Phone.State.IDLE) {            // Don't reset the audio mode or bluetooth/speakerphone state            // if we still need to let the user hear a tone through the earpiece.            if (toneToPlay == InCallTonePlayer.TONE_NONE) {                int currentMode = mAudioManager.getMode();                if(AudioManager.MODE_IN_VT_CALL == currentMode){                    if(!isVTConnected){                        resetAudioStateAfterDisconnect();                    }else{                        isNeedResetAudio = true;                        sendEmptyMessageDelayed(DELAY_RESET_AUDIO_MODE, 5000);                    }                }else{                    resetAudioStateAfterDisconnect();                }            }            NotificationMgr.getDefault().cancelCallInProgressNotification();            // If the InCallScreen is *not* in the foreground, forcibly            // dismiss it to make sure it won't still be in the activity            // history.  (But if it *is* in the foreground, don't mess            // with it; it needs to be visible, displaying the "Call            // ended" state.)            if (!mApplication.isShowingCallScreen()) {                if (VDBG) log("onDisconnect: force InCallScreen to finish()");                mApplication.dismissCallScreen();            } else {                if (VDBG) log("onDisconnect: In call screen. Set short timeout.");                mApplication.clearUserActivityTimeout();            }        }        if (c != null) {            final String number = c.getAddress();            final long date = c.getCreateTime();            final long duration = c.getDurationMillis();            final Connection.DisconnectCause cause = c.getDisconnectCause();            final Phone phone = c.getCall().getPhone();    final int dialType;    if (PhoneApp.getInstance().isVTCall())    dialType = CallLog.Calls.VIDEO_DIAL;    else    dialType = CallLog.Calls.VOICE_DIAL;            // Set the "type" to be displayed in the call log (see constants in CallLog.Calls)            final int callLogType;            if (c.isIncoming()) {                callLogType = (cause == Connection.DisconnectCause.INCOMING_MISSED ?                               Calls.MISSED_TYPE : Calls.INCOMING_TYPE);            } else {                callLogType = Calls.OUTGOING_TYPE;            }            if (VDBG) log("- callLogType: " + callLogType + ", UserData: " + c.getUserData());            {                final CallerInfo ci = getCallerInfoFromConnection(c);  // May be null.                final String logNumber = getLogNumber(c, ci);                if (DBG) log("- onDisconnect(): logNumber set to: " + /*logNumber*/ "xxxxxxx");                // TODO: In getLogNumber we use the presentation from                // the connection for the CNAP. Should we use the one                // below instead? (comes from caller info)                // For international calls, 011 needs to be logged as +                final int presentation = getPresentation(c, ci);                if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {                    if ((PhoneNumberUtils.isEmergencyNumber(number))                            && (mCurrentEmergencyToneState != EMERGENCY_TONE_OFF)) {                        if (mEmergencyTonePlayerVibrator != null) {                            mEmergencyTonePlayerVibrator.stop();                        }                    }                }                // To prevent accidental redial of emergency numbers                // (carrier requirement) the quickest solution is to                // not log the emergency number. We gate on CDMA                // (ugly) when we actually mean carrier X.                // TODO: Clean this up and come up with a unified strategy.                final boolean shouldNotlogEmergencyNumber =                        (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA);                // Don't call isOtaSpNumber on GSM phones.                final boolean isOtaNumber = (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA)                        && phone.isOtaSpNumber(number);                final boolean isEmergencyNumber = PhoneNumberUtils.isEmergencyNumber(number);                // Don't put OTA or CDMA Emergency calls into call logif (!(isOtaNumber || isEmergencyNumber && shouldNotlogEmergencyNumber ||mIsPhoneNumberInBlackList)) {CallLogAsync.AddCallArgs args = new CallLogAsync.AddCallArgs( mApplication, ci, logNumber, presentation, callLogType, date, duration, dialType);                     mCallLog.addCall(args);    mIsPhoneNumberInBlackList = false;                }            }            if (callLogType == Calls.MISSED_TYPE) {                // Show the "Missed call" notification.                // (Note we *don't* do this if this was an incoming call that                // the user deliberately rejected.)                showMissedCallNotification(c, date);            }            // Possibly play a "post-disconnect tone" thru the earpiece.            // We do this here, rather than from the InCallScreen            // activity, since we need to do this even if you're not in            // the Phone UI at the moment the connection ends.            if (toneToPlay != InCallTonePlayer.TONE_NONE) {                if (VDBG) log("- starting post-disconnect tone (" + toneToPlay + ")...");                new InCallTonePlayer(toneToPlay).start();                // TODO: alternatively, we could start an InCallTonePlayer                // here with an "unlimited" tone length,                // and manually stop it later when this connection truly goes                // away.  (The real connection over the network was closed as soon                // as we got the BUSY message.  But our telephony layer keeps the                // connection open for a few extra seconds so we can show the                // "busy" indication to the user.  We could stop the busy tone                // when *that* connection's "disconnect" event comes in.)            }            if (mCM.getState() == Phone.State.IDLE) {                // Release screen wake locks if the in-call screen is not                // showing. Otherwise, let the in-call screen handle this because                // it needs to show the call ended screen for a couple of                // seconds.                if (!mApplication.isShowingCallScreen()) {                    if (VDBG) log("- NOT showing in-call screen; releasing wake locks!");                    mApplication.setScreenTimeout(PhoneApp.ScreenTimeoutDuration.DEFAULT);                    mApplication.requestWakeState(PhoneApp.WakeState.SLEEP);                } else {                    if (VDBG) log("- still showing in-call screen; not releasing wake locks.");                }            } else {                if (VDBG) log("- phone still in use; not releasing wake locks.");            }            if (((mPreviousCdmaCallState == Call.State.DIALING)                    || (mPreviousCdmaCallState == Call.State.ALERTING))                    && (!PhoneNumberUtils.isEmergencyNumber(number))                    && (cause != Connection.DisconnectCause.INCOMING_MISSED )                    && (cause != Connection.DisconnectCause.NORMAL)                    && (cause != Connection.DisconnectCause.LOCAL)                    && (cause != Connection.DisconnectCause.INCOMING_REJECTED)) {                if (!mIsCdmaRedialCall) {                    if (autoretrySetting == InCallScreen.AUTO_RETRY_ON) {                        // TODO: (Moto): The contact reference data may need to be stored and use                        // here when redialing a call. For now, pass in NULL as the URI parameter.                        PhoneUtils.placeCall(phone, number, null);                        mIsCdmaRedialCall = true;                    } else {                        mIsCdmaRedialCall = false;                    }                } else {                    mIsCdmaRedialCall = false;                }            }        }    }

CDMA情况:

    /**     * Performs Call logging based on Timeout or Ignore Call Waiting Call for CDMA,     * and finally calls Hangup on the Call Waiting connection.     *     * This method should be called only from the UI thread.     * @see sendCdmaCallWaitingReject()     */    private void onCdmaCallWaitingReject() {        final Call ringingCall = mCM.getFirstActiveRingingCall();        // Call waiting timeout scenario        if (ringingCall.getState() == Call.State.WAITING) {            // Code for perform Call logging and missed call notification            Connection c = ringingCall.getLatestConnection();            if (c != null) {                String number = c.getAddress();                int presentation = c.getNumberPresentation();                final long date = c.getCreateTime();                final long duration = c.getDurationMillis();                final int callLogType = mCallWaitingTimeOut ?                        Calls.MISSED_TYPE : Calls.INCOMING_TYPE;                // get the callerinfo object and then log the call with it.                Object o = c.getUserData();                final CallerInfo ci;                if ((o == null) || (o instanceof CallerInfo)) {                    ci = (CallerInfo) o;                } else {                    ci = ((PhoneUtils.CallerInfoToken) o).currentInfo;                }// add this to judge dial typefinal int dialType;if (PhoneApp.getInstance().isVTCall())dialType = CallLog.Calls.VIDEO_DIAL;elsedialType = CallLog.Calls.VOICE_DIAL;                // Do final CNAP modifications of logNumber prior to logging [mimicking                // onDisconnect()]                final String logNumber = PhoneUtils.modifyForSpecialCnapCases(                        mApplication, ci, number, presentation);                final int newPresentation = (ci != null) ? ci.numberPresentation : presentation;                if (DBG) log("- onCdmaCallWaitingReject(): logNumber set to: " + logNumber                        + ", newPresentation value is: " + newPresentation);                CallLogAsync.AddCallArgs args =                        new CallLogAsync.AddCallArgs(                            mApplication, ci, logNumber, presentation,                            callLogType, date, duration, dialType);                mCallLog.addCall(args);                if (callLogType == Calls.MISSED_TYPE) {                    // Add missed call notification                    showMissedCallNotification(c, date);                } else {                    // Remove Call waiting 20 second display timer in the queue                    removeMessages(CALLWAITING_CALLERINFO_DISPLAY_DONE);                }                // Hangup the RingingCall connection for CW                PhoneUtils.hangup(c);            }            //Reset the mCallWaitingTimeOut boolean            mCallWaitingTimeOut = false;        }    }

通过上述的红色部分,调用了:CallLogAsync.AddCallArgs的AddCallArgs方法,而CallLogAsync.java是管理通讯录的接口。

/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.phone;import android.content.Context;import android.net.Uri;import android.os.AsyncTask;import android.os.Looper;import android.provider.CallLog.Calls;import android.util.Log;import com.android.internal.telephony.CallerInfo;/** * Class to access the call logs database asynchronously since * database ops can take a long time depending on the system's load. * It uses AsyncTask which has its own thread pool. * * <pre class="prettyprint"> * Typical usage: * ============== * *  // From an activity... *  String mLastNumber = ""; * *  CallLogAsync log = new CallLogAsync(); * *  CallLogAsync.AddCallArgs addCallArgs = new CallLogAsync.AddCallArgs( *      this, ci, number, presentation, type, timestamp, duration); * *  log.addCall(addCallArgs); * *  CallLogAsync.GetLastOutgoingCallArgs lastCallArgs = new CallLogAsync.GetLastOutgoingCallArgs( *      this, new CallLogAsync.OnLastOutgoingCallComplete() { *               public void lastOutgoingCall(String number) { mLastNumber = number; } *            }); *  log.getLastOutgoingCall(lastCallArgs); * </pre> * */public class CallLogAsync {    private static final String TAG = "CallLogAsync";    /**     * Parameter object to hold the args to add a call in the call log DB.     */    public static class AddCallArgs {        /**         * @param ci               CallerInfo.         * @param number           To be logged.         * @param presentation     Of the number.         * @param callType         The type of call (e.g INCOMING_TYPE). @see         *                         android.provider.CallLog for the list of values.         * @param timestamp        Of the call (millisecond since epoch).         * @param durationInMillis Of the call (millisecond).         */        public AddCallArgs(Context context,                           CallerInfo ci,                           String number,                           int presentation,                           int callType,                           long timestamp,                           long durationInMillis,   int dialType) {            // Note that the context is passed each time. We could            // have stored it in a member but we've run into a bunch            // of memory leaks in the past that resulted from storing            // references to contexts in places that were long lived            // when the contexts were expected to be short lived. For            // example, if you initialize this class with an Activity            // instead of an Application the Activity can't be GCed            // until this class can, and Activities tend to hold            // references to large amounts of RAM for things like the            // bitmaps in their views.            //            // Having hit more than a few of those bugs in the past            // we've grown cautious of storing references to Contexts            // when it's not very clear that the thing holding the            // references is tightly tied to the Context, for example            // Views the Activity is displaying.            this.context = context;            this.ci = ci;            this.number = number;            this.presentation = presentation;            this.callType = callType;            this.timestamp = timestamp;            this.durationInSec = (int)(durationInMillis / 1000);    this.dialType = dialType;}        // Since the members are accessed directly, we don't use the        // mXxxx notation.        public final Context context;        public final CallerInfo ci;        public final String number;        public final int presentation;        public final int callType;        public final long timestamp;        public final int durationInSec;public final int dialType;    }    /**     * Parameter object to hold the args to get the last outgoing call     * from the call log DB.     */    public static class GetLastOutgoingCallArgs {        public GetLastOutgoingCallArgs(Context context,                                       OnLastOutgoingCallComplete callback) {            this.context = context;            this.callback = callback;        }        public final Context context;        public final OnLastOutgoingCallComplete callback;    }    /**     * Non blocking version of CallLog.addCall(...)     */    public AsyncTask addCall(AddCallArgs args) {        assertUiThread();        return new AddCallTask().execute(args);    }    /** Interface to retrieve the last dialed number asynchronously. */    public interface OnLastOutgoingCallComplete {        /** @param number The last dialed number or an empty string if         *                none exists yet. */        void lastOutgoingCall(String number);    }    /**     * CallLog.getLastOutgoingCall(...)     */    public AsyncTask getLastOutgoingCall(GetLastOutgoingCallArgs args) {        assertUiThread();        return new GetLastOutgoingCallTask(args.callback).execute(args);    }    /**     * AsyncTask to save calls in the DB.     */    private class AddCallTask extends AsyncTask<AddCallArgs, Void, Uri[]> {        @Override        protected Uri[] doInBackground(AddCallArgs... callList) {            int count = callList.length;            Uri[] result = new Uri[count];            //Add by kylin 2012.02.14            try {            for (int i = 0; i < count; i++) {                    AddCallArgs c = callList[i];                                        // May block.                    result[i] = Calls.addCall(                        c.ci, c.context, c.number, c.presentation,                        c.callType, c.timestamp, c.durationInSec, c.dialType);                                    }} catch (Exception e) {// TODO: handle exception}            //end            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.");                }            }        }    }    /**     * AsyncTask to get the last outgoing call from the DB.     */    private class GetLastOutgoingCallTask extends AsyncTask<GetLastOutgoingCallArgs, Void, String> {        private final OnLastOutgoingCallComplete mCallback;        private String mNumber;        public GetLastOutgoingCallTask(OnLastOutgoingCallComplete callback) {            mCallback = callback;        }        // Happens on a background thread. We cannot run the callback        // here because only the UI thread can modify the view        // hierarchy (e.g enable/disable the dial button). The        // callback is ran rom the post execute method.        @Override        protected String doInBackground(GetLastOutgoingCallArgs... list) {            int count = list.length;            String number = "";            for (GetLastOutgoingCallArgs args : list) {                // May block. Select only the last one.                number = Calls.getLastOutgoingCall(args.context);            }            return number;  // passed to the onPostExecute method.        }        // Happens on the UI thread, it is safe to run the callback        // that may do some work on the views.        @Override        protected void onPostExecute(String number) {            assertUiThread();            mCallback.lastOutgoingCall(number);        }    }    private void assertUiThread() {        if (!Looper.getMainLooper().equals(Looper.myLooper())) {            throw new RuntimeException("Not on the UI thread!");        }    }}




更多相关文章

  1. android事件4-onTouchEvent, onClick及onLongClick的调用机制
  2. android 移动图片
  3. Android(安卓)Studio 安装No JVM Installation found. Please in
  4. Android打电话的流程
  5. andorid中的html.fromhtml方法
  6. android 自定义view中onMeasure()
  7. Android类参考---Fragment(五)
  8. Listview中Button抢占焦点的解决方法
  9. Android(安卓)中Parcelable的作用

随机推荐

  1. Android(安卓)ListView详解
  2. google maps api 地址
  3. Android(安卓)Activity界面切换添加动画
  4. android 服务前台运行startForeground
  5. 第一节(搭建环境)
  6. Android系统信息获取
  7. android中GridView关于间距的属性值介绍
  8. android工具链与GNU工具链的比较
  9. 对android的Activity切换时输入法不弹出
  10. Android短彩信数据库信息整理