代碼流程1,、先看UI顯示,StatuBar加載 CollapsedStatusBarFragment 替換 status_bar_container(狀態(tài)欄通知顯示區(qū)域) SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java FragmentHostManager.get(mStatusBarWindow)
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
CollapsedStatusBarFragment statusBarFragment =
(CollapsedStatusBarFragment) fragment;
statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
mStatusBarView = (PhoneStatusBarView) fragment.getView();
mStatusBarView.setBar(this);
mStatusBarView.setPanel(mNotificationPanel);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setBouncerShowing(mBouncerShowing);
setAreThereNotifications();
checkBarModes();
/// M: add for plmn display feature @{
attachPlmnPlugin();
///@}
}).getFragmentManager()
.beginTransaction()
.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
CollapsedStatusBarFragment.TAG)
.commit();
statusBarFragment.initNotificationIconArea(mNotificationIconAreaController) 初始化通知欄區(qū)域,,這是我們關(guān)心的 mStatusBarView.setBar(this) 傳遞statusBar處理下拉事件 mStatusBarView.setPanel(mNotificationPanel) 傳遞 NotificationPanelView 顯示下拉UI控制 2,、跟進(jìn) CollapsedStatusBarFragment 中,先看布局文件 status_bar.xml 1,、notification_lights_out---ImageView默認(rèn)gone
2、status_bar_contents--LinearLayout
notification_icon_area--FrameLayout
system_icon_area--LinearLayout
system_icons.xml(藍(lán)牙,、wifi,、VPN、網(wǎng)卡,、SIM卡信號(hào),、飛行模式等) 電池
clock--Clock.java
3、emergency_cryptkeeper_text--ViewStub(延遲加載 緊急電話文字)
這就是我們看到的statusBar的布局,本篇只關(guān)心 notification_icon_area,,其它的以后再進(jìn)行分析,。繼續(xù)看到之前的 initNotificationIconArea() SystemUI\src\com\android\systemui\statusbar\phone\CollapsedStatusBarFragment.java public void initNotificationIconArea(NotificationIconAreaController
notificationIconAreaController) {
ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
mNotificationIconAreaInner =
notificationIconAreaController.getNotificationInnerAreaView();
if (mNotificationIconAreaInner.getParent() != null) {
((ViewGroup) mNotificationIconAreaInner.getParent())
.removeView(mNotificationIconAreaInner);
}
notificationIconArea.addView(mNotificationIconAreaInner);
// Default to showing until we know otherwise.
showNotificationIconArea(false);
}
獲取到 notification_icon_area,F(xiàn)rameLayout轉(zhuǎn)為ViewGroup,,調(diào)用 notificationIconAreaController 獲取通知要顯示的view(LinearLayout),, 如果已經(jīng)有顯示的view,通過 view 父布局將其自身remove,,然后再重新addView,。最后將 mNotificationIconAreaInner 顯示出來(設(shè)置透明度為1,visibility為VISIBLE) 可以看到 CollapsedStatusBarFragment 中定義了幾個(gè)如下的方法,。 public void hideSystemIconArea(boolean animate) {
animateHide(mSystemIconArea, animate);
}
public void showSystemIconArea(boolean animate) {
animateShow(mSystemIconArea, animate);
}
public void hideNotificationIconArea(boolean animate) {
animateHide(mNotificationIconAreaInner, animate);
}
public void showNotificationIconArea(boolean animate) {
animateShow(mNotificationIconAreaInner, animate);
}
當(dāng)狀態(tài)欄下拉時(shí),,狀態(tài)欄中的圖標(biāo)icon會(huì)慢慢的變成透明和不可見,就是通過hideSystemIconArea(true), hideNotificationIconArea(true) 3,、接下來,,我們需要跟進(jìn) getNotificationInnerAreaView()方法中看看通知欄icon對(duì)應(yīng)的容器 SystemUI\src\com\android\systemui\statusbar\phone\NotificationIconAreaController.java public View getNotificationInnerAreaView() {
return mNotificationIconArea;
}
protected void initializeNotificationAreaViews(Context context) {
reloadDimens(context);
LayoutInflater layoutInflater = LayoutInflater.from(context);
mNotificationIconArea = inflateIconArea(layoutInflater);
mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
R.id.notificationIcons);
mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
}
protected View inflateIconArea(LayoutInflater inflater) {
return inflater.inflate(R.layout.notification_icon_area, null);
}
//notification_icon_area.xml
<com.android.keyguard.AlphaOptimizedLinearLayout
xmlns:android="http://schemas./apk/res/android"
android:id="@ id/notification_icon_area_inner"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.android.systemui.statusbar.phone.NotificationIconContainer
android:id="@ id/notificationIcons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:gravity="center_vertical"
android:orientation="horizontal"/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
好了,觀察上面的代碼,,現(xiàn)在基本上已經(jīng)理清 notification_icon_area 的布局結(jié)構(gòu)了 notification_icon_area(FrameLayout) 中添加 notification_icon_area_inner(LinearLayout), 每一個(gè)通知對(duì)應(yīng)的bean為 NotificationData,,創(chuàng)建 Notification 添加到 NotificationIconContainer(FrameLayout)中 4、緊接著我們就來看下 Notification 的監(jiān)聽加載流程,,回到 statusBar 的start()中注冊(cè) NotificationListenerWithPlugins 作為系統(tǒng)service監(jiān)聽通知消息 try {
mNotificationListener.registerAsSystemService(mContext,
new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
UserHandle.USER_ALL);
} catch (RemoteException e) {
Log.e(TAG, "Unable to register notification listener", e);
}
private final NotificationListenerWithPlugins mNotificationListener =
new NotificationListenerWithPlugins() {
@Override
public void onListenerConnected() {
...... services成功啟動(dòng),,獲取當(dāng)前處于活動(dòng)狀態(tài)的通知(沒被移除的通知),添加到通知欄,,此處應(yīng)該是重啟后重新加載
}
@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
...... 收到通知消息,,添加或者修改
if (isUpdate) {
updateNotification(sbn, rankingMap);
} else {
addNotification(sbn, rankingMap);
}
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn,
final RankingMap rankingMap) {
...... 移除通知消息
if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
final String key = sbn.getKey();
mHandler.post(() -> removeNotification(key, rankingMap));
}
}
@Override
public void onNotificationRankingUpdate(final RankingMap rankingMap) {
..... 通知的排序優(yōu)先級(jí)改變,修改通知位置
if (rankingMap != null) {
RankingMap r = onPluginRankingUpdate(rankingMap);
mHandler.post(() -> updateNotificationRanking(r));
}
}
};
繼續(xù)來看下 addNotification()方法 public void addNotification(StatusBarNotification notification, RankingMap ranking)
throws InflationException {
String key = notification.getKey();
if (true/**DEBUG*/) Log.d(TAG, "addNotification key=" key);
mNotificationData.updateRanking(ranking);
Entry shadeEntry = createNotificationViews(notification);
......
}
可以看到是通過 createNotificationViews()來創(chuàng)建通知 View對(duì)象,,內(nèi)部繼續(xù)調(diào)用 inflateViews() protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
throws InflationException {
if (DEBUG) {
Log.d(TAG, "createNotificationViews(notification=" sbn);
}
NotificationData.Entry entry = new NotificationData.Entry(sbn);
Dependency.get(LeakDetector.class).trackInstance(entry);
entry.createIcons(mContext, sbn);
// Construct the expanded view.
inflateViews(entry, mStackScroller);
return entry;
}
protected void inflateViews(Entry entry, ViewGroup parent) {
PackageManager pmUser = getPackageManagerForUser(mContext,
entry.notification.getUser().getIdentifier());
final StatusBarNotification sbn = entry.notification;
if (entry.row != null) {
entry.reset();
updateNotification(entry, pmUser, sbn, entry.row);
} else {
new RowInflaterTask().inflate(mContext, parent, entry,
row -> {
bindRow(entry, pmUser, sbn, row);
updateNotification(entry, pmUser, sbn, row);
});
}
}
看到上面的方法中,,entry在 createNotificationViews 中創(chuàng)建,只賦值了icons,, entry.row 為null,,進(jìn)入 RowInflaterTask 中 SystemUI\src\com\android\systemui\statusbar\notification\RowInflaterTask.java public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
RowInflationFinishedListener listener) {
mListener = listener;
AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
mEntry = entry;
entry.setInflationTask(this);
inflater.inflate(R.layout.status_bar_notification_row, parent, this);
}
這里我們得到了 Notification 對(duì)應(yīng)的layout為 status_bar_notification_row.xml, 回調(diào)方法中將 row 和 entry 綁定,,繼續(xù)再調(diào)用 updateNotification(),,注意這個(gè)方法是四個(gè)參數(shù)的,該類中還有重載方法是兩個(gè)參數(shù)的,。 private void updateNotification(Entry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
.....
entry.row = row;
entry.row.setOnActivatedListener(this);
boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
mNotificationData.getImportance(sbn.getKey()));
boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
row.updateNotification(entry);
}
緊接著調(diào)用了 ExpandableNotificationRow的 updateNotification(),,內(nèi)部繼續(xù)調(diào)用 NotificationInflater.inflateNotificationViews() SystemUI\src\com\android\systemui\statusbar\notification\NotificationInflater.java @VisibleForTesting
void inflateNotificationViews(int reInflateFlags) {
if (mRow.isRemoved()) {
// We don't want to reinflate anything for removed notifications. Otherwise views might
// be readded to the stack, leading to leaks. This may happen with low-priority groups
// where the removal of already removed children can lead to a reinflation.
return;
}
StatusBarNotification sbn = mRow.getEntry().notification;
new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,
mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
mCallback, mRemoteViewClickHandler).execute();
}
new AsyncInflationTask().execute(); @Override
protected InflationProgress doInBackground(Void... params) {
try {
final Notification.Builder recoveredBuilder
= Notification.Builder.recoverBuilder(mContext,
mSbn.getNotification());
Context packageContext = mSbn.getPackageContext(mContext);
Notification notification = mSbn.getNotification();
if (mIsLowPriority) {
int backgroundColor = mContext.getColor(
R.color.notification_material_background_low_priority_color);
recoveredBuilder.setBackgroundColorHint(backgroundColor);
}
if (notification.isMediaNotification()) {
MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
packageContext);
processor.setIsLowPriority(mIsLowPriority);
processor.processNotification(notification, recoveredBuilder);
}
return createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsLowPriority, mIsChildInGroup,
mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
packageContext);
} catch (Exception e) {
mError = e;
return null;
}
}
@Override
protected void onPostExecute(InflationProgress result) {
if (mError == null) {
mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbient,
mRemoteViewClickHandler, this);
} else {
handleError(mError);
}
}
從msbn中獲取 notifaction,判斷是否是媒體類型的通知,,進(jìn)行對(duì)應(yīng)的主題背景色修改,,通過傳遞的優(yōu)先級(jí)設(shè)置通知背景色,繼續(xù)看核心方法 createRemoteViews() private static InflationProgress createRemoteViews(int reInflateFlags,
Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
Context packageContext) {
InflationProgress result = new InflationProgress();
isLowPriority = isLowPriority && !isChildInGroup;
if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
}
if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
result.newExpandedView = createExpandedView(builder, isLowPriority);
}
if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
}
if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
result.newPublicView = builder.makePublicContentView();
}
if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
: builder.makeAmbientNotification();
}
result.packageContext = packageContext;
return result;
}
這里就是創(chuàng)建各種布局 CONTENT_VIEW、EXPANDED_VIEW,、HEADS_UP_VIEW,、PUBLIC_VIEW、AMBIENT_VIEW,, 然后回到 AsyncInflationTask 的 onPostExecute()中執(zhí)行 apply(),代碼太多就不貼了, SystemUI部分的通知流程分析技術(shù),,歡迎留言討論。 statusBar左邊區(qū)域(notification_icon_area)看完了,,接下來看下右邊的系統(tǒng)圖標(biāo)區(qū)域(system_icon_area) Android8.1 SystemUI源碼分析之 電池時(shí)鐘刷新
|