Home | History | Annotate | Download | only in notification
      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.app.Notification;
     20 import android.content.Context;
     21 import android.graphics.Color;
     22 import android.graphics.Rect;
     23 import android.view.MotionEvent;
     24 import android.view.View;
     25 import android.view.ViewGroup.MarginLayoutParams;
     26 import android.widget.TextView;
     27 
     28 import com.android.launcher3.R;
     29 import com.android.launcher3.graphics.IconPalette;
     30 import com.android.launcher3.popup.PopupContainerWithArrow;
     31 import com.android.launcher3.touch.SwipeDetector;
     32 import com.android.launcher3.util.Themes;
     33 
     34 import java.util.List;
     35 
     36 import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
     37 
     38 /**
     39  * Utility class to manage notification UI
     40  */
     41 public class NotificationItemView {
     42 
     43     private static final Rect sTempRect = new Rect();
     44 
     45     private final Context mContext;
     46     private final PopupContainerWithArrow mContainer;
     47 
     48     private final TextView mHeaderText;
     49     private final TextView mHeaderCount;
     50     private final NotificationMainView mMainView;
     51     private final NotificationFooterLayout mFooter;
     52     private final SwipeDetector mSwipeDetector;
     53     private final View mIconView;
     54 
     55     private final View mHeader;
     56     private final View mDivider;
     57 
     58     private View mGutter;
     59 
     60     private boolean mIgnoreTouch = false;
     61     private boolean mAnimatingNextIcon;
     62     private int mNotificationHeaderTextColor = Notification.COLOR_DEFAULT;
     63 
     64     public NotificationItemView(PopupContainerWithArrow container) {
     65         mContainer = container;
     66         mContext = container.getContext();
     67 
     68         mHeaderText = container.findViewById(R.id.notification_text);
     69         mHeaderCount = container.findViewById(R.id.notification_count);
     70         mMainView = container.findViewById(R.id.main_view);
     71         mFooter = container.findViewById(R.id.footer);
     72         mIconView = container.findViewById(R.id.popup_item_icon);
     73 
     74         mHeader = container.findViewById(R.id.header);
     75         mDivider = container.findViewById(R.id.divider);
     76 
     77         mSwipeDetector = new SwipeDetector(mContext, mMainView, HORIZONTAL);
     78         mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
     79         mMainView.setSwipeDetector(mSwipeDetector);
     80         mFooter.setContainer(this);
     81     }
     82 
     83     public void addGutter() {
     84         if (mGutter == null) {
     85             mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter, mContainer);
     86         }
     87     }
     88 
     89     public void removeFooter() {
     90         if (mContainer.indexOfChild(mFooter) >= 0) {
     91             mContainer.removeView(mFooter);
     92             mContainer.removeView(mDivider);
     93         }
     94     }
     95 
     96     public void inverseGutterMargin() {
     97         MarginLayoutParams lp = (MarginLayoutParams) mGutter.getLayoutParams();
     98         int top = lp.topMargin;
     99         lp.topMargin = lp.bottomMargin;
    100         lp.bottomMargin = top;
    101     }
    102 
    103     public void removeAllViews() {
    104         mContainer.removeView(mMainView);
    105         mContainer.removeView(mHeader);
    106 
    107         if (mContainer.indexOfChild(mFooter) >= 0) {
    108             mContainer.removeView(mFooter);
    109             mContainer.removeView(mDivider);
    110         }
    111 
    112         if (mGutter != null) {
    113             mContainer.removeView(mGutter);
    114         }
    115     }
    116 
    117     public void updateHeader(int notificationCount, int iconColor) {
    118         mHeaderCount.setText(notificationCount <= 1 ? "" : String.valueOf(notificationCount));
    119         if (Color.alpha(iconColor) > 0) {
    120             if (mNotificationHeaderTextColor == Notification.COLOR_DEFAULT) {
    121                 mNotificationHeaderTextColor =
    122                         IconPalette.resolveContrastColor(mContext, iconColor,
    123                                 Themes.getAttrColor(mContext, R.attr.popupColorPrimary));
    124             }
    125             mHeaderText.setTextColor(mNotificationHeaderTextColor);
    126             mHeaderCount.setTextColor(mNotificationHeaderTextColor);
    127         }
    128     }
    129 
    130     public boolean onInterceptTouchEvent(MotionEvent ev) {
    131         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    132             sTempRect.set(mMainView.getLeft(), mMainView.getTop(),
    133                     mMainView.getRight(), mMainView.getBottom());
    134             mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY());
    135             if (!mIgnoreTouch) {
    136                 mContainer.getParent().requestDisallowInterceptTouchEvent(true);
    137             }
    138         }
    139         if (mIgnoreTouch) {
    140             return false;
    141         }
    142         if (mMainView.getNotificationInfo() == null) {
    143             // The notification hasn't been populated yet.
    144             return false;
    145         }
    146 
    147         mSwipeDetector.onTouchEvent(ev);
    148         return mSwipeDetector.isDraggingOrSettling();
    149     }
    150 
    151     public boolean onTouchEvent(MotionEvent ev) {
    152         if (mIgnoreTouch) {
    153             return false;
    154         }
    155         if (mMainView.getNotificationInfo() == null) {
    156             // The notification hasn't been populated yet.
    157             return false;
    158         }
    159         return mSwipeDetector.onTouchEvent(ev);
    160     }
    161 
    162     public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
    163         if (notificationInfos.isEmpty()) {
    164             return;
    165         }
    166 
    167         NotificationInfo mainNotification = notificationInfos.get(0);
    168         mMainView.applyNotificationInfo(mainNotification, false);
    169 
    170         for (int i = 1; i < notificationInfos.size(); i++) {
    171             mFooter.addNotificationInfo(notificationInfos.get(i));
    172         }
    173         mFooter.commitNotificationInfos();
    174     }
    175 
    176     public void trimNotifications(final List<String> notificationKeys) {
    177         boolean dismissedMainNotification = !notificationKeys.contains(
    178                 mMainView.getNotificationInfo().notificationKey);
    179         if (dismissedMainNotification && !mAnimatingNextIcon) {
    180             // Animate the next icon into place as the new main notification.
    181             mAnimatingNextIcon = true;
    182             mMainView.setContentVisibility(View.INVISIBLE);
    183             mMainView.setContentTranslation(0);
    184             mIconView.getGlobalVisibleRect(sTempRect);
    185             mFooter.animateFirstNotificationTo(sTempRect, (newMainNotification) -> {
    186                 if (newMainNotification != null) {
    187                     mMainView.applyNotificationInfo(newMainNotification, true);
    188                     mMainView.setContentVisibility(View.VISIBLE);
    189                 }
    190                 mAnimatingNextIcon = false;
    191             });
    192         } else {
    193             mFooter.trimNotifications(notificationKeys);
    194         }
    195     }
    196 }
    197