• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NotificationMainView(Context context)54     public NotificationMainView(Context context) {
55         this(context, null, 0);
56     }
57 
NotificationMainView(Context context, AttributeSet attrs)58     public NotificationMainView(Context context, AttributeSet attrs) {
59         this(context, attrs, 0);
60     }
61 
NotificationMainView(Context context, AttributeSet attrs, int defStyle)62     public NotificationMainView(Context context, AttributeSet attrs, int defStyle) {
63         super(context, attrs, defStyle);
64     }
65 
66     @Override
onFinishInflate()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 
applyNotificationInfo(NotificationInfo mainNotification, View iconView)81     public void applyNotificationInfo(NotificationInfo mainNotification, View iconView) {
82         applyNotificationInfo(mainNotification, iconView, false);
83     }
84 
setSwipeDetector(SwipeDetector swipeDetector)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      */
applyNotificationInfo(NotificationInfo mainNotification, View iconView, boolean animate)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 
getNotificationInfo()119     public NotificationInfo getNotificationInfo() {
120         return mNotificationInfo;
121     }
122 
123 
canChildBeDismissed()124     public boolean canChildBeDismissed() {
125         return mNotificationInfo != null && mNotificationInfo.dismissable;
126     }
127 
onChildDismissed()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
onDragStart(boolean start)140     public void onDragStart(boolean start) { }
141 
142 
143     @Override
onDrag(float displacement, float velocity)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
onDragEnd(float velocity, boolean fling)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