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.animation.ObjectAnimator;
     20 import android.content.Context;
     21 import android.content.res.ColorStateList;
     22 import android.graphics.drawable.ColorDrawable;
     23 import android.graphics.drawable.RippleDrawable;
     24 import android.text.TextUtils;
     25 import android.util.AttributeSet;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.view.ViewPropertyAnimator;
     29 import android.widget.FrameLayout;
     30 import android.widget.TextView;
     31 
     32 import com.android.launcher3.ItemInfo;
     33 import com.android.launcher3.Launcher;
     34 import com.android.launcher3.R;
     35 import com.android.launcher3.touch.OverScroll;
     36 import com.android.launcher3.touch.SwipeDetector;
     37 import com.android.launcher3.userevent.nano.LauncherLogProto;
     38 import com.android.launcher3.util.Themes;
     39 
     40 /**
     41  * A {@link android.widget.FrameLayout} that contains a single notification,
     42  * e.g. icon + title + text.
     43  */
     44 public class NotificationMainView extends FrameLayout implements SwipeDetector.Listener {
     45 
     46     private NotificationInfo mNotificationInfo;
     47     private ViewGroup mTextAndBackground;
     48     private int mBackgroundColor;
     49     private TextView mTitleView;
     50     private TextView mTextView;
     51 
     52     private SwipeDetector mSwipeDetector;
     53 
     54     public NotificationMainView(Context context) {
     55         this(context, null, 0);
     56     }
     57 
     58     public NotificationMainView(Context context, AttributeSet attrs) {
     59         this(context, attrs, 0);
     60     }
     61 
     62     public NotificationMainView(Context context, AttributeSet attrs, int defStyle) {
     63         super(context, attrs, defStyle);
     64     }
     65 
     66     @Override
     67     protected void onFinishInflate() {
     68         super.onFinishInflate();
     69 
     70         mTextAndBackground = (ViewGroup) findViewById(R.id.text_and_background);
     71         ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground();
     72         mBackgroundColor = colorBackground.getColor();
     73         RippleDrawable rippleBackground = new RippleDrawable(ColorStateList.valueOf(
     74                 Themes.getAttrColor(getContext(), android.R.attr.colorControlHighlight)),
     75                 colorBackground, null);
     76         mTextAndBackground.setBackground(rippleBackground);
     77         mTitleView = (TextView) mTextAndBackground.findViewById(R.id.title);
     78         mTextView = (TextView) mTextAndBackground.findViewById(R.id.text);
     79     }
     80 
     81     public void applyNotificationInfo(NotificationInfo mainNotification, View iconView) {
     82         applyNotificationInfo(mainNotification, iconView, false);
     83     }
     84 
     85     public void setSwipeDetector(SwipeDetector swipeDetector) {
     86         mSwipeDetector = swipeDetector;
     87     }
     88 
     89     /**
     90      * Sets the content of this view, animating it after a new icon shifts up if necessary.
     91      */
     92     public void applyNotificationInfo(NotificationInfo mainNotification, View iconView,
     93            boolean animate) {
     94         mNotificationInfo = mainNotification;
     95         CharSequence title = mNotificationInfo.title;
     96         CharSequence text = mNotificationInfo.text;
     97         if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(text)) {
     98             mTitleView.setText(title.toString());
     99             mTextView.setText(text.toString());
    100         } else {
    101             mTitleView.setMaxLines(2);
    102             mTitleView.setText(TextUtils.isEmpty(title) ? text.toString() : title.toString());
    103             mTextView.setVisibility(GONE);
    104         }
    105         iconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
    106                 mBackgroundColor));
    107         if (mNotificationInfo.intent != null) {
    108             setOnClickListener(mNotificationInfo);
    109         }
    110         setTranslationX(0);
    111         // Add a dummy ItemInfo so that logging populates the correct container and item types
    112         // instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively.
    113         setTag(new ItemInfo());
    114         if (animate) {
    115             ObjectAnimator.ofFloat(mTextAndBackground, ALPHA, 0, 1).setDuration(150).start();
    116         }
    117     }
    118 
    119     public NotificationInfo getNotificationInfo() {
    120         return mNotificationInfo;
    121     }
    122 
    123 
    124     public boolean canChildBeDismissed() {
    125         return mNotificationInfo != null && mNotificationInfo.dismissable;
    126     }
    127 
    128     public void onChildDismissed() {
    129         Launcher launcher = Launcher.getLauncher(getContext());
    130         launcher.getPopupDataProvider().cancelNotification(
    131                 mNotificationInfo.notificationKey);
    132         launcher.getUserEventDispatcher().logActionOnItem(
    133                 LauncherLogProto.Action.Touch.SWIPE,
    134                 LauncherLogProto.Action.Direction.RIGHT, // Assume all swipes are right for logging.
    135                 LauncherLogProto.ItemType.NOTIFICATION);
    136     }
    137 
    138     // SwipeDetector.Listener's
    139     @Override
    140     public void onDragStart(boolean start) { }
    141 
    142 
    143     @Override
    144     public boolean onDrag(float displacement, float velocity) {
    145         setTranslationX(canChildBeDismissed()
    146                 ? displacement : OverScroll.dampedScroll(displacement, getWidth()));
    147         animate().cancel();
    148         return true;
    149     }
    150 
    151     @Override
    152     public void onDragEnd(float velocity, boolean fling) {
    153         final boolean willExit;
    154         final float endTranslation;
    155 
    156         if (!canChildBeDismissed()) {
    157             willExit = false;
    158             endTranslation = 0;
    159         } else if (fling) {
    160             willExit = true;
    161             endTranslation = velocity < 0 ? - getWidth() : getWidth();
    162         } else if (Math.abs(getTranslationX()) > getWidth() / 2) {
    163             willExit = true;
    164             endTranslation = (getTranslationX() < 0 ? -getWidth() : getWidth());
    165         } else {
    166             willExit = false;
    167             endTranslation = 0;
    168         }
    169 
    170         SwipeDetector.ScrollInterpolator interpolator = new SwipeDetector.ScrollInterpolator();
    171         interpolator.setVelocityAtZero(velocity);
    172 
    173         long duration = SwipeDetector.calculateDuration(velocity,
    174                 (endTranslation - getTranslationX()) / getWidth());
    175         animate()
    176                 .setDuration(duration)
    177                 .setInterpolator(interpolator)
    178                 .translationX(endTranslation)
    179                 .withEndAction(new Runnable() {
    180                     @Override
    181                     public void run() {
    182                         mSwipeDetector.finishedScrolling();
    183                         if (willExit) {
    184                             onChildDismissed();
    185                         }
    186                     }
    187                 }).start();
    188     }
    189 }
    190