Android L 5.0 MT流程 代码

转载请注明出处: http://blog.csdn.net/aaa111/article/details/43866909
  1. --------
  2. 写在前:本人新手有理解不准确或者错误的地方请大家指正出来,我好及时修改
  3. -----
  4. ---我理解的来电流程大概分为6个部分--
  5. 注:1>2>3并不是只步骤,是指经过的第1>2>3个类。
① 1>2>3 RIL>GSMPhone      
    状态变化>发出来电通知
② 4>5>6>7>8>9 PstnIncomingCallNotifier>Call    
    接收到通知>准备创建连接
③ 10>11>12>13CreateConnectionProcesser> ConnectionServices 
    开始创建连接>创建连接完成。
④ 14>11>9>>8 ConnectionServicesAdapter>CallsManager
    处理这个创建的 连接>成功来电
⑤ 8>15>16>17     CallsManager>Phone
    成功来电>准备启动界面
⑥ 18>19>20>21>22 CallList>StatubarNotifier
    开始启动界面 显示来电
----

framwork

①  RIL>GSMPhone    Call状态变化 -> 发出来电通知

  1. 0. Modem发出Call状态变化的通知,


  2. 1. framwork/opt/telephony/.../RIL.java
    1.1.RIL接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息
  1. 1.2.然后经由mCallStateRegistrants.notifyRegistrants发出通知(RegistrantList消息处理机制此处不做具体说明)。
  2.  
              
    1. private void processUnsolicited (Parcel p) {
    2. ...
    3. switch(response) {
    4. ...
    5. case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
    6.                 if (RILJ_LOGD) unsljLog(response);
    7.                 mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
BaseCommands.java registerForCallStateChanged()  mCallStateRegistrants.add(r);
注册为观察者(android源码中大量用到观察者模式,或者叫RegistrantList消息处理机制)。
 
          
  1.  @Override
  2.     public void registerForCallStateChanged(Handler h, int what, Object obj) {
  3.         Registrant r = new Registrant (h, what, obj);
  4. //添加到观察者列表
  5.         mCallStateRegistrants.add(r);
  6.     }

2. framwork/opt/telephony/...GSMCallTracker.java
2.1查找察者被调用的地方(AS中的快捷键Ctrl+Alt+H), 两处被响应处理处理,其中一处:GSMCallTracker handleMessage
 
          
  1. ...//registerForCallStateChanged调用
  2. mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
  3. ...
  4. @Override
  5. public void
  6. //响应处理
  7. handleMessage (Message msg) {
  8. ...
  9. case EVENT_CALL_STATE_CHANGE:
  10. //调用父类CallTracker查询Call List方法
  11.      pollCallsWhenSafe();
  12. break;
2.1.1. pollCallsWhenSafe()方法在CallTracker.java中实现
 
          
  1. protected void pollCallsWhenSafe() {
  2. mNeedsPoll = true;

  3. if (checkNoOperationsPending()) {
  4. mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
  5. mCi.getCurrentCalls(mLastRelevantPoll);//RIL.java中的getCurrentCalls方法
  6. }
  7. }
2.1.2 回到RIL.java   getCurrentCalls  将 RIL_REQUEST_GET_CURRENT_CALLS 消息封装成 RILRequest 类型并发送。
此处 result为 EVENT_POLL_CALLS_RESULT,所以后 GSMCallTracker 中 hand lemessage响应的是这个消息。
 
           
  1. @Override
  2. public void
  3. getCurrentCalls (Message result) {
  4. RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
  5. if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
  6. send(rr);
  7. }
2.2 RIL.java 有三处接收处理 RIL_REQUEST_GET_CURRENT_CALLS 消息,真正的逻辑处理在processSolicited方法
 
           
  1. private RILRequest processSolicited (Parcel p) {
  2. ...
  3. case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;
  4. ...
  5. if (rr.mResult != null) {
  6.                     AsyncResult.forMessage(rr.mResult, null, tr);
  7.                     rr.mResult.sendToTarget();//发出handler消息通知
  8.                 }

2.3 回到framworks/opt/telephony/.../telephony/gsm/GSMCallTracker.java
rr . mResult . sendToTarget ()发出handler消息通知后, handleMessage方法中响应消息“ EVENT_POLL_CALLS_RESULT",这个消息是在  pollCallsWhenSafe中封装的。
 
           
  1. @Override
  2. public void
  3. handleMessage (Message msg) {
  4. ...
  5.  case EVENT_POLL_CALLS_RESULT:
  6.                 ar = (AsyncResult)msg.obj;
  7.                 if (msg == mLastRelevantPoll) {
  8.                     if (DBG_POLL) log(
  9.                             "handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
  10.                     mNeedsPoll = false;
  11.                     mLastRelevantPoll = null;
  12.                     handlePollCalls((AsyncResult)msg.obj);
  13.                 }
  14.             break;
handlePollCalls方法根据RIL发出的Call List对象判断Call的状态,并发出不同的通知,
1) 新来电的通知是: phone. notifyNewRingingConnection
 
          
  1. handlePollCalls(){
  2. ...
  3. if (newRinging != null) {
  4. mPhone.notifyNewRingingConnection(newRinging);
  5. }
另外两个是 
2) 通话断开通知 onDisconnected;
3) Call状态变化通知 phone.notifiyPreciseCallStateChanged.
来电的时候发出的是phone.notifyNewRingConnection通知,进入到notifyNewRingConnection方法

3. framworks/opt/telephony/.../telephony/gsm/GSMPhone.java
 
         
  1.  public void notifyNewRingingConnection(Connection c) {
  2.         super.notifyNewRingingConnectionP(c);
  3.     }
调用父类   PhoneBase.java 
notifyNewRingingConnectionP() 发出来电通知 mNewRingingConnectionRegistrants.notifyRegistrants(ar);
 
          
  1. /**
  2.      * Notify registrants of a new ringing Connection.
  3.      * Subclasses of Phone probably want to replace this with a
  4.      * version scoped to their packages
  5.      */
  6.     public void notifyNewRingingConnectionP(Connection cn) {
  7.         if (!mIsVoiceCapable)
  8.             return;
  9.         AsyncResult ar = new AsyncResult(null, cn, null);
  10.         mNewRingingConnectionRegistrants.notifyRegistrants(ar);
  11.     }
RegistrantList.java
 
           
  1. public /*synchronized*/ void
  2. notifyRegistrants(AsyncResult ar)
  3. {
  4. internalNotifyRegistrants(ar.result, ar.exception);
  5. }
 
            
  1. private synchronized void
  2. internalNotifyRegistrants (Object result, Throwable exception)
  3. {
  4. for (int i = 0, s = registrants.size(); i < s ; i++) {
  5. Registrant r = (Registrant) registrants.get(i);
  6. r.internalNotifyRegistrant(result, exception);
  7. }
  8. }

 
           
  1. /*package*/ void
  2. internalNotifyRegistrant (Object result, Throwable exception)
  3. {
  4. Handler h = getHandler();
  5. if (h == null) {
  6. clear();
  7. } else {
  8. Message msg = Message.obtain();
  9. msg.what = what;
  10. msg.obj = new AsyncResult(userObj, result, exception);
  11. h.sendMessage(msg);
  12. }
  13. }
 
注册为观察者的方法为:
 
           
  1. // Inherited documentation suffices.
  2. @Override
  3. public void registerForNewRingingConnection(
  4. Handler h, int what, Object obj) {
  5. checkCorrectThread(h);

  6. mNewRingingConnectionRegistrants.addUnique(h, what, obj);
  7. }
registerForNewRingingConnection这个方法在4个地方被调用,即有4个地方关心是否有新来电的变化。
     1.packages/servicesTelephony/.../PstnIncomingCallNotifier.java   log:  D/Telephony( 1396): PstnIncomingCallNotifier: handleNewRingingConnection
     2.framworks/opt/telephony/.../PhoneProxy.java 
     3.framworks/opt/telephony/test/.../GSMPhoneTEST.java
     4.framworks/opt/telephony/.../telephony/CallManager.java 5.0之前是这里处理,新版本由PstnIncomingCallNotifier处理

----------------
前面:RIL发出Call状态变化消息通知,GSMPhone发出来电通知
----------------

Telephony

② PstnIncomingCallNotifier>Call  接收Framework层到通知>准备创建连接



4. packages/services/Telephony/.../PstnIncomingCallNotifier.java

registerForNotifications方法调用 registerForNewRingingConnection

4.1 调用 Phonebase中 不同的方法,注册为观察者。
翻译(不通顺 =_=):
我们应当直接跟phoneProxy做交互处理。然而phoneProxy直接与CallManager交互处理, 我们要么监听callmanager,要么就像这样参与到proxy中去。
两种都是不可取的,如果这个类和callmanager能够 register generically with the phone proxy instead ,这会比较好。
或者更好的是只是直接注册通知 with phone proxy, 而不用担心技术的改变,这需要改变opt/telephony中的代码。
 
           
/**
* Register for notifications from the base phone.
* TODO: We should only need to interact with the phoneproxy directly. However,
* since the phoneproxy only interacts directly with CallManager we either listen to callmanager
* or we have to poke into the proxy like this. Neither is desirable. It would be better if
* this class and callManager could register generically with the phone proxy instead and get
* radio techonology changes directly. Or better yet, just register for the notifications
* directly with phone proxy and never worry about the technology changes. This requires a
* change in opt/telephony code.
*/
private void registerForNotifications() {
Phone newPhone = mPhoneProxy.getActivePhone();
if (newPhone != mPhoneBase) {
unregisterForNotifications();
 
if (newPhone != null) {
Log.i(this, "Registering: %s", newPhone);
mPhoneBase = newPhone;
//调用 registerForNewRingingConnection方法
mPhoneBase.registerForNewRingingConnection(
mHandler, EVENT_NEW_RINGING_CONNECTION, null);
mPhoneBase.registerForCallWaiting(
mHandler, EVENT_CDMA_CALL_WAITING, null);
mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
null);
}
}
}
4.2 handle 处理EVENT_NEW_RINGING_CONNECTION消息
 
              
private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) {
          ...
                case EVENT_NEW_RINGING_CONNECTION :
                    handleNewRingingConnection((AsyncResult) msg.obj);
                    break;

4.2.1 handleNewRingingConnection方法,处理新的来电连接。
此处对应的log为:
D/Telephony( 1396): PstnIncomingCallNotifier:  handleNewRingingConnection
 
              
/**
* Verifies the incoming call and triggers sending the incoming-call intent to Telecom.
*
* @param asyncResult The result object from the new ringing event.
*/
private void handleNewRingingConnection(AsyncResult asyncResult) {
Log.d(this, "handleNewRingingConnection");
Connection connection = (Connection) asyncResult.result;
if (connection != null) {
Call call = connection.getCall();
 
// Final verification of the ringing state before sending the intent to Telecom.
//在发送intent到Telecom之前最后一次验证ringing 状态
if (call != null && call.getState().isRinging()) {
sendIncomingCallIntent(connection);
}
}
}
4.2.2 sendIncomingCallIntent方法
发送incoming call intent到telecom,发送的Connection 类型,里面包括isIncoming getState isRinging等
 
               
    /**
* Sends the incoming call intent to telecom.
*/
private void sendIncomingCallIntent(Connection connection) {
Bundle extras = null;
if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
!TextUtils.isEmpty(connection.getAddress())) {
extras = new Bundle();
Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
extras.putParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER, uri);
}
TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(
TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
}
addNewIncomingCall()定义在:  framworks/base/ telecomm /java/android/telecom/ TelecomManager.java   
TelecomManager的功能则主要是对TelecomService提供的远程接口的封装,然后提供给应用使用。
 addNewIncomingCall方法   @SystemApi
来电时触发此方法
 
                
/**
* Registers a new incoming call. A {@link ConnectionService} should invoke this method when it
* has an incoming call. The specified {@link PhoneAccountHandle?_?} must have been registered
* with {@link #registerPhoneAccount}. Once invoked, this method will cause the system to bind
* to the {@link ConnectionService} associated with the {@link PhoneAccountHandle} and request
* additional information about the call (See
* {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming call UI.
*
* @param phoneAccount A {@link PhoneAccountHandle} registered with
* {@link #registerPhoneAccount}.
* @param extras A bundle that will be passed through to
* {@link ConnectionService#onCreateIncomingConnection}.
* @hide
*/
@SystemApi
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
try {
if (isServiceConnected()) {
getTelecomService().addNewIncomingCall(
phoneAccount, extras == null ? new Bundle() : extras);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
}
}
addNewIncomingCall 的具体实现

Telecomm

5. packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java
继承自ITelecomService,TelecomService的接口由TeleComManager封装,并其供给应用使用,
5.1
@Override
addNewIncomingCall
新建intent 设定intent 的ACTION 、addFalgs等
 
          
  1. public static final String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
  2. ...
  3. /**
  4. * @see android.telecom.TelecomManager#addNewIncomingCall
  5. */
  6. @Override
  7. public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
  8. if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
  9. mAppOpsManager.checkPackage(
  10. Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());

  11. Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
  12. intent.setPackage(mContext.getPackageName());
  13. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  14. intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
  15. if (extras != null) {
  16. intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
  17. }

  18. long token = Binder.clearCallingIdentity();
  19. //启动Activity
  20. mContext.startActivityAsUser(intent, UserHandle.CURRENT);
  21. Binder.restoreCallingIdentity(token);
  22. }
  23. }
//启动  CallActivity  对应的log:
I/ActivityManager(  852): START u0 {act=android.telecom.action.INCOMING_CALL flg=0x10000000 pkg=com.android.server.telecom cmp=com.android.server.telecom/.IncomingCallActivity (has extras)
} from uid 1001 on display 0

// packages / services / Telecomm / AndroidManifest.xml

183<activity-alias android:name="IncomingCallActivity"184                android:targetActivity="CallActivity"185                android:exported="true">
186            <intent-filter>
187                <action android:name="android.telecom.action.INCOMING_CALL" />
188                <category android:name="android.intent.category.DEFAULT" />
189            intent-filter>
190        activity-alias>


6. packages/services/Telecomm/src/com/android/server/telecom/ CallActivity.java
6.1 执行完processIntent()后就finish(),对应的log
D/Telecom ( 1376): CallActivity:  onCreate: end
 
           
public class CallActivity extends Activity {
 
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
 
// TODO: Figure out if there is something to restore from bundle.
// See OutgoingCallBroadcaster in services/Telephony for more.
 
processIntent(getIntent());
 
// This activity does not have associated UI, so close.
finish();
Log.d(this, "onCreate: end");
}
6.1.1  processIntent 判断action
 
           
/**
* Processes intents sent to the activity.
*
* @param intent The intent.
*/
private void processIntent(Intent intent) {
// Ensure call intents are not processed on devices that are not capable of calling.
if (!isVoiceCapable()) {
return;
}
 
verifyCallAction(intent);
String action = intent.getAction();
 
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent);
} else if (TelecomManager.ACTION_INCOMING_CALL.equals(action)) {
processIncomingCallIntent(intent);
}
}
6.1.2  processIncomingCallIntent
 
           
private void processIncomingCallIntent(Intent intent) {
if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
               CallReceiver . processIncomingCallIntent ( intent );
} else {
sendBroadcastToReceiver(intent, true /* isIncoming */);
}
}
7. packages/services/Telecomm/src/com/android/server/telecom/CallReceiver.java
7.1 对应log
D/Telecom ( 1376): com.android.server.telecom.CallReceiver: Processing incoming call from connection service [ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}]
 
            
static void processIncomingCallIntent(Intent intent) {
PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
 
if (phoneAccountHandle == null) {
Log.w(TAG, "Rejecting incoming call due to null phone account");
return;
}
if (phoneAccountHandle.getComponentName() == null) {
Log.w(TAG, "Rejecting incoming call due to null component name");
return;
}
 
Bundle clientExtras = null;
if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
}
if (clientExtras == null) {
clientExtras = Bundle.EMPTY;
}
 
Log.d(TAG, "Processing incoming call from connection service [%s]",
phoneAccountHandle.getComponentName());
getCallsManager().processIncomingCallIntent(phoneAccountHandle, clientExtras);
}

8. packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
8.1 processIncomingCallIntent
D/Telecom ( 1376): CallsManager: processIncomingCallIntent
new一个Call 对象 把前面的参数传进来,然后调用call中建立连接的方法 startCreateConnection
    /**
     * 开始把call attach到connection services
     *
     * @param phoneAccountHandle The phone account which contains the component name of the
     *        connection service to use for this call.
     * @param extras The optional extras Bundle passed with the intent used for the incoming call.
     */

 
           
  1. /**
  2. * Starts the process to attach the call to a connection service.
  3. *
  4. * @param phoneAccountHandle The phone account which contains the component name of the
  5. * connection service to use for this call.
  6. * @param extras The optional extras Bundle passed with the intent used for the incoming call.
  7. */
  8. void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
  9. Log.d(this, "processIncomingCallIntent");
  10. Uri handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
  11. Call call = new Call(
  12. mContext,
  13. mConnectionServiceRepository,
  14. handle,
  15. null /* gatewayInfo */,
  16. null /* connectionManagerPhoneAccount */,
  17. phoneAccountHandle,
  18. true /* isIncoming */,
  19. false /* isConference */);
  20. call.setExtras(extras);
  21. // TODO: Move this to be a part of addCall()
  22. call.addListener(this);
  23. call.startCreateConnection(mPhoneAccountRegistrar);
  24. }
④ 14>11>9>>8 ConnectionServicesAdapter>CallsManager
    处理这个创建的连接>成功来电
⑤ 8>15>16>17     CallsManager>Phone
    成功来电>准备启动界面
⑥ 18>19>20>21>22 CallList>StatubarNotifier
    开始启动界面 显示来电
9. packages/services/Telecomm/src/com/android/server/telecom/Call.java
9.1 startCreateConnection()
开始建立连接队列,一旦完成创建,就应当有一个活动active的连接了存在service里。
 
           
  1. /**
  2. * Starts the create connection sequence. Upon completion, there should exist an active
  3. * connection through a connection service (or the call will have failed).
  4. *
  5. * @param phoneAccountRegistrar The phone account registrar.
  6. */
  7. void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
  8. Preconditions.checkState(mCreateConnectionProcessor == null);
  9. mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
  10. phoneAccountRegistrar, mContext);
  11. mCreateConnectionProcessor.process();
  12. }

③CreateConnectionProcesser>ConnectionServices 开始创建连接>创建连接完成。

10. packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java

10.1 process
 
          
  1. void process() {
  2. Log.v(this, "process");
  3. mAttemptRecords = new ArrayList<>();
  4. if (mCall.getTargetPhoneAccount() != null) {
  5. mAttemptRecords.add(new CallAttemptRecord(
  6. mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
  7. }
  8. adjustAttemptsForConnectionManager();
  9. adjustAttemptsForEmergency();
  10. mAttemptRecordIterator = mAttemptRecords.iterator();
  11. attemptNextPhoneAccount();
  12. }
10.2 attemptNextPhoneAccount()
service试图建立连接
 
          
  1. private void attemptNextPhoneAccount() {
  2. ...
  3. if (mResponse != null && attempt != null) {
  4.             Log.i(this, "Trying attempt %s", attempt);
  5.             ConnectionServiceWrapper service =
  6.                     mRepository.getService(
  7.                             attempt.connectionManagerPhoneAccount.getComponentName());
  8.             if (service == null) {
  9.                 Log.i(this, "Found no connection service for attempt %s", attempt);
  10.                 attemptNextPhoneAccount();
  11.             } else {
  12.                 mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
  13.                 mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
  14.                 mCall.setConnectionService(service);
  15.                 Log.i(this, "Attempting to call from %s", service.getComponentName());
  16.                 service.createConnection(mCall, new Response(service));
  17.             }
  18.         } 



11.  packages/services/Telecomm/src/com/android/server/telecom/ ConnectionServiceWrapper.java  
11.1 createConnection() 
BindCallback 是interface
       /**
     * 为播出的电话建立连接,或者attach一个已经存在的来电。
     */
 
          
  1. /**
  2. * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
  3. */
  4. void createConnection(final Call call, final CreateConnectionResponse response) {
  5. Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
  6. BindCallback callback = new BindCallback() {
  7. @Override
  8. public void onSuccess() {
  9. String callId = mCallIdMapper.getCallId(call);
  10. mPendingResponses.put(callId, response);
  11. GatewayInfo gatewayInfo = call.getGatewayInfo();
  12. Bundle extras = call.getExtras();
  13. if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
  14. gatewayInfo.getOriginalAddress() != null) {
  15. extras = (Bundle) extras.clone();
  16. extras.putString(
  17. TelecomManager.GATEWAY_PROVIDER_PACKAGE,
  18. gatewayInfo.getGatewayProviderPackageName());
  19. extras.putParcelable(
  20. TelecomManager.GATEWAY_ORIGINAL_ADDRESS,
  21. gatewayInfo.getOriginalAddress());
  22. }
  23. try {
  24. mServiceInterface.createConnection(
  25. call.getConnectionManagerPhoneAccount(),
  26. callId,
  27. new ConnectionRequest(
  28. call.getTargetPhoneAccount(),
  29. call.getHandle(),
  30. extras,
  31. call.getVideoState()),
  32. call.isIncoming(),
  33. call.isUnknown());
  34. } catch (RemoteException e) {
  35. Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
  36. mPendingResponses.remove(callId).handleCreateConnectionFailure(
  37. new DisconnectCause(DisconnectCause.ERROR, e.toString()));
  38. }
  39. }
  40. @Override
  41. public void onFailure() {
  42. Log.e(this, new Exception(), "Failure to call %s", getComponentName());
  43. response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));
  44. }
  45. };
  46. mBinder.bind(callback);
  47. }
12. packages/services/Telecomm/src/com/android/server/telecom/Servicesbinder.java
12.1  bind 绑定连接
          /**
         * 执行绑定到服务的操作(如果还没有绑定)然后执行指定的回调方法
         *
         * @param callback The 回调方法通知绑定是成功或失败
         */
 
          
  1. /**
  2. * Helper class to perform on-demand binding.
  3. */
  4. final class Binder {
  5. /**
  6. * Performs an bind to the service (only if not already bound) and executes the
  7. * specified callback.
  8. *
  9. * @param callback The callback to notify of the binding's success or failure.
  10. */
  11. void bind(BindCallback callback) {
  12. ThreadUtil.checkOnMainThread();
  13. Log.d(ServiceBinder.this, "bind()");

  14. // Reset any abort request if we're asked to bind again.
  15. clearAbort();

  16. if (!mCallbacks.isEmpty()) {
  17. // Binding already in progress, append to the list of callbacks and bail out.
  18. mCallbacks.add(callback);
  19. return;
  20. }

  21. mCallbacks.add(callback);
  22. if (mServiceConnection == null) {
  23. Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
  24. ServiceConnection connection = new ServiceBinderConnection();

  25. Log.d(ServiceBinder.this, "Binding to service with intent: %s", serviceIntent);
  26. if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
  27. handleFailedConnection();
  28. return;
  29. }
  30. } else {
  31. Log.d(ServiceBinder.this, "Service is already bound.");
  32. Preconditions.checkNotNull(mBinder);
  33. handleSuccessfulConnection();
  34. }
  35. }
  36. }
  37. //
上面的执行完之后,顺序执行到 onServiceConnected
12.2 onServiceConnected
 
           
  1. private final class ServiceBinderConnection implements ServiceConnection {
  2. @Override
  3. public void onServiceConnected(ComponentName componentName, IBinder binder) {
  4. ThreadUtil.checkOnMainThread();
  5. Log.i(this, "Service bound %s", componentName);//这句log被打印出来了
  6. // Unbind request was queued so unbind immediately.
  7. if (mIsBindingAborted) {
  8. clearAbort();
  9. logServiceDisconnected("onServiceConnected");
  10. mContext.unbindService(this);
  11. handleFailedConnection();
  12. return;
  13. }
  14. mServiceConnection = this;
  15. setBinder(binder);
  16. handleSuccessfulConnection();
  17. }
handleSuccessfulConnection
 
           
  1. private void handleSuccessfulConnection() {
  2. for (BindCallback callback : mCallbacks) {
  3. callback.onSuccess();
  4. }
  5. mCallbacks.clear();
  6. }

回调上面的onSuccess() 执行 mServiceInterface . createConnection  createConnection的具体实现在
13. framworks/base/telecomm/java/android/telecom/ConnectionServices.java

 
           
  1. @Override
  2. public void createConnection(
  3. PhoneAccountHandle connectionManagerPhoneAccount,
  4. String id,
  5. ConnectionRequest request,
  6. boolean isIncoming,
  7. boolean isUnknown) {
  8. //chengzhi
  9. SomeArgs args = SomeArgs.obtain();
  10. args.arg1 = connectionManagerPhoneAccount;
  11. args.arg2 = id;
  12. args.arg3 = request;
  13. args.argi1 = isIncoming ? 1 : 0;
  14. args.argi2 = isUnknown ? 1 : 0;
  15. mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
  16. }
13.1 handleMessage() MSG_CREATE_CONNECTION
 
           
  1. case MSG_CREATE_CONNECTION: {
  2. SomeArgs args = (SomeArgs) msg.obj;
  3. try {
  4. //chengzhi
  5. final PhoneAccountHandle connectionManagerPhoneAccount =
  6. (PhoneAccountHandle) args.arg1;
  7. final String id = (String) args.arg2;
  8. final ConnectionRequest request = (ConnectionRequest) args.arg3;
  9. final boolean isIncoming = args.argi1 == 1;
  10. final boolean isUnknown = args.argi2 == 1;
  11. if (!mAreAccountsInitialized) {
  12. Log.d(this, "Enqueueing pre-init request %s", id);
  13. mPreInitializationConnectionRequests.add(new Runnable() {
  14. @Override
  15. public void run() {
  16. createConnection(
  17. connectionManagerPhoneAccount,
  18. id,
  19. request,
  20. isIncoming,
  21. isUnknown);
  22. }
  23. });
  24. } else {
  25. //chengzhi debug
  26. createConnection(
  27. connectionManagerPhoneAccount,
  28. id,
  29. request,
  30. isIncoming,
  31. isUnknown);
  32. }
  33. } finally {
  34. args.recycle();
  35. }
  36. break;
  37. }
13.1.1 createConnection方法
创建 Connection connection
    /**
     * 这个方法可以被telecom用来创建呼出电话或者一个已存在的来电。任何一种情况,telecom都会循环经过一系列的服务和 调用 createConnection util a connection service取消或者成功完成创建。
     */
 
           
  1. /**
  2. * This can be used by telecom to either create a new outgoing call or attach to an existing
  3. * incoming call. In either case, telecom will cycle through a set of services and call
  4. * createConnection util a connection service cancels the process or completes it successfully.
  5. */
  6. private void createConnection(
  7. final PhoneAccountHandle callManagerAccount,
  8. final String callId,
  9. final ConnectionRequest request,
  10. boolean isIncoming,
  11. boolean isUnknown) {
  12. Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
  13. "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request, isIncoming,
  14. isUnknown);
  15. //chengzhi 01
  16. Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
  17. : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
  18. : onCreateOutgoingConnection(callManagerAccount, request);
  19. .....
  20.         mAdapter.handleCreateConnectionComplete
前面建立连接成功了,后面处理成功的连接
后面执行 mAdapter.handleCreateConnectionComplete

④ 14>11>9>>8 ConnectionServicesAdapter>CallsManager  处理这个创建的连接>成功来电

14.framework/base/telecomm/java/android/telecom/ConnectionServicesAdapter.java
 
           
  1. void handleCreateConnectionComplete(
  2. String id,
  3. ConnectionRequest request,
  4. ParcelableConnection connection) {
  5. for (IConnectionServiceAdapter adapter : mAdapters) {
  6. try {
  7. //chengzhi 03
  8. adapter.handleCreateConnectionComplete(id, request, connection);
  9. } catch (RemoteException e) {
  10. }
  11. }
  12. }

⑤  CallsManager>Phone    成功来电>准备启动界面

15. //packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java   handleCreateConnectionComplete
 
             
  1. private final class Adapter extends IConnectionServiceAdapter.Stub {
  2. @Override
  3. public void handleCreateConnectionComplete(
  4. String callId,
  5. ConnectionRequest request,
  6. ParcelableConnection connection) {
  7. logIncoming("handleCreateConnectionComplete %s", request);
  8. if (mCallIdMapper.isValidCallId(callId)) {
  9. SomeArgs args = SomeArgs.obtain();
  10. args.arg1 = callId;
  11. args.arg2 = request;
  12. args.arg3 = connection;
  13. mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args)
  14. .sendToTarget();
  15. }
  16. }
15.2 handleMessage处理消息  MSG_HANDLE_CREATE_CONNECTION_COMPLETE
 
              
  1. private final Handler mHandler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. Call call;
  5. switch (msg.what) {
  6. case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
  7. SomeArgs args = (SomeArgs) msg.obj;
  8. try {
  9. String callId = (String) args.arg1;
  10. ConnectionRequest request = (ConnectionRequest) args.arg2;
  11. ParcelableConnection connection = (ParcelableConnection) args.arg3;
  12. handleCreateConnectionComplete(callId, request, connection);
  13. } finally {
  14. args.recycle();
  15. }
  16. break;
  17. }
15.2.1 handleCreateConnectionComplete ()
如果成功连接
 
              
  1. private void handleCreateConnectionComplete(
  2. String callId,
  3. ConnectionRequest request,
  4. ParcelableConnection connection) {
  5. // TODO: Note we are not using parameter "request", which is a side effect of our tacit
  6. // assumption that we have at most one outgoing connection attempt per ConnectionService.
  7. // This may not continue to be the case.
  8. if (connection.getState() == Connection.STATE_DISCONNECTED) {
  9. // A connection that begins in the DISCONNECTED state is an indication of
  10. // failure to connect; we handle all failures uniformly
  11. removeCall(callId, connection.getDisconnectCause());
  12. } else {
  13. // Successful connection
  14. if (mPendingResponses.containsKey(callId)) {
  15. mPendingResponses.remove(callId)
  16. .handleCreateConnectionSuccess(mCallIdMapper, connection);
  17. }
  18. }
  19. }
重写  handleCreateConnectionSuccess方法
16. //packages/services/Telecomm/src/com/android/server/telecom/ Call.java 
16.1 handleCreateConnetionSucess()
 
               
@Override
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
mCreateConnectionProcessor = null;
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
setCallCapabilities(connection.getCapabilities());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
 
mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
mConferenceableCalls.add(idMapper.getCall(id));
}
 
if (mIsUnknown) {
for (Listener l : mListeners) {
l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection.getState()));
}
} else if (mIsIncoming) {
// We do not handle incoming calls immediately when they are verified by the connection
// service. We allow the caller-info-query code to execute first so that we can read the
// direct-to-voicemail property before deciding if we want to show the incoming call to
// the user or if we want to reject the call.
mDirectToVoicemailQueryPending = true;
 
// Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
// showing the user the incoming call screen.
mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis(
mContext.getContentResolver()));
} else {
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
getStateFromConnectionState(connection.getState()));
}
}
}

16.2 Runnable mDirectToVoicemailRunnable
 
              
  1. private final Runnable mDirectToVoicemailRunnable = new Runnable() {
  2. @Override
  3. public void run() {
  4. processDirectToVoicemail();
  5. }
16.2.1 processDirectToVoicemail
 
               
  1. final class Call implements CreateConnectionResponse {
  2. /**
  3. * Listener for events on the call.
  4. */
  5. interface Listener {
  6. void onSuccessfulIncomingCall(Call call);
  7. ...
  8. private void processDirectToVoicemail() {
  9. if (mDirectToVoicemailQueryPending) {
  10. if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
  11. Log.i(this, "Directing call to voicemail: %s.", this);
  12. // TODO: Once we move State handling from CallsManager to Call, we
  13. // will not need to set STATE_RINGING state prior to calling reject.
  14. setState(CallState.RINGING);
  15. reject(false, null);
  16. } else {
  17. // TODO: Make this class (not CallsManager) responsible for changing
  18. // the call state to STATE_RINGING.
  19. // TODO: Replace this with state transition to STATE_RINGING.
  20. for (Listener l : mListeners) {
  21. l.onSuccessfulIncomingCall(this);
  22. }
  23. }
  24. mDirectToVoicemailQueryPending = false;
  25. }
  26. }

17. //package/services/Telecomm/src/com/android/server/telecom/CallsManager.java  
17.1
@Override onSuccessfulIncomingCall
if 判断后 addCall()
 
              
  1. public final class CallsManager extends Call.ListenerBase {
  2. ...
  3. @Override
  4. public void onSuccessfulIncomingCall(Call incomingCall) {
  5. Log.d(this, "onSuccessfulIncomingCall");
  6. setCallState(incomingCall, CallState.RINGING);
  7. if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
  8. incomingCall.reject(false, null);
  9. // since the call was not added to the list of calls, we have to call the missed
  10. // call notifier and the call logger manually.
  11. mMissedCallNotifier.showMissedCallNotification(incomingCall);
  12. mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
  13. } else {
  14. incomingCall.mIsActiveSub = true;
  15. addCall(incomingCall);
  16. setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
  17. }
  18. }
17.1.1 addCall()
 
              
  1. /**
  2. * Adds the specified call to the main list of live calls.
  3. *
  4. * @param call The call to add.
  5. */
  6. private void addCall(Call call) {
  7. Log.v(this, "addCall(%s)", call);

  8. call.addListener(this);
  9. mCalls.add(call);

  10. // TODO: Update mForegroundCall prior to invoking
  11. // onCallAdded for calls which immediately take the foreground (like the first call).
  12. for (CallsManagerListener listener : mListeners) {
  13. listener.onCallAdded(call);
  14. }
  15. updateForegroundCall();
  16. }


InCallUI

⑥ CallList>StatubarNotifier    开始启动界面 显示来电

18. //package/services/Telecomm/src/com/android/server/telecom/ InCallController.java  
18.1 重写onCallAdded
@Override onCallAdded()
 
               
  1. @Override
  2. public void onCallAdded(Call call) {
  3. if (mInCallServices.isEmpty()) {
  4. bind();//执行这里
  5. } else {
  6. Log.i(this, "onCallAdded: %s", call);//输出log
  7. // Track the call if we don't already know about it.
  8. addCall(call);
  9. for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
  10. ComponentName componentName = entry.getKey();
  11. IInCallService inCallService = entry.getValue();
  12. ParcelableCall parcelableCall = toParcelableCall(call,
  13. componentName.equals(mInCallComponentName) /* includeVideoProvider */);
  14. try {
  15. inCallService.addCall(parcelableCall);
  16. } catch (RemoteException ignored) {
  17. }
  18. }
  19. }
  20. }
18.1.1 bind()
InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
 
             
  1. /**
  2. * Binds to the in-call app if not already connected by binding directly to the saved
  3. * component name of the {@link IInCallService} implementation.
  4. */
  5. private void bind() {
  6. ThreadUtil.checkOnMainThread();
  7. if (mInCallServices.isEmpty()) {
  8. PackageManager packageManager = mContext.getPackageManager();
  9. Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);

  10. for (ResolveInfo entry : packageManager.queryIntentServices(serviceIntent, 0)) {
  11. ServiceInfo serviceInfo = entry.serviceInfo;
  12. if (serviceInfo != null) {
  13. boolean hasServiceBindPermission = serviceInfo.permission != null &&
  14. serviceInfo.permission.equals(
  15. Manifest.permission.BIND_INCALL_SERVICE);
  16. boolean hasControlInCallPermission = packageManager.checkPermission(
  17. Manifest.permission.CONTROL_INCALL_EXPERIENCE,
  18. serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED;

  19. if (!hasServiceBindPermission) {
  20. Log.w(this, "InCallService does not have BIND_INCALL_SERVICE permission: " +
  21. serviceInfo.packageName);
  22. continue;
  23. }

  24. if (!hasControlInCallPermission) {
  25. Log.w(this,
  26. "InCall UI does not have CONTROL_INCALL_EXPERIENCE permission: " +
  27. serviceInfo.packageName);
  28. continue;
  29. }

  30. InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
  31. ComponentName componentName = new ComponentName(serviceInfo.packageName,
  32. serviceInfo.name);

  33. Log.i(this, "Attempting to bind to InCall %s, is dupe? %b ", //log输出
  34. serviceInfo.packageName,
  35. mServiceConnections.containsKey(componentName));

  36. if (!mServiceConnections.containsKey(componentName)) {
  37. Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
  38. intent.setComponent(componentName);

  39. if (mContext.bindServiceAsUser(intent, inCallServiceConnection,
  40. Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
  41. mServiceConnections.put(componentName, inCallServiceConnection);
  42. }
  43. }
  44. }
  45. }
  46. }
  47. }
18.1.2 InCallServiceConnection inCallServiceConnection = new InCallServiceConnection ();
InCallServiceConnection
 
             
  1. /**
  2. * Used to bind to the in-call app and triggers the start of communication between
  3. * this class and in-call app.
  4. */
  5. private class InCallServiceConnection implements ServiceConnection {
  6. /** {@inheritDoc} */
  7. @Override public void onServiceConnected(ComponentName name, IBinder service) {
  8. Log.d(this, "onServiceConnected: %s", name);
  9. onConnected(name, service);
  10. }
  11. /** {@inheritDoc} */
  12. @Override public void onServiceDisconnected(ComponentName name) {
  13. Log.d(this, "onDisconnected: %s", name);
  14. onDisconnected(name);
  15. }
  16. }
18.1.3 onConnected
 
              
  1. /**
  2. * Persists the {@link IInCallService} instance and starts the communication between
  3. * this class and in-call app by sending the first update to in-call app. This method is
  4. * called after a successful binding connection is established.
  5. *
  6. * @param componentName The service {@link ComponentName}.
  7. * @param service The {@link IInCallService} implementation.
  8. */
  9. private void onConnected(ComponentName componentName, IBinder service) {
  10. ThreadUtil.checkOnMainThread();

  11. Log.i(this, "onConnected to %s", componentName);

  12. IInCallService inCallService = IInCallService.Stub.asInterface(service);

  13. try {
  14. inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(),
  15. mCallIdMapper));
  16. mInCallServices.put(componentName, inCallService);
  17. } catch (RemoteException e) {
  18. Log.e(this, e, "Failed to set the in-call adapter.");
  19. return;
  20. }

  21. // Upon successful connection, send the state of the world to the service.
  22. ImmutableCollection<Call> calls = CallsManager.getInstance().getCalls();
  23. if (!calls.isEmpty()) {
  24. Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(),
  25. componentName);
  26. for (Call call : calls) {
  27. try {
  28. // Track the call if we don't already know about it.
  29. Log.i(this, "addCall after binding: %s", call);
  30. addCall(call);

  31. inCallService.addCall(toParcelableCall(call,
  32. componentName.equals(mInCallComponentName) /* includeVideoProvider */));
  33. } catch (RemoteException ignored) {
  34. }
  35. }
  36. onAudioStateChanged(null, CallsManager.getInstance().getAudioState());
  37. } else {
  38. unbind();
  39. }
  40. }
addCall(call)

19. //framworks/base/telecomm/java/android/telecom/InCallService.java 
@Override 
addCall()
 
              
  1. /** Manages the binder calls so that the implementor does not need to deal with it. */
  2. private final class InCallServiceBinder extends IInCallService.Stub {
  3. @Override
  4. public void setInCallAdapter(IInCallAdapter inCallAdapter) {
  5. mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
  6. }
  7. @Override
  8. public void addCall(ParcelableCall call) {
  9. mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
  10. }
19.1 handleMessage 处理消息 MSG_ADD_CALL
 
              
  1. /** Default Handler used to consolidate binder method calls onto a single thread. */
  2. private final Handler mHandler = new Handler(Looper.getMainLooper()) {
  3. @Override
  4. public void handleMessage(Message msg) {
  5. if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
  6. return;
  7. }

  8. switch (msg.what) {
  9. case MSG_SET_IN_CALL_ADAPTER:
  10. mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
  11. onPhoneCreated(mPhone);
  12. break;
  13. case MSG_ADD_CALL:
  14. mPhone.internalAddCall((ParcelableCall) msg.obj);
  15. break;

21. //framworks/base/telecomm/java/android/telecom/Phone.java
internalAddCall()
 
              
  1. final void internalAddCall(ParcelableCall parcelableCall) {
  2. Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
  3. parcelableCall.mIsActiveSub);
  4. mCallByTelecomCallId.put(parcelableCall.getId(), call);
  5. mCalls.add(call);
  6. checkCallTree(parcelableCall);
  7. call.internalUpdate(parcelableCall, mCallByTelecomCallId);
  8. fireCallAdded(call);
  9. }
20.1.1 fireCallAdded()
 
              
  1. private void fireCallAdded(Call call) {
  2. for (Listener listener : mListeners) {
  3. listener.onCallAdded(this, call);
  4. }
  5. }

onCallAdded()  @SystemApi系统Api  其他使用的地方会 @Override
 
               
  1. @SystemApipublic final class Phone { public abstract static class Listener {
  2.     ...
  3.     public void onCallAdded(Phone phone, Call call) { }
接22_2.
22_1. //pacakge/apps/InCallUI/src/com/android/incallui/ CallList.java  
@Override 
onCallAdded
 
               
  1. /**
  2. * Static singleton accessor method.
  3. */
  4. public static CallList getInstance() {
  5. return sInstance;
  6. }

  7. private Phone.Listener mPhoneListener = new Phone.Listener() {
  8. @Override
  9. public void onCallAdded(Phone phone, android.telecom.Call telecommCall) {
  10. Call call = new Call(telecommCall);
  11. if (call.getState() == Call.State.INCOMING) {
  12. onIncoming(call, call.getCannedSmsResponses());
  13. } else {
  14. onUpdate(call);
  15. }
  16. }
执行了下面的方法,但再往后的步骤不是从这里走的。
onIncoming()
 
                
  1. /**
  2. * Called when a single call has changed.
  3. */
  4. public void onIncoming(Call call, List<String> textMessages) {
  5. Log.d(this, "onIncoming - " + call);
  6. // Update active subscription from call object. it will be set by
  7. // Telecomm service for incoming call and whenever active sub changes.
  8. if (call.mIsActiveSub) {
  9. long sub = call.getSubId();
  10. Log.d(this, "onIncoming - sub:" + sub + " mSubId:" + mSubId);
  11. if (sub != mSubId) {
  12. setActiveSubscription(sub);
  13. }
  14. }
  15. if (updateCallInMap(call)) {
  16. Log.i(this, "onIncoming - " + call);
  17. }
  18. updateCallTextMap(call, textMessages);
  19. for (Listener listener : mListeners) {
  20. listener.onIncomingCall(call);
  21. }
  22. }
22_2. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java  
@Override 
onCallAdded
 
                
  1. public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
  2. ...
  3. private final Phone.Listener mPhoneListener = new Phone.Listener() {
  4. ...
  5.  
  6.         @Override
  7. public void onCallAdded(Phone phone, android.telecom.Call call) {
  8. call.addListener(mCallListener);
  9. }

23. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java  @override onCallAdded

onIncomingCall
 
                
  1. /**
  2. * Called when there is a new incoming call.
  3. *
  4. * @param call
  5. */
  6. @Override
  7. public void onIncomingCall(Call call) {
  8. InCallState newState = startOrFinishUi(InCallState.INCOMING);
  9. InCallState oldState = mInCallState;
  10. Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
  11. mInCallState = newState;
  12. for (IncomingCallListener listener : mIncomingCallListeners) {
  13. listener.onIncomingCall(oldState, mInCallState, call);
  14. }
  15. if (CallList.getInstance().isDsdaEnabled() && (mInCallActivity != null)) {
  16. mInCallActivity.updateDsdaTab();
  17. }
  18. }
startOrFinishUi() 开始或结束UI
 
                
  1. /**
  2. * When the state of in-call changes, this is the first method to get called. It determines if
  3. * the UI needs to be started or finished depending on the new state and does it.
  4. */
  5. private InCallState startOrFinishUi(InCallState newState) {
  6. Log.d(this, "startOrFinishUi: " + mInCallState + " -> " + newState);

  7. // TODO: Consider a proper state machine implementation

  8. // If the state isn't changing or if we're transitioning from pending outgoing to actual
  9. // outgoing, we have already done any starting/stopping of activities in a previous pass
  10. // ...so lets cut out early
  11. boolean alreadyOutgoing = mInCallState == InCallState.PENDING_OUTGOING &&
  12. newState == InCallState.OUTGOING;
  13. boolean isAnyOtherSubActive = InCallState.INCOMING == newState &&
  14. mCallList.isAnyOtherSubActive(mCallList.getActiveSubscription());
  15. if ((newState == mInCallState && !(mInCallActivity == null && isAnyOtherSubActive))
  16. || alreadyOutgoing) {
  17. return newState;
  18. }

  19. // A new Incoming call means that the user needs to be notified of the the call (since
  20. // it wasn't them who initiated it). We do this through full screen notifications and
  21. // happens indirectly through {@link StatusBarNotifier}.
  22. //
  23. // The process for incoming calls is as follows:
  24. //
  25. // 1) CallList - Announces existence of new INCOMING call
  26. // 2) InCallPresenter - Gets announcement and calculates that the new InCallState
  27. // - should be set to INCOMING.
  28. // 3) InCallPresenter - This method is called to see if we need to start or finish
  29. // the app given the new state.
  30. // 4) StatusBarNotifier - Listens to InCallState changes. InCallPresenter calls
  31. // StatusBarNotifier explicitly to issue a FullScreen Notification
  32. // that will either start the InCallActivity or show the user a
  33. // top-level notification dialog if the user is in an immersive app.
  34. // That notification can also start the InCallActivity.
  35. // 5) InCallActivity - Main activity starts up and at the end of its onCreate will
  36. // call InCallPresenter::setActivity() to let the presenter
  37. // know that start-up is complete.
  38. //
  39. // [ AND NOW YOU'RE IN THE CALL. voila! ]
  40. //
  41. // Our app is started using a fullScreen notification. We need to do this whenever
  42. // we get an incoming call.
  43. final boolean startStartupSequence = (InCallState.INCOMING == newState);

  44. // A dialog to show on top of the InCallUI to select a PhoneAccount
  45. final boolean showAccountPicker = (InCallState.WAITING_FOR_ACCOUNT == newState);

  46. // A new outgoing call indicates that the user just now dialed a number and when that
  47. // happens we need to display the screen immediately or show an account picker dialog if
  48. // no default is set. However, if the main InCallUI is already visible, we do not want to
  49. // re-initiate the start-up animation, so we do not need to do anything here.
  50. //
  51. // It is also possible to go into an intermediate state where the call has been initiated
  52. // but Telecomm has not yet returned with the details of the call (handle, gateway, etc.).
  53. // This pending outgoing state can also launch the call screen.
  54. //
  55. // This is different from the incoming call sequence because we do not need to shock the
  56. // user with a top-level notification. Just show the call UI normally.
  57. final boolean mainUiNotVisible = !isShowingInCallUi() || !getCallCardFragmentVisible();
  58. final boolean showCallUi = ((InCallState.PENDING_OUTGOING == newState ||
  59. InCallState.OUTGOING == newState) && mainUiNotVisible);

  60. // TODO: Can we be suddenly in a call without it having been in the outgoing or incoming
  61. // state? I havent seen that but if it can happen, the code below should be enabled.
  62. // showCallUi |= (InCallState.INCALL && !isActivityStarted());

  63. // The only time that we have an instance of mInCallActivity and it isn't started is
  64. // when it is being destroyed. In that case, lets avoid bringing up another instance of
  65. // the activity. When it is finally destroyed, we double check if we should bring it back
  66. // up so we aren't going to lose anything by avoiding a second startup here.
  67. boolean activityIsFinishing = mInCallActivity != null && !isActivityStarted();
  68. if (activityIsFinishing) {
  69. Log.i(this, "Undo the state change: " + newState + " -> " + mInCallState);
  70. return mInCallState;
  71. }

  72. if (showCallUi || showAccountPicker) {
  73. Log.i(this, "Start in call UI");
  74. showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
  75. } 
  76.         
  77.         //如果是来电的话
  78.         else if (startStartupSequence) {
  79. Log.i(this, "Start Full Screen in call UI");

  80. // We're about the bring up the in-call UI for an incoming call. If we still have
  81. // dialogs up, we need to clear them out before showing incoming screen.
  82. if (isActivityStarted()) {
  83. mInCallActivity.dismissPendingDialogs();
  84. }
  85. if (!startUi(newState)) {
  86. // startUI refused to start the UI. This indicates that it needed to restart the
  87. // activity. When it finally restarts, it will call us back, so we do not actually
  88. // change the state yet (we return mInCallState instead of newState).
  89. return mInCallState;
  90. }
  91. } else if (newState == InCallState.NO_CALLS) {
  92. // The new state is the no calls state. Tear everything down.
  93. attemptFinishActivity();
  94. attemptCleanup();
  95. }

  96. return newState;
  97. }
startUi 创建UI
 
                
  1. private boolean startUi(InCallState inCallState) {
  2. final Call incomingCall = mCallList.getIncomingCall();
  3. boolean isCallWaiting = mCallList.getActiveCall() != null &&
  4. mCallList.getIncomingCall() != null;
  5. // If the screen is off, we need to make sure it gets turned on for incoming calls.
  6. // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
  7. // when the activity is first created. Therefore, to ensure the screen is turned on
  8. // for the call waiting case, we finish() the current activity and start a new one.
  9. // There should be no jank from this since the screen is already off and will remain so
  10. // until our new activity is up.
  11. // In addition to call waiting scenario, we need to force finish() in case of DSDA when
  12. // we get an incoming call on one sub and there is a live call in other sub and screen
  13. // is off.
  14. boolean anyOtherSubActive = (incomingCall != null &&
  15. mCallList.isAnyOtherSubActive(mCallList.getActiveSubscription()));
  16. Log.i(this, "Start UI " + " anyOtherSubActive:" + anyOtherSubActive);
  17. if (isCallWaiting || anyOtherSubActive) {
  18. if (mProximitySensor.isScreenReallyOff() && isActivityStarted()) {
  19. mInCallActivity.finish();
  20. // When the activity actually finishes, we will start it again if there are
  21. // any active calls, so we do not need to start it explicitly here. Note, we
  22. // actually get called back on this function to restart it.
  23. // We return false to indicate that we did not actually start the UI.
  24. return false;
  25. } else {
  26. showInCall(false, false);
  27. }
  28. } else {
  29. mStatusBarNotifier.updateNotification(inCallState, mCallList);
  30. }
  31. return true;
  32. }
23. //pakages/apps/InCallUI/src/com/android/incallui/StatuBarNotifier.java       updateNotification()
 
                
  1. /**
  2. * Updates the phone app's status bar notification *and* launches the
  3. * incoming call UI in response to a new incoming call.
  4. *
  5. * If an incoming call is ringing (or call-waiting), the notification
  6. * will also include a "fullScreenIntent" that will cause the
  7. * InCallScreen to be launched, unless the current foreground activity
  8. * is marked as "immersive".
  9. *
  10. * (This is the mechanism that actually brings up the incoming call UI
  11. * when we receive a "new ringing connection" event from the telephony
  12. * layer.)
  13. *
  14. * Also note that this method is safe to call even if the phone isn't
  15. * actually ringing (or, more likely, if an incoming call *was*
  16. * ringing briefly but then disconnected). In that case, we'll simply
  17. * update or cancel the in-call notification based on the current
  18. * phone state.
  19. *
  20. * @see #updateInCallNotification(InCallState,CallList)
  21. */
  22. public void updateNotification(InCallState state, CallList callList) {
  23. updateInCallNotification(state, callList);
  24. }



updateInCallNotification()
 
                
  1. /**
  2. * Helper method for updateInCallNotification() and
  3. * updateNotification(): Update the phone app's
  4. * status bar notification based on the current telephony state, or
  5. * cancels the notification if the phone is totally idle.
  6. */
  7. private void updateInCallNotification(final InCallState state, CallList callList) {
  8. Log.d(this, "updateInCallNotification...");
  9. Call call = getCallToShow(callList);
  10. // Whether we have an outgoing call but the incall UI has yet to show up.
  11. // Since we don't normally show a notification while the incall screen is
  12. // in the foreground, if we show the outgoing notification before the activity
  13. // comes up the user will see it flash on and off on an outgoing call. We therefore
  14. // do not show the notification for outgoing calls before the activity has started.
  15. boolean isOutgoingWithoutIncallUi =
  16. state == InCallState.OUTGOING &&
  17. !InCallPresenter.getInstance().isActivityPreviouslyStarted();
  18. // Whether to show a notification immediately.
  19. boolean showNotificationNow =
  20. // We can still be in the INCALL state when a call is disconnected (in order to show
  21. // the "Call ended" screen. So check that we have an active connection too.
  22. (call != null) &&
  23. // We show a notification iff there is an active call.
  24. state.isConnectingOrConnected() &&
  25. // If the UI is already showing, then for most cases we do not want to show
  26. // a notification since that would be redundant, unless it is an incoming call,
  27. // in which case the notification is actually an important alert.
  28. (!InCallPresenter.getInstance().isShowingInCallUi() || state.isIncoming()) &&
  29. // If we have an outgoing call with no UI but the timer has fired, we show
  30. // a notification anyway.
  31. (!isOutgoingWithoutIncallUi ||
  32. mNotificationTimer.getState() == NotificationTimer.State.FIRED);
  33. if (showNotificationNow) {
  34. showNotification(call);
  35. } else {
  36. cancelInCall();
  37. if (isOutgoingWithoutIncallUi &&
  38. mNotificationTimer.getState() == NotificationTimer.State.CLEAR) {
  39. mNotificationTimer.schedule();
  40. }
  41. }
  42. // If we see a UI, or we are done with calls for now, reset to ground state.
  43. if (InCallPresenter.getInstance().isShowingInCallUi() || call == null) {
  44. mNotificationTimer.clear();
  45. }
  46. }
 
                 
  1. private void showNotification(final Call call) {
  2. final boolean isIncoming = (call.getState() == Call.State.INCOMING ||
  3. call.getState() == Call.State.CALL_WAITING);

  4. // we make a call to the contact info cache to query for supplemental data to what the
  5. // call provides. This includes the contact name and photo.
  6. // This callback will always get called immediately and synchronously with whatever data
  7. // it has available, and may make a subsequent call later (same thread) if it had to
  8. // call into the contacts provider for more data.
  9. mContactInfoCache.findInfo(call, isIncoming, new ContactInfoCacheCallback() {
  10. @Override
  11. public void onContactInfoComplete(String callId, ContactCacheEntry entry) {
  12. Call call = CallList.getInstance().getCallById(callId);
  13. if (call != null) {
  14. buildAndSendNotification(call, entry);
  15. }
  16. }

  17. @Override
  18. public void onImageLoadComplete(String callId, ContactCacheEntry entry) {
  19. Call call = CallList.getInstance().getCallById(callId);
  20. if (call != null) {
  21. buildAndSendNotification(call, entry);
  22. }
  23. }
  24. });
  25. }
构建heads-ip notification通知
 
                 
  1. /**
  2. * Sets up the main Ui for the notification
  3. */
  4. private void buildAndSendNotification(Call originalCall, ContactCacheEntry contactInfo) {
  5. // This can get called to update an existing notification after contact information has come
  6. // back. However, it can happen much later. Before we continue, we need to make sure that
  7. // the call being passed in is still the one we want to show in the notification.
  8. final Call call = getCallToShow(CallList.getInstance());
  9. if (call == null || !call.getId().equals(originalCall.getId())) {
  10. return;
  11. }
  12. final int state = call.getState();
  13. final boolean isConference = call.isConferenceCall();
  14. final boolean isVideoUpgradeRequest = call.getSessionModificationState()
  15. == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
  16. // Check if data has changed; if nothing is different, don't issue another notification.
  17. final int iconResId = getIconToDisplay(call);
  18. final Bitmap largeIcon = getLargeIconToDisplay(contactInfo, isConference);
  19. final int contentResId = getContentString(call);
  20. final String contentTitle = getContentTitle(contactInfo, isConference);
  21. if (!checkForChangeAndSaveData(iconResId, contentResId, largeIcon, contentTitle, state)) {
  22. return;
  23. }
  24. /*
  25. * Nothing more to check...build and send it.
  26. */
  27. final Notification.Builder builder = getNotificationBuilder();
  28. // Set up the main intent to send the user to the in-call screen
  29. final PendingIntent inCallPendingIntent = createLaunchPendingIntent();
  30. builder.setContentIntent(inCallPendingIntent);
  31. // Set the intent as a full screen intent as well if a call is incoming
  32. if ((state == Call.State.INCOMING || state == Call.State.CALL_WAITING) &&
  33. !InCallPresenter.getInstance().isShowingInCallUi()) {
  34. configureFullScreenIntent(builder, inCallPendingIntent, call);
  35. }
  36. // Set the content
  37. builder.setContentText(mContext.getString(contentResId));
  38. builder.setSmallIcon(iconResId);
  39. builder.setContentTitle(contentTitle);
  40. builder.setLargeIcon(largeIcon);
  41. builder.setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
  42. if (isVideoUpgradeRequest) {
  43. builder.setUsesChronometer(false);
  44. addDismissUpgradeRequestAction(builder);
  45. addAcceptUpgradeRequestAction(builder);
  46. } else {
  47. createIncomingCallNotification(call, state, builder);
  48. }
  49. addPersonReference(builder, contactInfo, call);
  50. /*
  51. * Fire off the notification // 发射通知!!
  52. */
  53. Notification notification = builder.build();
  54. Log.d(this, "Notifying IN_CALL_NOTIFICATION: " + notification);
  55. mNotificationManager.notify(IN_CALL_NOTIFICATION, notification);
  56. mIsShowingNotification = true;
  57. }
上面两个方法都要执行,一个是创建通知 一个是启动通知
1.创建通知
createIncomingCallNotification
 
                 
  1. private void createIncomingCallNotification(
  2. Call call, int state, Notification.Builder builder) {
  3. if (state == Call.State.ACTIVE) {
  4. builder.setUsesChronometer(true);
  5. builder.setWhen(call.getConnectTimeMillis());
  6. } else {
  7. builder.setUsesChronometer(false);
  8. }

  9. // Add hang up option for any active calls (active | onhold), outgoing calls (dialing).
  10. if (state == Call.State.ACTIVE ||
  11. state == Call.State.ONHOLD ||
  12. Call.State.isDialing(state)) {
  13. addHangupAction(builder);
  14. } else if (state == Call.State.INCOMING || state == Call.State.CALL_WAITING) {
  15. addDismissAction(builder);
  16. if (call.isVideoCall(mContext)) {
  17. addVoiceAction(builder);
  18. addVideoCallAction(builder);
  19. } else {
  20. addAnswerAction(builder);
  21. }
  22. }
  23. }
上面添加“接听”和“忽略”两个操作,
 
                 
  1. private void addAnswerAction(Notification.Builder builder) {
  2. Log.i(this, "Will show \"answer\" action in the incoming call Notification");
  3. PendingIntent answerVoicePendingIntent = createNotificationPendingIntent(
  4. mContext, InCallApp.ACTION_ANSWER_VOICE_INCOMING_CALL);
  5. builder.addAction(R.drawable.ic_call_white_24dp,
  6. mContext.getText(R.string.description_target_answer),
  7. answerVoicePendingIntent);
  8. }
  9. private void addDismissAction(Notification.Builder builder) {
  10. Log.i(this, "Will show \"dismiss\" action in the incoming call Notification");
  11. PendingIntent declinePendingIntent =
  12. createNotificationPendingIntent(mContext, InCallApp.ACTION_DECLINE_INCOMING_CALL);
  13. builder.addAction(R.drawable.ic_close_dk,
  14. mContext.getText(R.string.notification_action_dismiss),
  15. declinePendingIntent);
  16. }
启动通知了:
NotificationManager.java
 
                 
  1. /**
  2. * Post a notification to be shown in the status bar. If a notification with
  3. * the same id has already been posted by your application and has not yet been canceled, it
  4. * will be replaced by the updated information.
  5. *
  6. * @param id An identifier for this notification unique within your
  7. * application.
  8. * @param notification A {@link Notification} object describing what to show the user. Must not
  9. * be null.
  10. */
  11. public void notify(int id, Notification notification)
  12. {
  13. notify(null, id, notification);
  14. }

根据下面的说明我们知道,在状态栏显示处通知
我们跟的是来电的代码,来电信息呈献给用户有两种情况:
1. 屏幕唤醒状态下 是在通知栏显示通知
2. 屏幕熄灭状态下 点亮屏幕全屏显示
如下图所示:


 
                 
  1. /**
  2. * Post a notification to be shown in the status bar. If a notification with
  3. * the same tag and id has already been posted by your application and has not yet been
  4. * canceled, it will be replaced by the updated information.
  5. *
  6. * @param tag A string identifier for this notification. May be {@code null}.
  7. * @param id An identifier for this notification. The pair (tag, id) must be unique
  8. * within your application.
  9. * @param notification A {@link Notification} object describing what to
  10. * show the user. Must not be null.
  11. */
  12. public void notify(String tag, int id, Notification notification)
  13. {
  14. int[] idOut = new int[1];
  15. INotificationManager service = getService();
  16. String pkg = mContext.getPackageName();
  17. if (notification.sound != null) {
  18. notification.sound = notification.sound.getCanonicalUri();
  19. if (StrictMode.vmFileUriExposureEnabled()) {
  20. notification.sound.checkFileUriExposed("Notification.sound");
  21. }
  22. }
  23. if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
  24. Notification stripped = notification.clone();
  25. Builder.stripForDelivery(stripped);
  26. try {
  27. service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
  28. stripped, idOut, UserHandle.myUserId());
  29. if (id != idOut[0]) {
  30. Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
  31. }
  32. } catch (RemoteException e) {
  33. }
  34. }




你可能感兴趣的:(Telephony,Android,MO/MT)