Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 4.0 Phone撥號和來電流程分析

Android 4.0 Phone撥號和來電流程分析

編輯:關於Android編程


本文只對應用層進行分析

1.來電流程分析

PhoneApp在初始化時會實例CallNotifier對象,Callnotifier主要是對電話狀態的監聽,通知事件

[java]
PhoneApp創建一個CallNotifier        
 
    // Create the CallNotifer singleton, which handles  
            // asynchronous events from the telephony layer (like  
            // launching the incoming-call UI when an incoming call comes  
            // in.)  
            notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync()); 

PhoneApp創建一個CallNotifier      

    // Create the CallNotifer singleton, which handles
            // asynchronous events from the telephony layer (like
            // launching the incoming-call UI when an incoming call comes
            // in.)
            notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());
Callnotifier實現對電話狀態的監聽

[java]
/** Private constructor; @see init() */ 
 private CallNotifier(PhoneApp app, Phone phone, Ringer ringer, 
                      BluetoothHandsfree btMgr, CallLogAsync callLog) { 
     mApplication = app; 
     mCM = app.mCM; 
     mCallLog = callLog; 
 
     mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE); 
 
     <SPAN style="FONT-SIZE: 18px; COLOR: #cc0000"><STRONG>registerForNotifications();//狀態監聽</STRONG></SPAN> 

   /** Private constructor; @see init() */
    private CallNotifier(PhoneApp app, Phone phone, Ringer ringer,
                         BluetoothHandsfree btMgr, CallLogAsync callLog) {
        mApplication = app;
        mCM = app.mCM;
        mCallLog = callLog;

        mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE);

        registerForNotifications();//狀態監聽
 registerForNotifications方法注冊電話狀態監聽

[java]
private void registerForNotifications() { 

    private void registerForNotifications() {
[java] view plaincopyprint?mCM.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null); 

        mCM.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);[java] view plaincopyprint?    mCM.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null); 
    mCM.registerForDisconnect(this, PHONE_DISCONNECT, null); 
    mCM.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null); 
    mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null); 
    mCM.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null); 
    mCM.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null); 
    mCM.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null); 
    mCM.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null); 
    mCM.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null); 
    mCM.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null); 
    mCM.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null); 
    mCM.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null); 

        mCM.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);
        mCM.registerForDisconnect(this, PHONE_DISCONNECT, null);
        mCM.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);
        mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null);
        mCM.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null);
        mCM.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null);
        mCM.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null);
        mCM.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null);
        mCM.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null);
        mCM.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null);
        mCM.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null);
        mCM.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null);
    }
  mCM.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null); 監聽來電,在handleMessage函數內處理

[java]
@Override 
   public void handleMessage(Message msg) { 
       switch (msg.what) { 
           case PHONE_NEW_RINGING_CONNECTION: 
               log("RINGING... (new)"); 
               onNewRingingConnection((AsyncResult) msg.obj); 
               mSilentRingerRequested = false; 
               break; 

 @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case PHONE_NEW_RINGING_CONNECTION:
                log("RINGING... (new)");
                onNewRingingConnection((AsyncResult) msg.obj);
                mSilentRingerRequested = false;
                break;轉到onNewRingingConnection處理來電,最後轉到showIncomingCall函數啟動InCallScreen界面,當然還有處理一些狀態更新,響鈴之類的

[java]
/**
    * Handles a "new ringing connection" event from the telephony layer.
    */ 
   private void onNewRingingConnection(AsyncResult r) { 
       Connection c = (Connection) r.result; 
       log("onNewRingingConnection(): state = " + mCM.getState() + ", conn = { " + c + " }"); 
       Call ringing = c.getCall(); 
       Phone phone = ringing.getPhone(); 
 
       // Check for a few cases where we totally ignore incoming calls.  
       if (ignoreAllIncomingCalls(phone)) { 
           // Immediately reject the call, without even indicating to the user  
           // that an incoming call occurred.  (This will generally send the  
           // caller straight to voicemail, just as if we *had* shown the  
           // incoming-call UI and the user had declined the call.)  
           PhoneUtils.hangupRingingCall(ringing); 
           return; 
       } 
 
       if (c == null) { 
           Log.w(LOG_TAG, "CallNotifier.onNewRingingConnection(): null connection!"); 
           // Should never happen, but if it does just bail out and do nothing.  
           return; 
       } 
 
       if (!c.isRinging()) { 
           Log.i(LOG_TAG, "CallNotifier.onNewRingingConnection(): connection not ringing!"); 
           // This is a very strange case: an incoming call that stopped  
           // ringing almost instantly after the onNewRingingConnection()  
           // event.  There's nothing we can do here, so just bail out  
           // without doing anything.  (But presumably we'll log it in  
           // the call log when the disconnect event comes in...)  
           return; 
       } 
 
       // Stop any signalInfo tone being played on receiving a Call  
       stopSignalInfoTone(); 
 
       Call.State state = c.getState(); 
       // State will be either INCOMING or WAITING.  
       if (VDBG) log("- connection is ringing!  state = " + state); 
       // if (DBG) PhoneUtils.dumpCallState(mPhone);  
 
       // No need to do any service state checks here (like for  
       // "emergency mode"), since in those states the SIM won't let  
       // us get incoming connections in the first place.  
 
       // TODO: Consider sending out a serialized broadcast Intent here  
       // (maybe "ACTION_NEW_INCOMING_CALL"), *before* starting the  
       // ringer and going to the in-call UI.  The intent should contain  
       // the caller-id info for the current connection, and say whether  
       // it would be a "call waiting" call or a regular ringing call.  
       // If anybody consumed the broadcast, we'd bail out without  
       // ringing or bringing up the in-call UI.  
       //  
       // This would give 3rd party apps a chance to listen for (and  
       // intercept) new ringing connections.  An app could reject the  
       // incoming call by consuming the broadcast and doing nothing, or  
       // it could "pick up" the call (without any action by the user!)  
       // via some future TelephonyManager API.  
       //  
       // See bug 1312336 for more details.  
       // We'd need to protect this with a new "intercept incoming calls"  
       // system permission.  
 
       // Obtain a partial wake lock to make sure the CPU doesn't go to  
       // sleep before we finish bringing up the InCallScreen.  
       // (This will be upgraded soon to a full wake lock; see  
       // showIncomingCall().)  
       if (VDBG) log("Holding wake lock on new incoming connection."); 
       mApplication.requestWakeState(PhoneApp.WakeState.PARTIAL); 
 
       // - don't ring for call waiting connections  
       // - do this before showing the incoming call panel  
       if (PhoneUtils.isRealIncomingCall(state)) { 
           startIncomingCallQuery(c); 
       } else { 
           if (PhoneUtils.PhoneSettings.vibCallWaiting(mApplication)) { 
               mApplication.vibrate(200,300,500); 
           } 
           if (VDBG) log("- starting call waiting tone..."); 
           if (mCallWaitingTonePlayer == null) { 
               mCallWaitingTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_CALL_WAITING); 
               mCallWaitingTonePlayer.start(); 
           } 
           // in this case, just fall through like before, and call  
           // showIncomingCall().  
           if (DBG) log("- showing incoming call (this is a WAITING call)..."); 
           showIncomingCall(); 
       } 
 
       // Note we *don't* post a status bar notification here, since  
       // we're not necessarily ready to actually show the incoming call  
       // to the user.  (For calls in the INCOMING state, at least, we  
       // still need to run a caller-id query, and we may not even ring  
       // at all if the "send directly to voicemail" flag is set.)  
       //  
       // Instead, we update the notification (and potentially launch the  
       // InCallScreen) from the showIncomingCall() method, which runs  
       // when the caller-id query completes or times out.  
 
       if (VDBG) log("- onNewRingingConnection() done."); 
   } 

 /**
     * Handles a "new ringing connection" event from the telephony layer.
     */
    private void onNewRingingConnection(AsyncResult r) {
        Connection c = (Connection) r.result;
        log("onNewRingingConnection(): state = " + mCM.getState() + ", conn = { " + c + " }");
        Call ringing = c.getCall();
        Phone phone = ringing.getPhone();

        // Check for a few cases where we totally ignore incoming calls.
        if (ignoreAllIncomingCalls(phone)) {
            // Immediately reject the call, without even indicating to the user
            // that an incoming call occurred.  (This will generally send the
            // caller straight to voicemail, just as if we *had* shown the
            // incoming-call UI and the user had declined the call.)
            PhoneUtils.hangupRingingCall(ringing);
            return;
        }

        if (c == null) {
            Log.w(LOG_TAG, "CallNotifier.onNewRingingConnection(): null connection!");
            // Should never happen, but if it does just bail out and do nothing.
            return;
        }

        if (!c.isRinging()) {
            Log.i(LOG_TAG, "CallNotifier.onNewRingingConnection(): connection not ringing!");
            // This is a very strange case: an incoming call that stopped
            // ringing almost instantly after the onNewRingingConnection()
            // event.  There's nothing we can do here, so just bail out
            // without doing anything.  (But presumably we'll log it in
            // the call log when the disconnect event comes in...)
            return;
        }

        // Stop any signalInfo tone being played on receiving a Call
        stopSignalInfoTone();

        Call.State state = c.getState();
        // State will be either INCOMING or WAITING.
        if (VDBG) log("- connection is ringing!  state = " + state);
        // if (DBG) PhoneUtils.dumpCallState(mPhone);

        // No need to do any service state checks here (like for
        // "emergency mode"), since in those states the SIM won't let
        // us get incoming connections in the first place.

        // TODO: Consider sending out a serialized broadcast Intent here
        // (maybe "ACTION_NEW_INCOMING_CALL"), *before* starting the
        // ringer and going to the in-call UI.  The intent should contain
        // the caller-id info for the current connection, and say whether
        // it would be a "call waiting" call or a regular ringing call.
        // If anybody consumed the broadcast, we'd bail out without
        // ringing or bringing up the in-call UI.
        //
        // This would give 3rd party apps a chance to listen for (and
        // intercept) new ringing connections.  An app could reject the
        // incoming call by consuming the broadcast and doing nothing, or
        // it could "pick up" the call (without any action by the user!)
        // via some future TelephonyManager API.
        //
        // See bug 1312336 for more details.
        // We'd need to protect this with a new "intercept incoming calls"
        // system permission.

        // Obtain a partial wake lock to make sure the CPU doesn't go to
        // sleep before we finish bringing up the InCallScreen.
        // (This will be upgraded soon to a full wake lock; see
        // showIncomingCall().)
        if (VDBG) log("Holding wake lock on new incoming connection.");
        mApplication.requestWakeState(PhoneApp.WakeState.PARTIAL);

        // - don't ring for call waiting connections
        // - do this before showing the incoming call panel
        if (PhoneUtils.isRealIncomingCall(state)) {
            startIncomingCallQuery(c);
        } else {
            if (PhoneUtils.PhoneSettings.vibCallWaiting(mApplication)) {
                mApplication.vibrate(200,300,500);
            }
            if (VDBG) log("- starting call waiting tone...");
            if (mCallWaitingTonePlayer == null) {
                mCallWaitingTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_CALL_WAITING);
                mCallWaitingTonePlayer.start();
            }
            // in this case, just fall through like before, and call
            // showIncomingCall().
            if (DBG) log("- showing incoming call (this is a WAITING call)...");
            showIncomingCall();www.2cto.com
        }

        // Note we *don't* post a status bar notification here, since
        // we're not necessarily ready to actually show the incoming call
        // to the user.  (For calls in the INCOMING state, at least, we
        // still need to run a caller-id query, and we may not even ring
        // at all if the "send directly to voicemail" flag is set.)
        //
        // Instead, we update the notification (and potentially launch the
        // InCallScreen) from the showIncomingCall() method, which runs
        // when the caller-id query completes or times out.

        if (VDBG) log("- onNewRingingConnection() done.");
    }
 2.撥號流程分析

撥號主要是從撥號盤按下call按鍵開始,進入OutgoingCallBroadcaster處理,

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved