| package com.android.systemui.statusbar.phone; |
| |
| import android.content.Context; |
| import android.content.res.ColorStateList; |
| import android.content.res.Resources; |
| import android.graphics.Color; |
| import android.graphics.Rect; |
| import android.support.annotation.NonNull; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.widget.FrameLayout; |
| |
| import com.android.internal.util.NotificationColorUtil; |
| import com.android.systemui.R; |
| import com.android.systemui.statusbar.ExpandableNotificationRow; |
| import com.android.systemui.statusbar.NotificationData; |
| import com.android.systemui.statusbar.NotificationShelf; |
| import com.android.systemui.statusbar.StatusBarIconView; |
| import com.android.systemui.statusbar.notification.NotificationUtils; |
| import com.android.systemui.statusbar.policy.DarkIconDispatcher; |
| import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; |
| import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; |
| |
| import java.util.ArrayList; |
| import java.util.function.Function; |
| |
| /** |
| * A controller for the space in the status bar to the left of the system icons. This area is |
| * normally reserved for notifications. |
| */ |
| public class NotificationIconAreaController implements DarkReceiver { |
| private final NotificationColorUtil mNotificationColorUtil; |
| |
| private int mIconSize; |
| private int mIconHPadding; |
| private int mIconTint = Color.WHITE; |
| |
| private StatusBar mStatusBar; |
| protected View mNotificationIconArea; |
| private NotificationIconContainer mNotificationIcons; |
| private NotificationIconContainer mShelfIcons; |
| private final Rect mTintArea = new Rect(); |
| private NotificationStackScrollLayout mNotificationScrollLayout; |
| private Context mContext; |
| |
| public NotificationIconAreaController(Context context, StatusBar statusBar) { |
| mStatusBar = statusBar; |
| mNotificationColorUtil = NotificationColorUtil.getInstance(context); |
| mContext = context; |
| |
| initializeNotificationAreaViews(context); |
| } |
| |
| protected View inflateIconArea(LayoutInflater inflater) { |
| return inflater.inflate(R.layout.notification_icon_area, null); |
| } |
| |
| /** |
| * 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(); |
| } |
| |
| public void setupShelf(NotificationShelf shelf) { |
| mShelfIcons = shelf.getShelfIcons(); |
| shelf.setCollapsedIcons(mNotificationIcons); |
| } |
| |
| public void onDensityOrFontScaleChanged(Context context) { |
| reloadDimens(context); |
| final FrameLayout.LayoutParams params = generateIconLayoutParams(); |
| for (int i = 0; i < mNotificationIcons.getChildCount(); i++) { |
| View child = mNotificationIcons.getChildAt(i); |
| child.setLayoutParams(params); |
| child = mShelfIcons.getChildAt(i); |
| child.setLayoutParams(params); |
| } |
| } |
| |
| @NonNull |
| private FrameLayout.LayoutParams generateIconLayoutParams() { |
| return new FrameLayout.LayoutParams( |
| mIconSize + 2 * mIconHPadding, getHeight()); |
| } |
| |
| private void reloadDimens(Context context) { |
| Resources res = context.getResources(); |
| mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); |
| mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding); |
| } |
| |
| /** |
| * Returns the view that represents the notification area. |
| */ |
| public View getNotificationInnerAreaView() { |
| return mNotificationIconArea; |
| } |
| |
| /** |
| * See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}. |
| * Sets the color that should be used to tint any icons in the notification area. |
| * |
| * @param tintArea the area in which to tint the icons, specified in screen coordinates |
| * @param darkIntensity |
| */ |
| public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) { |
| if (tintArea == null) { |
| mTintArea.setEmpty(); |
| } else { |
| mTintArea.set(tintArea); |
| } |
| mIconTint = iconTint; |
| applyNotificationIconsTint(); |
| } |
| |
| protected int getHeight() { |
| return mStatusBar.getStatusBarHeight(); |
| } |
| |
| protected boolean shouldShowNotificationIcon(NotificationData.Entry entry, |
| NotificationData notificationData, boolean showAmbient) { |
| if (notificationData.isAmbient(entry.key) && !showAmbient |
| && !NotificationData.showNotificationEvenIfUnprovisioned(entry.notification)) { |
| return false; |
| } |
| if (!StatusBar.isTopLevelChild(entry)) { |
| return false; |
| } |
| if (entry.row.getVisibility() == View.GONE) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Updates the notifications with the given list of notifications to display. |
| */ |
| public void updateNotificationIcons(NotificationData notificationData) { |
| |
| updateIconsForLayout(notificationData, entry -> entry.icon, mNotificationIcons, |
| false /* showAmbient */); |
| updateIconsForLayout(notificationData, entry -> entry.expandedIcon, mShelfIcons, |
| NotificationShelf.SHOW_AMBIENT_ICONS); |
| |
| applyNotificationIconsTint(); |
| } |
| |
| /** |
| * Updates the notification icons for a host layout. This will ensure that the notification |
| * host layout will have the same icons like the ones in here. |
| * |
| * @param notificationData the notification data to look up which notifications are relevant |
| * @param function A function to look up an icon view based on an entry |
| * @param hostLayout which layout should be updated |
| * @param showAmbient should ambient notification icons be shown |
| */ |
| 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)); |
| } |
| } |
| } |
| |
| |
| ArrayList<View> toRemove = new ArrayList<>(); |
| for (int i = 0; i < hostLayout.getChildCount(); i++) { |
| View child = hostLayout.getChildAt(i); |
| if (!toShow.contains(child)) { |
| toRemove.add(child); |
| } |
| } |
| |
| final int toRemoveCount = toRemove.size(); |
| for (int i = 0; i < toRemoveCount; i++) { |
| hostLayout.removeView(toRemove.get(i)); |
| } |
| |
| 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); |
| } |
| } |
| |
| hostLayout.setChangingViewPositions(true); |
| // Re-sort notification icons |
| final int childCount = hostLayout.getChildCount(); |
| for (int i = 0; i < childCount; i++) { |
| View actual = hostLayout.getChildAt(i); |
| StatusBarIconView expected = toShow.get(i); |
| if (actual == expected) { |
| continue; |
| } |
| hostLayout.removeView(expected); |
| hostLayout.addView(expected, i); |
| } |
| hostLayout.setChangingViewPositions(false); |
| } |
| |
| /** |
| * Applies {@link #mIconTint} to the notification icons. |
| */ |
| private void applyNotificationIconsTint() { |
| for (int i = 0; i < mNotificationIcons.getChildCount(); i++) { |
| StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i); |
| boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L)); |
| boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil); |
| if (colorize) { |
| v.setImageTintList(ColorStateList.valueOf( |
| DarkIconDispatcher.getTint(mTintArea, v, mIconTint))); |
| } |
| v.setIconTint(mIconTint); |
| } |
| } |
| } |