Home | History | Annotate | Download | only in phone
      1 package com.android.systemui.statusbar.phone;
      2 
      3 import android.content.Context;
      4 import android.content.res.ColorStateList;
      5 import android.content.res.Resources;
      6 import android.graphics.Color;
      7 import android.graphics.Rect;
      8 import android.support.annotation.NonNull;
      9 import android.view.LayoutInflater;
     10 import android.view.View;
     11 import android.widget.ImageView;
     12 import android.widget.LinearLayout;
     13 
     14 import com.android.internal.util.NotificationColorUtil;
     15 import com.android.systemui.R;
     16 import com.android.systemui.statusbar.NotificationData;
     17 import com.android.systemui.statusbar.StatusBarIconView;
     18 import com.android.systemui.statusbar.notification.NotificationUtils;
     19 
     20 import 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  */
     26 public 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