incall发起notification后,由systemui根据当前手机状态,来决定是显示来电界面还是headsup小窗口。
- package/app/Dialer -- InCallPresenter
接着上篇文章,从onIncomingCall开始查看:
@Override public void onIncomingCall(Call call) { InCallState newState = startOrFinishUi(InCallState.INCOMING); for (IncomingCallListener listener : mIncomingCallListeners) { listener.onIncomingCall(oldState, mInCallState, call); } }
关注startOrFinishUi方法,若是满足直接显示UI的条件调用showInCall,直接启动UI;否则调用startUi:
private InCallState startOrFinishUi(InCallState newState) { if (showCallUi || showAccountPicker || isAutoAnswer) { showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */); } else if (startIncomingCallSequence) { if (!startUi(newState)) { return mInCallState; } } }
调用StatusBarNotifier.updateNotification:
private boolean startUi(InCallState inCallState) { if (isCallWaiting || anyOtherSubActive) { if (mProximitySensor.isScreenReallyOff() && isActivityStarted()) { mInCallActivity.finish(); return false; } else { showInCall(false, false); } } else { mStatusBarNotifier.updateNotification(inCallState, mCallList); } return true; }
- package/app/Dialer -- StatusBarNotifier
incall发起通知,后续由notification决定是显示小窗口还是来电界面:
private void buildAndSendNotification(Call originalCall, ContactCacheEntry contactInfo) { Notification.Builder publicBuilder = new Notification.Builder(mContext); final PendingIntent inCallPendingIntent = createLaunchPendingIntent(); if (notificationType == NOTIFICATION_INCOMING_CALL && (!InCallPresenter.getInstance().isShowingInCallUi() || (pendingAccountSelectionCall != null))) { configureFullScreenIntent(builder, inCallPendingIntent, call); } Notification notification = builder.build(); mNotificationManager.notify(notificationType, notification); }
configureFullScreenIntent方法:
private void configureFullScreenIntent(Notification.Builder builder, PendingIntent intent,
Call call) { // Ok, we actually want to launch the incoming call // UI at this point (in addition to simply posting a notification // to the status bar). Setting fullScreenIntent will cause // the InCallScreen to be launched immediately *unless* the // current foreground activity is marked as "immersive". builder.setFullScreenIntent(intent, true); }
携带intent来启动InCallActivity:
private PendingIntent createLaunchPendingIntent() { final Intent intent = InCallPresenter.getInstance().getInCallIntent( false /* showDialpad */, false /* newOutgoingCall */); // PendingIntent that can be used to launch the InCallActivity. The // system fires off this intent if the user pulls down the windowshade // and clicks the notification's expanded view. It's also used to // launch the InCallActivity immediately when when there's an incoming // call (see the "fullScreenIntent" field below). PendingIntent inCallPendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0); return inCallPendingIntent; }
- frameworks/base/core -- NotificationManager
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user) { INotificationManager service = getService(); try { service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, copy, idOut, user.getIdentifier()); } }
- frameworks/base/core -- NotificationManagerService
找到INotificationManager aidl实现enqueueNotificationWithTag方法的地方:
private final IBinder mService = new INotificationManager.Stub() { @Override public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, Notification notification, int[] idOut, int userId) throws RemoteException { enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), tag, id, notification, idOut, userId); }
- frameworks/base/packages/SystemUI -- BaseStatusBar
private final NotificationListenerService mNotificationListener = new NotificationListenerService() { @Override public void onNotificationPosted(final StatusBarNotification sbn, final RankingMap rankingMap) { if (sbn != null) { mHandler.post(new Runnable() { @Override public void run() { if (isUpdate) { updateNotification(sbn, rankingMap); } else { addNotification(sbn, rankingMap, null /* oldEntry */); } } });
- frameworks/base/packages/SystemUI -- PhoneStatusBar
isHeadsUped决定是显示headsup还是来电界面:
@Override public void addNotification(StatusBarNotification notification, RankingMap ranking, Entry oldEntry) { boolean isHeadsUped = shouldPeek(shadeEntry); if (isHeadsUped) { mHeadsUpManager.showNotification(shadeEntry); setNotificationShown(notification); } if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) { try { notification.getNotification().fullScreenIntent.send(); shadeEntry.notifyFullScreenIntentLaunched(); }