NotificationIconAreaController.java revision 3e7592d0cbbde5b0b85d98b82d991ee5d2aab8a9
1package com.android.systemui.statusbar.phone;
2
3import android.content.Context;
4import android.content.res.ColorStateList;
5import android.content.res.Resources;
6import android.graphics.Color;
7import android.graphics.Rect;
8import android.support.annotation.NonNull;
9import android.view.LayoutInflater;
10import android.view.View;
11import android.widget.ImageView;
12import android.widget.LinearLayout;
13
14import com.android.internal.util.NotificationColorUtil;
15import com.android.systemui.R;
16import com.android.systemui.statusbar.NotificationData;
17import com.android.systemui.statusbar.StatusBarIconView;
18import com.android.systemui.statusbar.notification.NotificationUtils;
19
20import java.util.ArrayList;
21
22/**
23 * A controller for the space in the status bar to the left of the system icons. This area is
24 * normally reserved for notifications.
25 */
26public class NotificationIconAreaController {
27    private final NotificationColorUtil mNotificationColorUtil;
28
29    private int mIconSize;
30    private int mIconHPadding;
31    private int mIconTint = Color.WHITE;
32
33    private PhoneStatusBar mPhoneStatusBar;
34    protected View mNotificationIconArea;
35    private IconMerger mNotificationIcons;
36    private ImageView mMoreIcon;
37    private final Rect mTintArea = new Rect();
38
39    public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
40        mPhoneStatusBar = phoneStatusBar;
41        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
42
43        initializeNotificationAreaViews(context);
44    }
45
46    protected View inflateIconArea(LayoutInflater inflater) {
47        return inflater.inflate(R.layout.notification_icon_area, null);
48    }
49
50    /**
51     * Initializes the views that will represent the notification area.
52     */
53    protected void initializeNotificationAreaViews(Context context) {
54        reloadDimens(context);
55
56        LayoutInflater layoutInflater = LayoutInflater.from(context);
57        mNotificationIconArea = inflateIconArea(layoutInflater);
58
59        mNotificationIcons =
60                (IconMerger) mNotificationIconArea.findViewById(R.id.notificationIcons);
61
62        mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
63        if (mMoreIcon != null) {
64            mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
65            mNotificationIcons.setOverflowIndicator(mMoreIcon);
66        }
67    }
68
69    public void onDensityOrFontScaleChanged(Context context) {
70        reloadDimens(context);
71        final LinearLayout.LayoutParams params = generateIconLayoutParams();
72        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
73            View child = mNotificationIcons.getChildAt(i);
74            child.setLayoutParams(params);
75        }
76    }
77
78    @NonNull
79    private LinearLayout.LayoutParams generateIconLayoutParams() {
80        return new LinearLayout.LayoutParams(
81                mIconSize + 2 * mIconHPadding, getHeight());
82    }
83
84    private void reloadDimens(Context context) {
85        Resources res = context.getResources();
86        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
87        mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
88    }
89
90    /**
91     * Returns the view that represents the notification area.
92     */
93    public View getNotificationInnerAreaView() {
94        return mNotificationIconArea;
95    }
96
97    /**
98     * See {@link StatusBarIconController#setIconsDarkArea}.
99     *
100     * @param tintArea the area in which to tint the icons, specified in screen coordinates
101     */
102    public void setTintArea(Rect tintArea) {
103        if (tintArea == null) {
104            mTintArea.setEmpty();
105        } else {
106            mTintArea.set(tintArea);
107        }
108        applyNotificationIconsTint();
109    }
110
111    /**
112     * Sets the color that should be used to tint any icons in the notification area. If this
113     * method is not called, the default tint is {@link Color#WHITE}.
114     */
115    public void setIconTint(int iconTint) {
116        mIconTint = iconTint;
117        if (mMoreIcon != null) {
118            mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
119        }
120        applyNotificationIconsTint();
121    }
122
123    protected int getHeight() {
124        return mPhoneStatusBar.getStatusBarHeight();
125    }
126
127    protected boolean shouldShowNotification(NotificationData.Entry entry,
128            NotificationData notificationData) {
129        if (notificationData.isAmbient(entry.key)
130                && !NotificationData.showNotificationEvenIfUnprovisioned(entry.notification)) {
131            return false;
132        }
133        if (!PhoneStatusBar.isTopLevelChild(entry)) {
134            return false;
135        }
136        if (entry.row.getVisibility() == View.GONE) {
137            return false;
138        }
139
140        return true;
141    }
142
143    /**
144     * Updates the notifications with the given list of notifications to display.
145     */
146    public void updateNotificationIcons(NotificationData notificationData) {
147        final LinearLayout.LayoutParams params = generateIconLayoutParams();
148
149        ArrayList<NotificationData.Entry> activeNotifications =
150                notificationData.getActiveNotifications();
151        final int size = activeNotifications.size();
152        ArrayList<StatusBarIconView> toShow = new ArrayList<>(size);
153
154        // Filter out ambient notifications and notification children.
155        for (int i = 0; i < size; i++) {
156            NotificationData.Entry ent = activeNotifications.get(i);
157            if (shouldShowNotification(ent, notificationData)) {
158                toShow.add(ent.icon);
159            }
160        }
161
162        ArrayList<View> toRemove = new ArrayList<>();
163        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
164            View child = mNotificationIcons.getChildAt(i);
165            if (!toShow.contains(child)) {
166                toRemove.add(child);
167            }
168        }
169
170        final int toRemoveCount = toRemove.size();
171        for (int i = 0; i < toRemoveCount; i++) {
172            mNotificationIcons.removeView(toRemove.get(i));
173        }
174
175        for (int i = 0; i < toShow.size(); i++) {
176            View v = toShow.get(i);
177            if (v.getParent() == null) {
178                mNotificationIcons.addView(v, i, params);
179            }
180        }
181
182        // Re-sort notification icons
183        final int childCount = mNotificationIcons.getChildCount();
184        for (int i = 0; i < childCount; i++) {
185            View actual = mNotificationIcons.getChildAt(i);
186            StatusBarIconView expected = toShow.get(i);
187            if (actual == expected) {
188                continue;
189            }
190            mNotificationIcons.removeView(expected);
191            mNotificationIcons.addView(expected, i);
192        }
193
194        applyNotificationIconsTint();
195    }
196
197    /**
198     * Applies {@link #mIconTint} to the notification icons.
199     */
200    private void applyNotificationIconsTint() {
201        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
202            StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
203            boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
204            boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
205            if (colorize) {
206                v.setImageTintList(ColorStateList.valueOf(
207                        StatusBarIconController.getTint(mTintArea, v, mIconTint)));
208            }
209        }
210    }
211}
212