本文主要是介绍Android 5.0 Lollipop MT流程 代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
---我理解的来电流程大概分为6各部分--
注: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状态变化 -> 发出来电通知
0. Modem发出Call状态变化的通知,
1. framwork/opt/telephony/.../RIL.java
1.1.RIL接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息
1.2.然后经由
mCallStateRegistrants.notifyRegistrants发出通知(RegistrantList消息处理机制此处不做具体说明)。
private void
processUnsolicited ( Parcel p ) { ...
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
BaseCommands.java registerForCallStateChanged() mCallStateRegistrants.add(r);
注册为观察者(android源码中大量用到观察者模式,或者叫RegistrantList消息处理机制)。
@Override
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
//添加到观察者列表
mCallStateRegistrants.add(r);
}
2. framwork/opt/telephony/...GSMCallTracker.java
2.1查找察者被调用的地方(AS中的快捷键Ctrl+Alt+H), 两处被响应处理处理,其中一处:GSMCallTracker handleMessage
...//registerForCallStateChanged调用
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
...
@Override
public void
//响应处理
handleMessage (Message msg) {
...
case EVENT_CALL_STATE_CHANGE:
//调用父类CallTracker查询Call List方法
pollCallsWhenSafe ();
break;
2.1.1. pollCallsWhenSafe ()方法在CallTracker.java中实现
protected void pollCallsWhenSafe () {
mNeedsPoll = true;
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);//RIL.java中的getCurrentCalls方法
}
}
2.1.2 回到RIL.java getCurrentCalls 将RIL_REQUEST_GET_CURRENT_CALLS 消息封装成 RILRequest 类型并发送。
@Override
public void
getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
2.2 RIL.java 有三处接收处理 RIL_REQUEST_GET_CURRENT_CALLS 消息,真正的逻辑处理在processSolicited方法
private RILRequest processSolicited (Parcel p) {
...
case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break;
...
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, null, tr);
rr.mResult.sendToTarget();//发出handler消息通知
}
2.3 回到framworks/opt/telephony/.../telephony/gsm/GSMCallTracker.java
rr . mResult . sendToTarget ()发出handler消息通知后,会在CallTracker中的handleMessage方法中响应。并且它的消息类型是“ EVENT_POLL_CALLS_RESULT"
@Override
public void
handleMessage (Message msg) {
...
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.obj;
if (msg == mLastRelevantPoll) {
if (DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
mNeedsPoll = false;
mLastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
}
break;
handlePollCalls方法根据RIL发出的Call List对象判断Call的状态,并发出不同的通知,
1) 新来电的通知是: phone. notifyNewRingingConnection;
handlePollCalls(){
...
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);
}
另外两个是
2) 通话断开通知 onDisconnected;
3) Call状态变化通知 phone.notifiyPreciseCallStateChanged.
来电的时候发出的是phone.notifyNewRingConnection通知,进入到notifyNewRingConnection方法
3. framworks/opt/telephony/.../telephony/gsm/GSMPhone.java
public void notifyNewRingingConnection(Connection c) {
super.notifyNewRingingConnectionP(c);
}
调用父类 PhoneBase.java
notifyNewRingingConnectionP() 发出来电通知 mNewRingingConnectionRegistrants.notifyRegistrants(ar);
/**
* Notify registrants of a new ringing Connection.
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
*/
public void notifyNewRingingConnectionP(Connection cn) {
if (!mIsVoiceCapable)
return;
AsyncResult ar = new AsyncResult(null, cn, null);
mNewRingingConnectionRegistrants.notifyRegistrants(ar);
}
RegistrantList.java
public /*synchronized*/ void
notifyRegistrants(AsyncResult ar)
{
internalNotifyRegistrants(ar.result, ar.exception);
}
private synchronized void
internalNotifyRegistrants (Object result, Throwable exception)
{
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}
}
/*package*/ void
internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();
if (h == null) {
clear();
} else {
Message msg = Message.obtain();
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
注册为观察者的方法为:
// Inherited documentation suffices.
@Override
public void registerForNewRingingConnection(
Handler h, int what, Object obj) {
checkCorrectThread(h);
mNewRingingConnectionRegistrants.addUnique(h, what, obj);
}
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
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等
public static final String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
...
/**
* @see android.telecom.TelecomManager#addNewIncomingCall
*/
@Override
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
mAppOpsManager.checkPackage(
Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
intent.setPackage(mContext.getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
if (extras != null) {
intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
}
long token = Binder.clearCallingIdentity();
//启动Activity
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
Binder.restoreCallingIdentity(token);
}
}
//启动 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.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}]
<div class="linenums" style="color: rgb(30, 52, 123); margin-top: 0px; margin-bottom: 0px; padding-left: 0px; "><div class="L0" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">static</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">void</span><span class="pln" style="color: rgb(72, 72, 76); "> processIncomingCallIntent</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">Intent</span><span class="pln" style="color: rgb(72, 72, 76); "> intent</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L1" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">PhoneAccountHandle</span><span class="pln" style="color: rgb(72, 72, 76); "> phoneAccountHandle </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> intent</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getParcelableExtra</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span></code></div><div class="L2" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">TelecomManager</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">EXTRA_PHONE_ACCOUNT_HANDLE</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L3" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "> </code></div><div class="L4" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">phoneAccountHandle </span><span class="pun" style="color: rgb(147, 161, 161); ">==</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">null</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L5" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">w</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">TAG</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"Rejecting incoming call due to null phone account"</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L6" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">return</span><span class="pun" style="color: rgb(147, 161, 161); ">;</span></code></div><div class="L7" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L8" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">phoneAccountHandle</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getComponentName</span><span class="pun" style="color: rgb(147, 161, 161); ">()</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">==</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">null</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L9" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">w</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">TAG</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"Rejecting incoming call due to null component name"</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L0" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">return</span><span class="pun" style="color: rgb(147, 161, 161); ">;</span></code></div><div class="L1" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L2" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "> </code></div><div class="L3" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Bundle</span><span class="pln" style="color: rgb(72, 72, 76); "> clientExtras </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">null</span><span class="pun" style="color: rgb(147, 161, 161); ">;</span></code></div><div class="L4" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">intent</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">hasExtra</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">TelecomManager</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">EXTRA_INCOMING_CALL_EXTRAS</span><span class="pun" style="color: rgb(147, 161, 161); ">))</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L5" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> clientExtras </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> intent</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getBundleExtra</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">TelecomManager</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">EXTRA_INCOMING_CALL_EXTRAS</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L6" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L7" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">clientExtras </span><span class="pun" style="color: rgb(147, 161, 161); ">==</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">null</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L8" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> clientExtras </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Bundle</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">EMPTY</span><span class="pun" style="color: rgb(147, 161, 161); ">;</span></code></div><div class="L9" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L0" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "> </code></div><div class="L1" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">d</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">TAG</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"Processing incoming call from connection service [%s]"</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span></code></div><div class="L2" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> phoneAccountHandle</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getComponentName</span><span class="pun" style="color: rgb(147, 161, 161); ">());</span></code></div><div class="L3" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> getCallsManager</span><span class="pun" style="color: rgb(147, 161, 161); ">().</span><span class="pln" style="color: rgb(72, 72, 76); background-color: rgb(192, 192, 192); ">processIncomingCallIntent</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">phoneAccountHandle</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> clientExtras</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L4" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div></div>
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.
*/
/**
* 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);
}
④ 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里。
/**
* 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();
}
10.1 process
void process() {
Log.v(this, "process");
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency();
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
}
10.2 attemptNextPhoneAccount()
service试图建立连接
private void attemptNextPhoneAccount() {
...
if (mResponse != null && attempt != null) {
Log.i(this, "Trying attempt %s", attempt);
ConnectionServiceWrapper service =
mRepository.getService(
attempt.connectionManagerPhoneAccount.getComponentName());
if (service == null) {
Log.i(this, "Found no connection service for attempt %s", attempt);
attemptNextPhoneAccount();
} else {
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(service);
Log.i(this, "Attempting to call from %s", service.getComponentName());
service.createConnection(mCall, new Response(service));
}
}
11. packages/services/Telecomm/src/com/android/server/telecom/ ConnectionServiceWrapper.java
11.1 createConnection()
BindCallback 是interface
/** * 为播出的电话建立连接,或者attach一个已经存在的来电。
*/
/**
* 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);
}
12. packages/services/Telecomm/src/com/android/server/telecom/Servicesbinder.java
12.1 bind 绑定连接
/** * 执行绑定到服务的操作(如果还没有绑定)然后执行指定的回调方法
*
* @param callback The 回调方法通知绑定是成功或失败
*/
/**
* Helper class to perform on-demand binding.
*/
final class Binder {
/**
* Performs an bind to the service (only if not already bound) and executes the
* specified callback.
*
* @param callback The callback to notify of the binding's success or failure.
*/
void bind(BindCallback callback) {
ThreadUtil.checkOnMainThread();
Log.d(ServiceBinder.this, "bind()");
// Reset any abort request if we're asked to bind again.
clearAbort();
if (!mCallbacks.isEmpty()) {
// Binding already in progress, append to the list of callbacks and bail out.
mCallbacks.add(callback);
return;
}
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection();
Log.d(ServiceBinder.this, "Binding to service with intent: %s", serviceIntent);
if (! mContext . bindService ( serviceIntent , connection , Context . BIND_AUTO_CREATE )) {
handleFailedConnection();
return;
}
} else {
Log.d(ServiceBinder.this, "Service is already bound.");
Preconditions.checkNotNull(mBinder);
handleSuccessfulConnection();
}
}
}
//
上面的执行完之后,顺序执行到 onServiceConnected
12.2 onServiceConnected
private final class ServiceBinderConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
ThreadUtil.checkOnMainThread();
Log.i(this, "Service bound %s", componentName);//这句log被打印出来了
// Unbind request was queued so unbind immediately.
if (mIsBindingAborted) {
clearAbort();
logServiceDisconnected("onServiceConnected");
mContext.unbindService(this);
handleFailedConnection();
return;
}
mServiceConnection = this;
setBinder(binder);
handleSuccessfulConnection();
}
handleSuccessfulConnection
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
}
mCallbacks.clear();
}
回调上面的onSuccess() 执行 mServiceInterface . createConnection createConnection的具体实现在
13. framworks/base/telecomm/java/android/telecom/ConnectionServices.java
@Override
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
//chengzhi
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();
}
13.1 handleMessage() MSG_CREATE_CONNECTION
case MSG_CREATE_CONNECTION: {
SomeArgs args = (SomeArgs) msg.obj;
try {
//chengzhi
final PhoneAccountHandle connectionManagerPhoneAccount =
(PhoneAccountHandle) args.arg1;
final String id = (String) args.arg2;
final ConnectionRequest request = (ConnectionRequest) args.arg3;
final boolean isIncoming = args.argi1 == 1;
final boolean isUnknown = args.argi2 == 1;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init request %s", id);
mPreInitializationConnectionRequests.add(new Runnable() {
@Override
public void run() {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
});
} else {
//chengzhi debug
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
} finally {
args.recycle();
}
break;
}
13.1.1 createConnection方法
创建 Connection connection
/**
* 这个方法可以被telecom用来创建呼出电话或者一个已存在的来电。任何一种情况,telecom都会循环经过一系列的服务和 调用
createConnection util a connection service取消或者成功完成创建。 */
/**
* 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);
//chengzhi 01
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
.....
mAdapter.handleCreateConnectionComplete
前面建立连接成功了,后面处理成功的连接
后面执行 mAdapter.handleCreateConnectionComplete
14.framework/base/telecomm/java/android/telecom/ConnectionServicesAdapter.java
void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
//chengzhi 03
adapter.handleCreateConnectionComplete(id, request, connection);
} catch (RemoteException e) {
}
}
}
15. //packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java handleCreateConnectionComplete
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
public void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
logIncoming("handleCreateConnectionComplete %s", request);
if (mCallIdMapper.isValidCallId(callId)) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = request;
args.arg3 = connection;
mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args)
.sendToTarget();
}
}
15.2 handleMessage处理消息 MSG_HANDLE_CREATE_CONNECTION_COMPLETE
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Call call;
switch (msg.what) {
case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
String callId = (String) args.arg1;
ConnectionRequest request = (ConnectionRequest) args.arg2;
ParcelableConnection connection = (ParcelableConnection) args.arg3;
handleCreateConnectionComplete(callId, request, connection);
} finally {
args.recycle();
}
break;
}
15.2.1 handleCreateConnectionComplete ()
如果成功连接
private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
// TODO: Note we are not using parameter "request", which is a side effect of our tacit
// assumption that we have at most one outgoing connection attempt per ConnectionService.
// This may not continue to be the case.
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// A connection that begins in the DISCONNECTED state is an indication of
// failure to connect; we handle all failures uniformly
removeCall(callId, connection.getDisconnectCause());
} else {
// Successful connection
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId)
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
}
}
重写 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
private final Runnable mDirectToVoicemailRunnable = new Runnable() {
@Override
public void run() {
processDirectToVoicemail();
}
16.2.1 processDirectToVoicemail
final class Call implements CreateConnectionResponse {
/**
* Listener for events on the call.
*/
interface Listener {
void onSuccessfulIncomingCall ( Call call ); ...
private void processDirectToVoicemail() {
if (mDirectToVoicemailQueryPending) {
if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
Log.i(this, "Directing call to voicemail: %s.", this);
// TODO: Once we move State handling from CallsManager to Call, we
// will not need to set STATE_RINGING state prior to calling reject.
setState(CallState.RINGING);
reject(false, null);
} else {
// TODO: Make this class (not CallsManager) responsible for changing
// the call state to STATE_RINGING.
// TODO: Replace this with state transition to STATE_RINGING.
for (Listener l : mListeners) {
l.onSuccessfulIncomingCall(this);
}
}
mDirectToVoicemailQueryPending = false;
}
}
17. //package/services/Telecomm/src/com/android/server/telecom/CallsManager.java
17.1
@Override onSuccessfulIncomingCall
if 判断后 addCall()
public final class CallsManager extends Call.ListenerBase {
...
@Override
public void onSuccessfulIncomingCall(Call incomingCall) {
Log.d(this, "onSuccessfulIncomingCall");
setCallState(incomingCall, CallState.RINGING);
if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
incomingCall.reject(false, null);
// since the call was not added to the list of calls, we have to call the missed
// call notifier and the call logger manually.
mMissedCallNotifier.showMissedCallNotification(incomingCall);
mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
} else {
incomingCall.mIsActiveSub = true;
addCall(incomingCall);
setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
}
}
17.1.1 addCall()
/**
* Adds the specified call to the main list of live calls.
*
* @param call The call to add.
*/
private void addCall(Call call) {
Log.v(this, "addCall(%s)", call);
call.addListener(this);
mCalls.add(call);
// TODO: Update mForegroundCall prior to invoking
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
listener.onCallAdded(call);
}
updateForegroundCall();
}
18. //package/services/Telecomm/src/com/android/server/telecom/ InCallController.java
18.1 重写onCallAdded
@OverrideonCallAdded()
@Override
public void onCallAdded(Call call) {
if (mInCallServices.isEmpty()) {
bind();//执行这里
} else {
Log.i(this, "onCallAdded: %s", call);//输出log
// Track the call if we don't already know about it.
addCall(call);
for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = toParcelableCall(call,
componentName.equals(mInCallComponentName) /* includeVideoProvider */);
try {
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
}
}
18.1.1 bind()
InCallServiceConnection inCallServiceConnection =newInCallServiceConnection();
/**
* Binds to the in-call app if not already connected by binding directly to the saved
* component name of the {@link IInCallService} implementation.
*/
private void bind() {
ThreadUtil.checkOnMainThread();
if (mInCallServices.isEmpty()) {
PackageManager packageManager = mContext.getPackageManager();
Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
for (ResolveInfo entry : packageManager.queryIntentServices(serviceIntent, 0)) {
ServiceInfo serviceInfo = entry.serviceInfo;
if (serviceInfo != null) {
boolean hasServiceBindPermission = serviceInfo.permission != null &&
serviceInfo.permission.equals(
Manifest.permission.BIND_INCALL_SERVICE);
boolean hasControlInCallPermission = packageManager.checkPermission(
Manifest.permission.CONTROL_INCALL_EXPERIENCE,
serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED;
if (!hasServiceBindPermission) {
Log.w(this, "InCallService does not have BIND_INCALL_SERVICE permission: " +
serviceInfo.packageName);
continue;
}
if (!hasControlInCallPermission) {
Log.w(this,
"InCall UI does not have CONTROL_INCALL_EXPERIENCE permission: " +
serviceInfo.packageName);
continue;
}
InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
ComponentName componentName = new ComponentName(serviceInfo.packageName,
serviceInfo.name);
Log.i(this, "Attempting to bind to InCall %s, is dupe? %b ", //log输出
serviceInfo.packageName,
mServiceConnections.containsKey(componentName));
if (!mServiceConnections.containsKey(componentName)) {
Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
intent.setComponent(componentName);
if (mContext.bindServiceAsUser(intent, inCallServiceConnection,
Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
mServiceConnections.put(componentName, inCallServiceConnection);
}
}
}
}
}
}
18.1.2 InCallServiceConnection inCallServiceConnection = new InCallServiceConnection ();
InCallServiceConnection
/**
* Used to bind to the in-call app and triggers the start of communication between
* this class and in-call app.
*/
private class InCallServiceConnection implements ServiceConnection {
/** {@inheritDoc} */
@Override public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(this, "onServiceConnected: %s", name);
onConnected(name, service);
}
/** {@inheritDoc} */
@Override public void onServiceDisconnected(ComponentName name) {
Log.d(this, "onDisconnected: %s", name);
onDisconnected(name);
}
}
18.1.3 onConnected
/**
* Persists the {@link IInCallService} instance and starts the communication between
* this class and in-call app by sending the first update to in-call app. This method is
* called after a successful binding connection is established.
*
* @param componentName The service {@link ComponentName}.
* @param service The {@link IInCallService} implementation.
*/
private void onConnected(ComponentName componentName, IBinder service) {
ThreadUtil.checkOnMainThread();
Log.i(this, "onConnected to %s", componentName);
IInCallService inCallService = IInCallService.Stub.asInterface(service);
try {
inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(),
mCallIdMapper));
mInCallServices.put(componentName, inCallService);
} catch (RemoteException e) {
Log.e(this, e, "Failed to set the in-call adapter.");
return;
}
// Upon successful connection, send the state of the world to the service.
ImmutableCollection<Call> calls = CallsManager.getInstance().getCalls();
if (!calls.isEmpty()) {
Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(),
componentName);
for (Call call : calls) {
try {
// Track the call if we don't already know about it.
Log.i(this, "addCall after binding: %s", call);
addCall(call);
inCallService.addCall(toParcelableCall(call,
componentName.equals(mInCallComponentName) /* includeVideoProvider */));
} catch (RemoteException ignored) {
}
}
onAudioStateChanged(null, CallsManager.getInstance().getAudioState());
} else {
unbind();
}
}
addCall(call)
19. //framworks/base/telecomm/java/android/telecom/InCallService.java
@Override
addCall()
/** Manages the binder calls so that the implementor does not need to deal with it. */
private final class InCallServiceBinder extends IInCallService.Stub {
@Override
public void setInCallAdapter(IInCallAdapter inCallAdapter) {
mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
}
@Override
public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
}
19.1 handleMessage 处理消息 MSG_ADD_CALL
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
return;
}
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
onPhoneCreated(mPhone);
break;
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
break;
21. //framworks/base/telecomm/java/android/telecom/Phone.java
internalAddCall()
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
parcelableCall.mIsActiveSub);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
fireCallAdded(call);
}
20.1.1 fireCallAdded()
private void fireCallAdded(Call call) {
for (Listener listener : mListeners) {
listener.onCallAdded(this, call);
}
}
onCallAdded() @SystemApi系统Api 其他使用的地方会 @Override
@SystemApipublic final class Phone { public abstract static class Listener {
...
public void onCallAdded(Phone phone, Call call) { }
接22_2.
22_1. //pacakge/apps/InCallUI/src/com/android/incallui/ CallList.java
@Override
onCallAdded
/**
* Static singleton accessor method.
*/
public static CallList getInstance() {
return sInstance;
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
@Override
public void onCallAdded(Phone phone, android.telecom.Call telecommCall) {
Call call = new Call(telecommCall);
if (call.getState() == Call.State.INCOMING) {
onIncoming(call, call.getCannedSmsResponses());
} else {
onUpdate(call);
}
}
执行了下面的方法,但再往后的步骤不是从这里走的。
onIncoming()
<div class="linenums" style="margin-top: 0px; margin-bottom: 0px; padding-left: 0px; "><div class="L0" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); ">/**</span></code></div><div class="L1" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * Called when a single call has changed.</span></code></div><div class="L2" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> */</span></code></div><div class="L3" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">public</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">void</span><span class="pln" style="color: rgb(72, 72, 76); "> onIncoming</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">Call</span><span class="pln" style="color: rgb(72, 72, 76); "> call</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">List</span><span class="pun" style="color: rgb(147, 161, 161); "><</span><span class="typ" style="color: teal; ">String</span><span class="pun" style="color: rgb(147, 161, 161); ">></span><span class="pln" style="color: rgb(72, 72, 76); "> textMessages</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L4" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">d</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="kwd" style="color: rgb(30, 52, 123); ">this</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"onIncoming - "</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> call</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L5" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "> </code></div><div class="L6" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="com" style="color: rgb(147, 161, 161); ">// Update active subscription from call object. it will be set by</span></code></div><div class="L7" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="com" style="color: rgb(147, 161, 161); ">// Telecomm service for incoming call and whenever active sub changes.</span></code></div><div class="L8" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">call</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">mIsActiveSub</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L9" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">long</span><span class="pln" style="color: rgb(72, 72, 76); "> sub </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> call</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getSubId</span><span class="pun" style="color: rgb(147, 161, 161); ">();</span></code></div><div class="L0" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">d</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="kwd" style="color: rgb(30, 52, 123); ">this</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"onIncoming - sub:"</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> sub </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">" mSubId:"</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> mSubId</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L1" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">sub </span><span class="pun" style="color: rgb(147, 161, 161); ">!=</span><span class="pln" style="color: rgb(72, 72, 76); "> mSubId</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L2" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> setActiveSubscription</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">sub</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L3" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L4" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L5" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "> </code></div><div class="L6" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">updateCallInMap</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">call</span><span class="pun" style="color: rgb(147, 161, 161); ">))</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L7" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">i</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="kwd" style="color: rgb(30, 52, 123); ">this</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"onIncoming - "</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> call</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L8" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L9" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> updateCallTextMap</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">call</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> textMessages</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L0" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "> </code></div><div class="L1" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">for</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">Listener</span><span class="pln" style="color: rgb(72, 72, 76); "> listener </span><span class="pun" style="color: rgb(147, 161, 161); ">:</span><span class="pln" style="color: rgb(72, 72, 76); "> mListeners</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L2" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> listener</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); background-color: rgb(192, 192, 192); ">onIncomingCall</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">call</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L3" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L4" style="color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pun" style="color: rgb(147, 161, 161); "> </span></code></div></div>
22_2. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java
@Override
onCallAdded
public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
...
private final Phone.Listener mPhoneListener = new Phone.Listener() {
...
@Override
public void onCallAdded(Phone phone, android.telecom.Call call) {
call.addListener(mCallListener);
}
23. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java @override onCallAdded
onIncomingCall
/**
* Called when there is a new incoming call.
*
* @param call
*/
@Override
public void onIncomingCall(Call call) {
InCallState newState = startOrFinishUi(InCallState.INCOMING);
InCallState oldState = mInCallState;
Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
mInCallState = newState;
for (IncomingCallListener listener : mIncomingCallListeners) {
listener.onIncomingCall(oldState, mInCallState, call);
}
if (CallList.getInstance().isDsdaEnabled() && (mInCallActivity != null)) {
mInCallActivity.updateDsdaTab();
}
}
startOrFinishUi() 开始或结束UI
注意注释部分的 immersive app
/**
* When the state of in-call changes, this is the first method to get called. It determines if
* the UI needs to be started or finished depending on the new state and does it.
*/
private InCallState startOrFinishUi(InCallState newState) {
Log.d(this, "startOrFinishUi: " + mInCallState + " -> " + newState);
// TODO: Consider a proper state machine implementation
// If the state isn't changing or if we're transitioning from pending outgoing to actual
// outgoing, we have already done any starting/stopping of activities in a previous pass
// ...so lets cut out early
boolean alreadyOutgoing = mInCallState == InCallState.PENDING_OUTGOING &&
newState == InCallState.OUTGOING;
boolean isAnyOtherSubActive = InCallState.INCOMING == newState &&
mCallList.isAnyOtherSubActive(mCallList.getActiveSubscription());
if ((newState == mInCallState && !(mInCallActivity == null && isAnyOtherSubActive))
|| alreadyOutgoing) {
return newState;
}
// A new Incoming call means that the user needs to be notified of the the call (since
// it wasn't them who initiated it). We do this through full screen notifications and
// happens indirectly through {@link StatusBarNotifier}.
//
// The process for incoming calls is as follows:
//
// 1) CallList - Announces existence of new INCOMING call
// 2) InCallPresenter - Gets announcement and calculates that the new InCallState
// - should be set to INCOMING.
// 3) InCallPresenter - This method is called to see if we need to start or finish
// the app given the new state.
// 4) StatusBarNotifier - Listens to InCallState changes. InCallPresenter calls
// StatusBarNotifier explicitly to issue a FullScreen Notification
// that will either start the InCallActivity or show the user a
// top-level notification dialog if the user is in an immersive app.//注意着一段注释
// That notification can also start the InCallActivity.
// 5) InCallActivity - Main activity starts up and at the end of its onCreate will
// call InCallPresenter::setActivity() to let the presenter
// know that start-up is complete.
//
// [ AND NOW YOU'RE IN THE CALL. voila! ]
//
// Our app is started using a fullScreen notification. We need to do this whenever
// we get an incoming call.
final boolean startStartupSequence = (InCallState.INCOMING == newState);
// A dialog to show on top of the InCallUI to select a PhoneAccount
final boolean showAccountPicker = (InCallState.WAITING_FOR_ACCOUNT == newState);
// A new outgoing call indicates that the user just now dialed a number and when that
// happens we need to display the screen immediately or show an account picker dialog if
// no default is set. However, if the main InCallUI is already visible, we do not want to
// re-initiate the start-up animation, so we do not need to do anything here.
//
// It is also possible to go into an intermediate state where the call has been initiated
// but Telecomm has not yet returned with the details of the call (handle, gateway, etc.).
// This pending outgoing state can also launch the call screen.
//
// This is different from the incoming call sequence because we do not need to shock the
// user with a top-level notification. Just show the call UI normally.
final boolean mainUiNotVisible = !isShowingInCallUi() || !getCallCardFragmentVisible();
final boolean showCallUi = ((InCallState.PENDING_OUTGOING == newState ||
InCallState.OUTGOING == newState) && mainUiNotVisible);
// TODO: Can we be suddenly in a call without it having been in the outgoing or incoming
// state? I havent seen that but if it can happen, the code below should be enabled.
// showCallUi |= (InCallState.INCALL && !isActivityStarted());
// The only time that we have an instance of mInCallActivity and it isn't started is
// when it is being destroyed. In that case, lets avoid bringing up another instance of
// the activity. When it is finally destroyed, we double check if we should bring it back
// up so we aren't going to lose anything by avoiding a second startup here.
boolean activityIsFinishing = mInCallActivity != null && !isActivityStarted();
if (activityIsFinishing) {
Log.i(this, "Undo the state change: " + newState + " -> " + mInCallState);
return mInCallState;
}
if (showCallUi || showAccountPicker) {
Log.i(this, "Start in call UI");
showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
}
//如果是来电的话
- else if (startStartupSequence) {
Log.i(this, "Start Full Screen in call UI");
// We're about the bring up the in-call UI for an incoming call. If we still have
// dialogs up, we need to clear them out before showing incoming screen.
if (isActivityStarted()) {
mInCallActivity.dismissPendingDialogs();
}
if (!startUi(newState)) {
// startUI refused to start the UI. This indicates that it needed to restart the
// activity. When it finally restarts, it will call us back, so we do not actually
// change the state yet (we return mInCallState instead of newState).
return mInCallState;
}
} else if (newState == InCallState.NO_CALLS) {
// The new state is the no calls state. Tear everything down.
attemptFinishActivity();
attemptCleanup();
}
return newState;
}
startUi 创建UI
关于是全屏显示还是Heads-Up Notification 显示, 具体的判断条件我还没理清楚,如果有人知道的话,请在评论区写一下或者贴出一个链接,本人不胜感激。
private boolean startUi(InCallState inCallState) {
final Call incomingCall = mCallList.getIncomingCall();
boolean isCallWaiting = mCallList.getActiveCall() != null &&
mCallList.getIncomingCall() != null;
// If the screen is off, we need to make sure it gets turned on for incoming calls.
// This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
// when the activity is first created. Therefore, to ensure the screen is turned on
// for the call waiting case, we finish() the current activity and start a new one.
// There should be no jank from this since the screen is already off and will remain so
// until our new activity is up.
// In addition to call waiting scenario, we need to force finish() in case of DSDA when
// we get an incoming call on one sub and there is a live call in other sub and screen
// is off.
boolean anyOtherSubActive = (incomingCall != null &&
mCallList.isAnyOtherSubActive(mCallList.getActiveSubscription()));
Log.i(this, "Start UI " + " anyOtherSubActive:" + anyOtherSubActive);
if (isCallWaiting || anyOtherSubActive) {
if (mProximitySensor.isScreenReallyOff() && isActivityStarted()) {
mInCallActivity.finish();
// When the activity actually finishes, we will start it again if there are
// any active calls, so we do not need to start it explicitly here. Note, we
// actually get called back on this function to restart it.
// We return false to indicate that we did not actually start the UI.
return false;
} else {
showInCall(false, false);
}
} else {
mStatusBarNotifier.updateNotification(inCallState, mCallList);
}
return true;
}
23. //pakages/apps/InCallUI/src/com/android/incallui/StatuBarNotifier.java updateNotification()
/**
* Updates the phone app's status bar notification *and* launches the
* incoming call UI in response to a new incoming call.
*
* If an incoming call is ringing (or call-waiting), the notification
* will also include a "fullScreenIntent" that will cause the
* InCallScreen to be launched, unless the current foreground activity
* is marked as "immersive".
*
* (This is the mechanism that actually brings up the incoming call UI
* when we receive a "new ringing connection" event from the telephony
* layer.)
*
* Also note that this method is safe to call even if the phone isn't
* actually ringing (or, more likely, if an incoming call *was*
* ringing briefly but then disconnected). In that case, we'll simply
* update or cancel the in-call notification based on the current
* phone state.
*
* @see #updateInCallNotification(InCallState,CallList)
*/
public void updateNotification(InCallState state, CallList callList) {
updateInCallNotification(state, callList);
}
updateInCallNotification()
/**
* Helper method for updateInCallNotification() and
* updateNotification(): Update the phone app's
* status bar notification based on the current telephony state, or
* cancels the notification if the phone is totally idle.
*/
private void updateInCallNotification(final InCallState state, CallList callList) {
Log.d(this, "updateInCallNotification...");
Call call = getCallToShow(callList);
// Whether we have an outgoing call but the incall UI has yet to show up.
// Since we don't normally show a notification while the incall screen is
// in the foreground, if we show the outgoing notification before the activity
// comes up the user will see it flash on and off on an outgoing call. We therefore
// do not show the notification for outgoing calls before the activity has started.
boolean isOutgoingWithoutIncallUi =
state == InCallState.OUTGOING &&
!InCallPresenter.getInstance().isActivityPreviouslyStarted();
// Whether to show a notification immediately.
boolean showNotificationNow =
// We can still be in the INCALL state when a call is disconnected (in order to show
// the "Call ended" screen. So check that we have an active connection too.
(call != null) &&
// We show a notification iff there is an active call.
state.isConnectingOrConnected() &&
// If the UI is already showing, then for most cases we do not want to show
// a notification since that would be redundant, unless it is an incoming call,
// in which case the notification is actually an important alert.
(!InCallPresenter.getInstance().isShowingInCallUi() || state.isIncoming()) &&
// If we have an outgoing call with no UI but the timer has fired, we show
// a notification anyway.
(!isOutgoingWithoutIncallUi ||
mNotificationTimer.getState() == NotificationTimer.State.FIRED);
if (showNotificationNow) {
showNotification(call);
} else {
cancelInCall();
if (isOutgoingWithoutIncallUi &&
mNotificationTimer.getState() == NotificationTimer.State.CLEAR) {
mNotificationTimer.schedule();
}
}
// If we see a UI, or we are done with calls for now, reset to ground state.
if (InCallPresenter.getInstance().isShowingInCallUi() || call == null) {
mNotificationTimer.clear();
}
}
private void showNotification(final Call call) {
final boolean isIncoming = (call.getState() == Call.State.INCOMING ||
call.getState() == Call.State.CALL_WAITING);
// we make a call to the contact info cache to query for supplemental data to what the
// call provides. This includes the contact name and photo.
// This callback will always get called immediately and synchronously with whatever data
// it has available, and may make a subsequent call later (same thread) if it had to
// call into the contacts provider for more data.
mContactInfoCache.findInfo(call, isIncoming, new ContactInfoCacheCallback() {
@Override
public void onContactInfoComplete(String callId, ContactCacheEntry entry) {
Call call = CallList.getInstance().getCallById(callId);
if (call != null) {
buildAndSendNotification(call, entry);
}
}
@Override
public void onImageLoadComplete(String callId, ContactCacheEntry entry) {
Call call = CallList.getInstance().getCallById(callId);
if (call != null) {
buildAndSendNotification(call, entry);
}
}
});
}
/**
* Sets up the main Ui for the notification
*/
private void buildAndSendNotification(Call originalCall, ContactCacheEntry contactInfo) {
// This can get called to update an existing notification after contact information has come
// back. However, it can happen much later. Before we continue, we need to make sure that
// the call being passed in is still the one we want to show in the notification.
final Call call = getCallToShow(CallList.getInstance());
if (call == null || !call.getId().equals(originalCall.getId())) {
return;
}
final int state = call.getState();
final boolean isConference = call.isConferenceCall();
final boolean isVideoUpgradeRequest = call.getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
// Check if data has changed; if nothing is different, don't issue another notification.
final int iconResId = getIconToDisplay(call);
final Bitmap largeIcon = getLargeIconToDisplay(contactInfo, isConference);
final int contentResId = getContentString(call);
final String contentTitle = getContentTitle(contactInfo, isConference);
if (!checkForChangeAndSaveData(iconResId, contentResId, largeIcon, contentTitle, state)) {
return;
}
/*
* Nothing more to check...build and send it.
*/
final Notification.Builder builder = getNotificationBuilder();
// Set up the main intent to send the user to the in-call screen
final PendingIntent inCallPendingIntent = createLaunchPendingIntent();
builder.setContentIntent(inCallPendingIntent);
// Set the intent as a full screen intent as well if a call is incoming
if ((state == Call.State.INCOMING || state == Call.State.CALL_WAITING) &&
!InCallPresenter.getInstance().isShowingInCallUi()) {
configureFullScreenIntent(builder, inCallPendingIntent, call);
}
// Set the content
builder.setContentText(mContext.getString(contentResId));
builder.setSmallIcon(iconResId);
builder.setContentTitle(contentTitle);
builder.setLargeIcon(largeIcon);
builder.setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
if (isVideoUpgradeRequest) {
builder.setUsesChronometer(false);
addDismissUpgradeRequestAction(builder);
addAcceptUpgradeRequestAction(builder);
} else {
createIncomingCallNotification(call, state, builder);
}
addPersonReference(builder, contactInfo, call);
/*
* Fire off the notification // 发射通知!!
*/
Notification notification = builder.build();
Log.d(this, "Notifying IN_CALL_NOTIFICATION: " + notification);
mNotificationManager.notify(IN_CALL_NOTIFICATION, notification);
mIsShowingNotification = true;
}
上面两个方法都要执行,一个是创建通知 一个是启动通知
1.创建通知
createIncomingCallNotification
private void createIncomingCallNotification(
Call call, int state, Notification.Builder builder) {
if (state == Call.State.ACTIVE) {
builder.setUsesChronometer(true);
builder.setWhen(call.getConnectTimeMillis());
} else {
builder.setUsesChronometer(false);
}
// Add hang up option for any active calls (active | onhold), outgoing calls (dialing).
if (state == Call.State.ACTIVE ||
state == Call.State.ONHOLD ||
Call.State.isDialing(state)) {
addHangupAction(builder);
} else if (state == Call.State.INCOMING || state == Call.State.CALL_WAITING) {
addDismissAction(builder);
if (call.isVideoCall(mContext)) {
addVoiceAction(builder);
addVideoCallAction(builder);
} else {
addAnswerAction(builder);
}
}
}
上面添加“接听”和“忽略”两个操作,
private void addAnswerAction(Notification.Builder builder) {
Log.i(this, "Will show \"answer\" action in the incoming call Notification");
PendingIntent answerVoicePendingIntent = createNotificationPendingIntent(
mContext, InCallApp.ACTION_ANSWER_VOICE_INCOMING_CALL);
builder.addAction(R.drawable.ic_call_white_24dp,
mContext.getText(R.string.description_target_answer),
answerVoicePendingIntent);
}
private void addDismissAction(Notification.Builder builder) {
Log.i(this, "Will show \"dismiss\" action in the incoming call Notification");
PendingIntent declinePendingIntent =
createNotificationPendingIntent(mContext, InCallApp.ACTION_DECLINE_INCOMING_CALL);
builder.addAction(R.drawable.ic_close_dk,
mContext.getText(R.string.notification_action_dismiss),
declinePendingIntent);
}
启动通知了:
NotificationManager.java
/**
* Post a notification to be shown in the status bar. If a notification with
* the same id has already been posted by your application and has not yet been canceled, it
* will be replaced by the updated information.
*
* @param id An identifier for this notification unique within your
* application.
* @param notification A {@link Notification} object describing what to show the user. Must not
* be null.
*/
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
根据下面的说明我们知道,在状态栏显示处通知
我们跟的是来电的代码,来电信息呈献给用户有两种情况:
1. 屏幕唤醒状态下 是在通知栏显示通知
2. 屏幕熄灭状态下 点亮屏幕全屏显示
==2015-05-06修改==
上面的描述不准确,评论区也有同学指出,在非熄屏但锁屏的情况下,来电也是全屏的。
这一部分的东西确实我没有理清楚,后面有时间我会搞清楚再更新这一部分的内容。
如下图所示:
<div class="L0" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); ">/**</span></code></div><div class="L1" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * Post a notification to be shown in the <span style="background-color: rgb(192, 192, 192); ">status bar</span>. If a notification with</span></code></div><div class="L2" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * the same tag and id has already been posted by your application and has not yet been</span></code></div><div class="L3" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * canceled, it will be replaced by the updated information.</span></code></div><div class="L4" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> *</span></code></div><div class="L5" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * @param tag A string identifier for this notification. May be {@code null}.</span></code></div><div class="L6" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * @param id An identifier for this notification. The pair (tag, id) must be unique</span></code></div><div class="L7" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * within your application.</span></code></div><div class="L8" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * @param notification A {@link Notification} object describing what to</span></code></div><div class="L9" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> * show the user. Must not be null.</span></code></div><div class="L0" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="com" style="color: rgb(147, 161, 161); "> */</span></code></div><div class="L1" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">public</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">void</span><span class="pln" style="color: rgb(72, 72, 76); "> notify</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">String</span><span class="pln" style="color: rgb(72, 72, 76); "> tag</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">int</span><span class="pln" style="color: rgb(72, 72, 76); "> id</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Notification</span><span class="pln" style="color: rgb(72, 72, 76); "> notification</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span></code></div><div class="L2" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L3" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">int</span><span class="pun" style="color: rgb(147, 161, 161); ">[]</span><span class="pln" style="color: rgb(72, 72, 76); "> idOut </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">new</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">int</span><span class="pun" style="color: rgb(147, 161, 161); ">[</span><span class="lit" style="color: rgb(25, 95, 145); ">1</span><span class="pun" style="color: rgb(147, 161, 161); ">];</span></code></div><div class="L4" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">INotificationManager</span><span class="pln" style="color: rgb(72, 72, 76); "> service </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> getService</span><span class="pun" style="color: rgb(147, 161, 161); ">();</span></code></div><div class="L5" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">String</span><span class="pln" style="color: rgb(72, 72, 76); "> pkg </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> mContext</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getPackageName</span><span class="pun" style="color: rgb(147, 161, 161); ">();</span></code></div><div class="L6" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">notification</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">sound </span><span class="pun" style="color: rgb(147, 161, 161); ">!=</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">null</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L7" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> notification</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">sound </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> notification</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">sound</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getCanonicalUri</span><span class="pun" style="color: rgb(147, 161, 161); ">();</span></code></div><div class="L8" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">StrictMode</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">vmFileUriExposureEnabled</span><span class="pun" style="color: rgb(147, 161, 161); ">())</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L9" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> notification</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">sound</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">checkFileUriExposed</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="str" style="color: rgb(221, 17, 68); ">"Notification.sound"</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L0" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L1" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L2" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">localLOGV</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">v</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">TAG</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> pkg </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">": notify("</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> id </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">", "</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> notification </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">")"</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L3" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Notification</span><span class="pln" style="color: rgb(72, 72, 76); "> stripped </span><span class="pun" style="color: rgb(147, 161, 161); ">=</span><span class="pln" style="color: rgb(72, 72, 76); "> notification</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">clone</span><span class="pun" style="color: rgb(147, 161, 161); ">();</span></code></div><div class="L4" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Builder</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">stripForDelivery</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">stripped</span><span class="pun" style="color: rgb(147, 161, 161); ">);</span></code></div><div class="L5" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">try</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L6" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> service</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">enqueueNotificationWithTag</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">pkg</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> mContext</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">getOpPackageName</span><span class="pun" style="color: rgb(147, 161, 161); ">(),</span><span class="pln" style="color: rgb(72, 72, 76); "> tag</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> id</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span></code></div><div class="L7" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> stripped</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> idOut</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">UserHandle</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">myUserId</span><span class="pun" style="color: rgb(147, 161, 161); ">());</span></code></div><div class="L8" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">if</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">id </span><span class="pun" style="color: rgb(147, 161, 161); ">!=</span><span class="pln" style="color: rgb(72, 72, 76); "> idOut</span><span class="pun" style="color: rgb(147, 161, 161); ">[</span><span class="lit" style="color: rgb(25, 95, 145); ">0</span><span class="pun" style="color: rgb(147, 161, 161); ">])</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L9" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="typ" style="color: teal; ">Log</span><span class="pun" style="color: rgb(147, 161, 161); ">.</span><span class="pln" style="color: rgb(72, 72, 76); ">w</span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="pln" style="color: rgb(72, 72, 76); ">TAG</span><span class="pun" style="color: rgb(147, 161, 161); ">,</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">"notify: id corrupted: sent "</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> id </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="str" style="color: rgb(221, 17, 68); ">", got back "</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">+</span><span class="pln" style="color: rgb(72, 72, 76); "> idOut</span><span class="pun" style="color: rgb(147, 161, 161); ">[</span><span class="lit" style="color: rgb(25, 95, 145); ">0</span><span class="pun" style="color: rgb(147, 161, 161); ">]);</span></code></div><div class="L0" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L1" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="kwd" style="color: rgb(30, 52, 123); ">catch</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">(</span><span class="typ" style="color: teal; ">RemoteException</span><span class="pln" style="color: rgb(72, 72, 76); "> e</span><span class="pun" style="color: rgb(147, 161, 161); ">)</span><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">{</span></code></div><div class="L2" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div><div class="L3" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(247, 247, 249); color: rgb(190, 190, 197); line-height: 18px; padding-left: 0px; list-style-type: none; "><code class="language-java" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; word-wrap: break-word; "><span class="pln" style="color: rgb(72, 72, 76); "> </span><span class="pun" style="color: rgb(147, 161, 161); ">}</span></code></div>
这篇关于Android 5.0 Lollipop MT流程 代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!