Android 5.1 Phone MT(来电)流程分析(应用层)
来源:互联网 发布:汽车美容快修软件 编辑:程序博客网 时间:2024/06/05 15:00
写在前面的话
本文主要分析Android 接电话的流程,研究的代码是Android 5.1的,现在我们只关注应用层,以CDMA为例,GSM同理。
一、显示来电的界面
(如果图片看不清的话,可以右键选择在新标签中打开图片,或者把图片另存到自己电脑再查看。)
步骤1,2:在Framework层的最后,是由PhoneBase.java将来电通知传递到应用层的,如果想了解这段流程,请看《Android 5.1 Phone MT(来电)流程分析(Framework层) 》的步骤1~13。
步骤3,4,5: 好了,回到正题,本文主要讲的是应用层的流程。PstnIncomingCallNotifier.java在registerForNotifications()方法里注册监听了EVENT_NEW_RINGING_CONNECTION
事件,因此它会接收到Framework层传递过来的来电通知。在PstnIncomingCallNotifier.java里mHandler的handleMessage()方法有EVENT_NEW_RINGING_CONNECTION
相应的处理。
/** * Used to listen to events from {@link #mPhoneBase}. */ private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch(msg.what) { case EVENT_NEW_RINGING_CONNECTION: handleNewRingingConnection((AsyncResult) msg.obj); break; ... } } }; /** * 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. if (call != null && call.getState().isRinging()) { Phone phone = call.getPhone(); if (phone != null&& isBlockedByFirewall(connection.getAddress(), phone.getPhoneId())) { PhoneUtils.hangupRingingCall(call); sendBlockRecordBroadcast(phone.getPhoneId(), connection.getAddress()); return; } sendIncomingCallIntent(connection); } } } /** * Sends the incoming call intent to telecom. */ private void sendIncomingCallIntent(Connection connection) { ... TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall( TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras); }}
步骤6: TelecomManager.java的addNewIncomingCall()方法
/** * 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); } }
步骤7~10: TelecomService.java的addNewIncomingCall()方法
/** * @see android.telecom.TelecomManager#addNewIncomingCall */ @Override public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle); if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) { mAppOpsManager.checkPackage( Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName()); // Make sure it doesn't cross the UserHandle boundary enforceUserHandleMatchesCaller(phoneAccountHandle); Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL); intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, true); if (extras != null) { intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras); } sendRequestAsync(MSG_NEW_INCOMING_CALL, 0, intent); } else { Log.w(this, "Null phoneAccountHandle. Ignoring request to add new incoming call"); } } private MainThreadRequest sendRequestAsync(int command, int arg1, Object arg) { MainThreadRequest request = new MainThreadRequest(); request.arg = arg; mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget(); return request; }
(在这里跟Android5.0是不一样的)在sendRequestAsync()方法里调用obtainMessage()方法创建了一个消息类型为MSG_NEW_INCOMING_CALL
的Message,并且通过sendToTarget()发送出去。
步骤11,12: TelecomService.java里MainThreadHandler的handleMessage()方法有对MSG_NEW_INCOMING_CALL
的处理。
case MSG_NEW_INCOMING_CALL: if (request.arg == null || !(request.arg instanceof Intent)) { Log.w(this, "Invalid new incoming call request"); break; } CallReceiver.processIncomingCallIntent((Intent) request.arg); break;
调用了CallReceiver.java的processIncomingCallIntent(),进而又调用CallsManager.java的processIncomingCallIntent()方法。
步骤13: CallsManager.java的processIncomingCallIntent()方法
/** * Starts the process to attach the call to a connection service. * * @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. */ void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { Log.d(this, "processIncomingCallIntent"); Uri handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER); Call call = new Call( mContext, mConnectionServiceRepository, handle, null /* gatewayInfo */, null /* connectionManagerPhoneAccount */, phoneAccountHandle, true /* isIncoming */, false /* isConference */); call.setExtras(extras); // TODO: Move this to be a part of addCall() call.addListener(this); call.startCreateConnection(mPhoneAccountRegistrar); }
在这里创建了一个Call对象,并且把需要的参数传递进来,并且调用Call的startCreateConnection方法。
步骤14,15,16: Call.java的startCreateConnection()方法,这个Call.java是在packages\services\telecomm\src\com\android\server\telecom目录下的。
/** * Starts the create connection sequence. Upon completion, there should exist an active * connection through a connection service (or the call will have failed). * * @param phoneAccountRegistrar The phone account registrar. */ void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) { Preconditions.checkState(mCreateConnectionProcessor == null); mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext); mCreateConnectionProcessor.process(); }
创建了一个CreateConnectionProcessor对象,先调用它的process()方法,再调用attemptNextPhoneAccount方法,最后调用了ConnectionServiceWrapper.java的createConnection()方法,步骤13中创建的Call对象也就被传递到了这里。
步骤17: ConnectionServiceWrapper.java的createConnection()方法。
/** * Creates a new connection for a new outgoing call or to attach to an existing incoming call. */ void createConnection(final Call call, final CreateConnectionResponse response) { Log.d(this, "createConnection(%s) via %s.", call, getComponentName()); BindCallback callback = new BindCallback() { @Override public void onSuccess() { String callId = mCallIdMapper.getCallId(call); mPendingResponses.put(callId, response); GatewayInfo gatewayInfo = call.getGatewayInfo(); Bundle extras = call.getExtras(); if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && gatewayInfo.getOriginalAddress() != null) { extras = (Bundle) extras.clone(); extras.putString( TelecomManager.GATEWAY_PROVIDER_PACKAGE, gatewayInfo.getGatewayProviderPackageName()); extras.putParcelable( TelecomManager.GATEWAY_ORIGINAL_ADDRESS, gatewayInfo.getOriginalAddress()); } try { mServiceInterface.createConnection( call.getConnectionManagerPhoneAccount(), callId, new ConnectionRequest( call.getTargetPhoneAccount(), call.getHandle(), extras, call.getVideoState()), call.isIncoming(), call.isUnknown()); } catch (RemoteException e) { Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); mPendingResponses.remove(callId).handleCreateConnectionFailure( new DisconnectCause(DisconnectCause.ERROR, e.toString())); } } @Override public void onFailure() { Log.e(this, new Exception(), "Failure to call %s", getComponentName()); response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); } }; mBinder.bind(callback); }
步骤18,19:这里调用了ConnectionServiceWrapper的父类ServiceBinder的bind()方法,先new一个ServiceConnection对象,然后绑定一个远程服务端服务。如果绑定成功的话,在ServiceBinder的内部类ServiceBinderConnection的onServiceConnected()方法就被调用。
在这里做了两件事:
1、步骤20,21:通过setBinder()方法,回调ConnectionServiceWrapper的setServiceInterface()方法,通过mServiceInterface = IConnectionService.Stub.asInterface(binder);
这行代码获取一个远程服务端的对象mServiceInterface 。
2、步骤22,23:再通过调用handleSuccessfulConnection()方法回调callback 的onSuccess()方法,也就又回到ConnectionServiceWrapper的createConnection()方法里。
步骤24,25:最后通过这一行mServiceInterface.createConnection();
,调用ConnectionService.java里mBinder的createConnection()方法。
private final IBinder mBinder = new IConnectionService.Stub() { ... @Override public void createConnection(PhoneAccountHandle connectionManagerPhoneAccount, String id,ConnectionRequest request, boolean isIncoming,boolean isUnknown) { SomeArgs args = SomeArgs.obtain(); args.arg1 = connectionManagerPhoneAccount; args.arg2 = id; args.arg3 = request; args.argi1 = isIncoming ? 1 : 0; args.argi2 = isUnknown ? 1 : 0; mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget(); } ...}
步骤26,27:在这里通过obtainMessage()方法创建了一个消息类型为MSG_CREATE_CONNECTION
的Message,再把传进来的参数封装到Message里再发送出去,然后在ConnectionService.java里mHandler的handleMessage()方法里处理这个Message,最后就调用了ConnectionService.java的createConnection()方法。
步骤28: ConnectionService.java的createConnection()方法。
/** * This can be used by telecom to either create a new outgoing call or attach to an existing * incoming call. In either case, telecom will cycle through a set of services and call * createConnection util a connection service cancels the process or completes it successfully. */ private void createConnection( final PhoneAccountHandle callManagerAccount, final String callId, final ConnectionRequest request, boolean isIncoming, boolean isUnknown) { Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " + "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request, isIncoming, isUnknown); Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request) : isIncoming ? onCreateIncomingConnection(callManagerAccount, request) : onCreateOutgoingConnection(callManagerAccount, request); Log.d(this, "createConnection, connection: %s", connection); if (connection == null) { connection = Connection.createFailedConnection( new DisconnectCause(DisconnectCause.ERROR)); } if (connection.getState() != Connection.STATE_DISCONNECTED) { addConnection(callId, connection); } Uri address = connection.getAddress(); String number = address == null ? "null" : address.getSchemeSpecificPart(); Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: 0x%x", Connection.toLogSafePhoneNumber(number), Connection.stateToString(connection.getState()), Connection.capabilitiesToString(connection.getConnectionCapabilities()), connection.getCallProperties()); Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId); mAdapter.handleCreateConnectionComplete( callId, request, new ParcelableConnection( getAccountHandle(request, connection), connection.getState(), connection.getConnectionCapabilities(), connection.getCallProperties(), connection.getAddress(), connection.getAddressPresentation(), connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation(), connection.getVideoProvider() == null ? null : connection.getVideoProvider().getInterface(), connection.getVideoState(), connection.isRingbackRequested(), connection.getAudioModeIsVoip(), connection.getStatusHints(), connection.getDisconnectCause(), createIdList(connection.getConferenceables()), connection.getCallSubstate())); if (isUnknown) { triggerConferenceRecalculate(); } }
步骤29: onCreateIncomingConnection()方法会被调用到,这个方法被TelephonyConnectionService重写,TelephonyConnectionService是ConnectionService的实例,所以会调用TelephonyConnectionService.java的onCreateIncomingConnection()方法来创建一个CDMAConnection对象。
步骤30:创建CDMAConnection对象之后,就调用ConnectionServiceAdapter.java的handleCreateConnectionComplete()来处理之后的事情,比如启动UI界面之类。
步骤31~39:流程一直走,这一段也没什么好说的了。
步骤40: CallsManager.java的onSuccessfulIncomingCall()方法。
在这里做了两件事:
1、把Call的状态从NEW
改成RINGING
。
2、把Call对象添加到Call的集合里。(步骤41)
步骤42~63: 启动UI界面,有两种方式,弹出一个小窗口显示来电,或者全屏显示来电。
二、接听电话
也没什么好说的,时序图已经写得比较明白,在步骤18之后,就紧接着《Android 5.1 Phone MT(来电)流程分析(Framework层) 》的步骤21。等真正接通电话之后,就把Call的状态从RINGING改成ACTIVE,Call的状态改变之后,就会停止响铃,对应《Android 5.1 Phone MT(来电)流程分析(Framework层) 》的步骤20。
如果想继续了解Framework层的流程,请看《Android 5.1 Phone MT(来电)流程分析(Framework层) 》。
- Android 5.1 Phone MT(来电)流程分析(应用层)
- Android 5.1 Phone MT(来电)流程分析(Framework层)
- Android 5.1 Phone MT(来电)流程分析(Framework层)
- Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程
- Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程
- Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程
- Android 6.0 Phone MO(去电)流程分析(应用层)
- Android6.0的phone应用源码分析(8)——来电(MT)
- Android6.0的phone应用源码分析(8)——来电(MT)
- Android N 来电流程(MT)
- Android N 来电流程(MT)
- Android 4.0 Phone拨号和来电流程分析
- Android 5.1 Phone MO(去电)流程分析(Framework层)
- android -- phone (三)来电流程
- Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析
- 转(Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析)
- Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析
- Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析
- (九) Build Variants(构建变种版本)
- mongoDb-学习笔记3
- angular指令插件1——toggle
- android事件之onInterceptTouchEvent,dispatchTouchEvent,onTouchEvent,requestDisallowInterceptTouchEvent
- Decode Ways
- Android 5.1 Phone MT(来电)流程分析(应用层)
- 关于细节
- SWTableViewCell滑动删除表格行
- 使用Gson转化天气预报Json
- windows下mysql忘记root密码的解决办法
- java volatile关键字
- webService学习记录-01
- iOS app打包 -- 生成ipa测试包 步骤详解
- Bootstrap的js插件之弹出框(popover)