1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.notification; 18 19 import android.animation.AnimatorSet; 20 import android.content.Context; 21 import android.graphics.Outline; 22 import android.graphics.Rect; 23 import android.view.MotionEvent; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.view.ViewGroup.MarginLayoutParams; 27 import android.view.ViewOutlineProvider; 28 import android.widget.TextView; 29 30 import com.android.launcher3.R; 31 import com.android.launcher3.popup.PopupContainerWithArrow; 32 import com.android.launcher3.util.Themes; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 /** 38 * Utility class to manage notification UI 39 */ 40 public class NotificationItemView { 41 42 private static final Rect sTempRect = new Rect(); 43 44 private final Context mContext; 45 private final PopupContainerWithArrow mPopupContainer; 46 private final ViewGroup mRootView; 47 48 private final TextView mHeaderCount; 49 private final NotificationMainView mMainView; 50 51 private final View mHeader; 52 53 private View mGutter; 54 55 private boolean mIgnoreTouch = false; 56 private List<NotificationInfo> mNotificationInfos = new ArrayList<>(); 57 NotificationItemView(PopupContainerWithArrow container, ViewGroup rootView)58 public NotificationItemView(PopupContainerWithArrow container, ViewGroup rootView) { 59 mPopupContainer = container; 60 mRootView = rootView; 61 mContext = container.getContext(); 62 63 mHeaderCount = container.findViewById(R.id.notification_count); 64 mMainView = container.findViewById(R.id.main_view); 65 66 mHeader = container.findViewById(R.id.header); 67 68 float radius = Themes.getDialogCornerRadius(mContext); 69 rootView.setClipToOutline(true); 70 rootView.setOutlineProvider(new ViewOutlineProvider() { 71 @Override 72 public void getOutline(View view, Outline outline) { 73 outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius); 74 } 75 }); 76 } 77 78 /** 79 * Animates the background color to a new color. 80 * @param color The color to change to. 81 * @param animatorSetOut The AnimatorSet where we add the color animator to. 82 */ updateBackgroundColor(int color, AnimatorSet animatorSetOut)83 public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) { 84 mMainView.updateBackgroundColor(color, animatorSetOut); 85 } 86 addGutter()87 public void addGutter() { 88 if (mGutter == null) { 89 mGutter = mPopupContainer.inflateAndAdd(R.layout.notification_gutter, mRootView); 90 } 91 } 92 inverseGutterMargin()93 public void inverseGutterMargin() { 94 MarginLayoutParams lp = (MarginLayoutParams) mGutter.getLayoutParams(); 95 int top = lp.topMargin; 96 lp.topMargin = lp.bottomMargin; 97 lp.bottomMargin = top; 98 } 99 removeAllViews()100 public void removeAllViews() { 101 mRootView.removeView(mMainView); 102 mRootView.removeView(mHeader); 103 if (mGutter != null) { 104 mRootView.removeView(mGutter); 105 } 106 } 107 108 /** 109 * Updates the header text. 110 * @param notificationCount The number of notifications. 111 */ updateHeader(int notificationCount)112 public void updateHeader(int notificationCount) { 113 final String text; 114 final int visibility; 115 if (notificationCount <= 1) { 116 text = ""; 117 visibility = View.INVISIBLE; 118 } else { 119 text = String.valueOf(notificationCount); 120 visibility = View.VISIBLE; 121 122 } 123 mHeaderCount.setText(text); 124 mHeaderCount.setVisibility(visibility); 125 } 126 onInterceptTouchEvent(MotionEvent ev)127 public boolean onInterceptTouchEvent(MotionEvent ev) { 128 if (ev.getAction() == MotionEvent.ACTION_DOWN) { 129 sTempRect.set(mRootView.getLeft(), mRootView.getTop(), 130 mRootView.getRight(), mRootView.getBottom()); 131 mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY()); 132 if (!mIgnoreTouch) { 133 mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true); 134 } 135 } 136 if (mIgnoreTouch) { 137 return false; 138 } 139 if (mMainView.getNotificationInfo() == null) { 140 // The notification hasn't been populated yet. 141 return false; 142 } 143 144 return false; 145 } 146 applyNotificationInfos(final List<NotificationInfo> notificationInfos)147 public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) { 148 mNotificationInfos.clear(); 149 if (notificationInfos.isEmpty()) { 150 return; 151 } 152 mNotificationInfos.addAll(notificationInfos); 153 154 NotificationInfo mainNotification = notificationInfos.get(0); 155 mMainView.applyNotificationInfo(mainNotification, false); 156 } 157 trimNotifications(final List<String> notificationKeys)158 public void trimNotifications(final List<String> notificationKeys) { 159 NotificationInfo currentMainNotificationInfo = mMainView.getNotificationInfo(); 160 boolean shouldUpdateMainNotification = !notificationKeys.contains( 161 currentMainNotificationInfo.notificationKey); 162 163 if (shouldUpdateMainNotification) { 164 int size = notificationKeys.size(); 165 NotificationInfo nextNotification = null; 166 // We get the latest notification by finding the notification after the one that was 167 // just dismissed. 168 for (int i = 0; i < size; ++i) { 169 if (currentMainNotificationInfo == mNotificationInfos.get(i) && i + 1 < size) { 170 nextNotification = mNotificationInfos.get(i + 1); 171 break; 172 } 173 } 174 if (nextNotification != null) { 175 mMainView.applyNotificationInfo(nextNotification, true); 176 } 177 } 178 } 179 } 180