SystemUI之狀態欄notification icon加載流程

引言

今天咱們主要講的是SystemUI狀態欄裏面另外一個常見的icons——notification icons,該icons主要用於顯示app或者framework發送的各類notification icon,表示當前有新的通知來了,須要下拉通知欄進行查看,以達到提示用戶的目的。java

正文

本文主要從兩個方面講述下notification icon功能,主要分爲初始化流程和通知icon顯示流程
話很少說,咱們開始吧。android

初始化流程app

首先咱們看下狀態欄的佈局文件 status_bar.xmlasync

<!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
             PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/notification_icon_area"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" />

        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            >

咱們今天講的notification icons就是這個 android:id="@+id/notification_icon_area" 了。
一樣它最外層是一個AlphaOptimizedFrameLayout控件,前文已經說過相似的了,
SystemUI之狀態欄status icon加載流程
該控件實現了hasOverlappingRendering()方法,該方法用來標記當前view是否存在過分繪製。ide

接下來咱們看下SystemUI是怎麼加載這個AlphaOptimizedFrameLayout函數

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);
    }

NotificationIconAreaController.javaui

/**
     * Initializes the views that will represent the notification area.
     */
    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);
    }

如上,咱們就找到了初始化的地方,主要是經過inflate這個R.layout.notification_icon_area文件,經過addView的方式添加到了AlphaOptimizedFrameLayout,下面就是看下R.layout.notification_icon_area這個文件了this

<com.android.keyguard.AlphaOptimizedLinearLayout
    xmlns:android="http://schemas.android.com/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>
/**
 * A container for notification icons. It handles overflowing icons properly and positions them
 * correctly on the screen.
 */
public class NotificationIconContainer extends AlphaOptimizedFrameLayout {}

從備註就可以看出來,這個就是全部notification icons的父控件,全部icons最後都是添加到這裏面來的,
好了,到這裏咱們的第一部分初始化流程就講完了。spa

通知icon顯示流程

首先咱們須要看下notification生成的地方

StatusBar.java

public void onNotificationPosted(final StatusBarNotification sbn,
                final RankingMap rankingMap) {

                          if (isUpdate) {
                                updateNotification(sbn, rankingMap);
                            } else {
                                addNotification(sbn, rankingMap);
                            }
}

public void addNotification(StatusBarNotification notification, RankingMap ranking)
            throws InflationException {
        String key = notification.getKey();
        if (DEBUG) Log.d(TAG, "addNotification key=" + key);

        mNotificationData.updateRanking(ranking);
        Entry shadeEntry = createNotificationViews(notification);

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;
    }
}

層層調用以後,最後會經過entry.createIcons(mContext, sbn)生成notification icon,而後存放在NotificationData裏面,感興趣的能夠看下entry.createIcons(mContext, sbn), 該函數裏面主要生成了一個StatusBarIconView對象,這個就是最終顯示在狀態欄的icon。

notification生成的過程大體就是經過inflateViews(entry, mStackScroller)--->AsyncInflationTask處理加載而後生成ExpandableNotificationRow等的信息,最後經過StatusBar.java

@Override
    public void onAsyncInflationFinished(Entry entry) {
        mPendingNotifications.remove(entry.key);
        // If there was an async task started after the removal, we don't want to add it back to
        // the list, otherwise we might get leaks.
        boolean isNew = mNotificationData.get(entry.key) == null;
        if (isNew && !entry.row.isRemoved()) {
            addEntry(entry);
        } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
            mVisualStabilityManager.onLowPriorityUpdated(entry);
            updateNotificationShade();//  此處完成添加
        }
        entry.row.setLowPriorityStateUpdated(false);
    }

private void updateNotificationShade() {
        ................................................
        for (int i=0; i<toShow.size(); i++) {
            View v = toShow.get(i);
            if (v.getParent() == null) {
                mVisualStabilityManager.notifyViewAddition(v);
                mStackScroller.addView(v);
            }
        }
        ................................................
        // Let's also update the icons
        mNotificationIconAreaController.updateNotificationIcons(mNotificationData);//添加notification icons
}

updateNotificationShade這個函數回調完成view的添加,這個函數先是把inflate出來的通知,添加到NotificationScrollLayout裏面,而後再添加notification icon,接下來咱們就看下updateNotificationIcons裏面的邏輯了。

NotificationIconAreaController.java

private NotificationIconContainer mNotificationIcons;
/**
     * Updates the notifications with the given list of notifications to display.
     */
    public void updateNotificationIcons(NotificationData notificationData) {

        updateIconsForLayout(notificationData, entry -> entry.icon, mNotificationIcons,
                false /* showAmbient */);//  添加status bar notification icon
        updateIconsForLayout(notificationData, entry -> entry.expandedIcon, mShelfIcons,
                NotificationShelf.SHOW_AMBIENT_ICONS);//  添加 notification self icon

        applyNotificationIconsTint();
    }

主要的添加動做就在updateIconsForLayout這個函數中了

private void updateIconsForLayout(NotificationData notificationData,
            Function<NotificationData.Entry, StatusBarIconView> function,
            NotificationIconContainer hostLayout, boolean showAmbient) {

        ArrayList<StatusBarIconView> toShow = new ArrayList<>(
                mNotificationScrollLayout.getChildCount());
        // Filter out ambient notifications and notification children.
        for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
            View view = mNotificationScrollLayout.getChildAt(i);
            if (view instanceof ExpandableNotificationRow) {
                NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
                if (shouldShowNotificationIcon(ent, notificationData, showAmbient)) {
                    toShow.add(function.apply(ent));
                }
            }
        }
        ......................................
        ......................................
        ......................................
        final FrameLayout.LayoutParams params = generateIconLayoutParams();
        for (int i = 0; i < toShow.size(); i++) {
            View v = toShow.get(i);
            // The view might still be transiently added if it was just removed and added again
            hostLayout.removeTransientView(v);
            if (v.getParent() == null) {
                hostLayout.addView(v, i, params);
            }
        }

}

首先從mNotificationScrollLayout取出NotificationData,而後把NotificationData存放的StatusBarIconView取出添加到toShow裏面,最後遍歷添加到NotificationIconContainer中,這樣就完成了往NotificationIconContainer添加icon的過程。

到這裏,notification icon加載流程已經講完,後面有時間還會講下signal icon的加載流程,敬請關注。

相關文章
相關標籤/搜索