• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.systemui.statusbar.notification.stack;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.util.MathUtils;
23 import android.view.View;
24 
25 import com.android.systemui.Dependency;
26 import com.android.systemui.R;
27 import com.android.systemui.statusbar.AmbientPulseManager;
28 import com.android.systemui.statusbar.NotificationShelf;
29 import com.android.systemui.statusbar.StatusBarState;
30 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
31 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
32 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
33 import com.android.systemui.statusbar.notification.row.ExpandableView;
34 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
35 
36 import java.util.ArrayList;
37 
38 /**
39  * A global state to track all input states for the algorithm.
40  */
41 public class AmbientState {
42 
43     private static final float MAX_PULSE_HEIGHT = 100000f;
44 
45     private final SectionProvider mSectionProvider;
46     private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
47     private int mScrollY;
48     private int mAnchorViewIndex;
49     private int mAnchorViewY;
50     private boolean mDimmed;
51     private ActivatableNotificationView mActivatedChild;
52     private float mOverScrollTopAmount;
53     private float mOverScrollBottomAmount;
54     private int mSpeedBumpIndex = -1;
55     private boolean mDark;
56     private boolean mHideSensitive;
57     private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
58     private float mStackTranslation;
59     private int mLayoutHeight;
60     private int mTopPadding;
61     private boolean mShadeExpanded;
62     private float mMaxHeadsUpTranslation;
63     private boolean mDismissAllInProgress;
64     private int mLayoutMinHeight;
65     private NotificationShelf mShelf;
66     private int mZDistanceBetweenElements;
67     private int mBaseZHeight;
68     private int mMaxLayoutHeight;
69     private ActivatableNotificationView mLastVisibleBackgroundChild;
70     private float mCurrentScrollVelocity;
71     private int mStatusBarState;
72     private float mExpandingVelocity;
73     private boolean mPanelTracking;
74     private boolean mExpansionChanging;
75     private boolean mPanelFullWidth;
76     private boolean mPulsing;
77     private boolean mUnlockHintRunning;
78     private boolean mQsCustomizerShowing;
79     private int mIntrinsicPadding;
80     private int mExpandAnimationTopChange;
81     private ExpandableNotificationRow mExpandingNotification;
82     private float mDarkAmount;
83     private boolean mAppearing;
84     private float mPulseHeight = MAX_PULSE_HEIGHT;
85     private float mDozeAmount = 0.0f;
86 
AmbientState( Context context, @NonNull SectionProvider sectionProvider)87     public AmbientState(
88             Context context,
89             @NonNull SectionProvider sectionProvider) {
90         mSectionProvider = sectionProvider;
91         reload(context);
92     }
93 
94     /**
95      * Reload the dimens e.g. if the density changed.
96      */
reload(Context context)97     public void reload(Context context) {
98         mZDistanceBetweenElements = getZDistanceBetweenElements(context);
99         mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
100     }
101 
getZDistanceBetweenElements(Context context)102     private static int getZDistanceBetweenElements(Context context) {
103         return Math.max(1, context.getResources()
104                 .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
105     }
106 
getBaseHeight(int zdistanceBetweenElements)107     private static int getBaseHeight(int zdistanceBetweenElements) {
108         return 4 * zdistanceBetweenElements;
109     }
110 
111     /**
112      * @return the launch height for notifications that are launched
113      */
getNotificationLaunchHeight(Context context)114     public static int getNotificationLaunchHeight(Context context) {
115         int zDistance = getZDistanceBetweenElements(context);
116         return getBaseHeight(zDistance) * 2;
117     }
118 
119     /**
120      * @return the basic Z height on which notifications remain.
121      */
getBaseZHeight()122     public int getBaseZHeight() {
123         return mBaseZHeight;
124     }
125 
126     /**
127      * @return the distance in Z between two overlaying notifications.
128      */
getZDistanceBetweenElements()129     public int getZDistanceBetweenElements() {
130         return mZDistanceBetweenElements;
131     }
132 
getScrollY()133     public int getScrollY() {
134         return mScrollY;
135     }
136 
setScrollY(int scrollY)137     public void setScrollY(int scrollY) {
138         this.mScrollY = scrollY;
139     }
140 
141     /**
142      * Index of the child view whose Y position on screen is returned by {@link #getAnchorViewY()}.
143      * Other views are laid out outwards from this view in both directions.
144      */
getAnchorViewIndex()145     public int getAnchorViewIndex() {
146         return mAnchorViewIndex;
147     }
148 
setAnchorViewIndex(int anchorViewIndex)149     public void setAnchorViewIndex(int anchorViewIndex) {
150         mAnchorViewIndex = anchorViewIndex;
151     }
152 
153     /** Current Y position of the view at {@link #getAnchorViewIndex()}. */
getAnchorViewY()154     public int getAnchorViewY() {
155         return mAnchorViewY;
156     }
157 
setAnchorViewY(int anchorViewY)158     public void setAnchorViewY(int anchorViewY) {
159         mAnchorViewY = anchorViewY;
160     }
161 
162     /** Call when dragging begins. */
onBeginDrag(ExpandableView view)163     public void onBeginDrag(ExpandableView view) {
164         mDraggedViews.add(view);
165     }
166 
onDragFinished(View view)167     public void onDragFinished(View view) {
168         mDraggedViews.remove(view);
169     }
170 
getDraggedViews()171     public ArrayList<ExpandableView> getDraggedViews() {
172         return mDraggedViews;
173     }
174 
175     /**
176      * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
177      *               translucent and everything is scaled back a bit.
178      */
setDimmed(boolean dimmed)179     public void setDimmed(boolean dimmed) {
180         mDimmed = dimmed;
181     }
182 
183     /** In dark mode, we draw as little as possible, assuming a black background */
setDark(boolean dark)184     public void setDark(boolean dark) {
185         mDark = dark;
186     }
187 
188     /** Dark ratio of the status bar **/
setDarkAmount(float darkAmount)189     public void setDarkAmount(float darkAmount) {
190         if (darkAmount == 1.0f && mDarkAmount != darkAmount) {
191             // Whenever we are fully dark, let's reset the pulseHeight again
192             mPulseHeight = MAX_PULSE_HEIGHT;
193         }
194         mDarkAmount = darkAmount;
195     }
196 
197     /** Returns the dark ratio of the status bar */
getDarkAmount()198     public float getDarkAmount() {
199         return mDarkAmount;
200     }
201 
setHideSensitive(boolean hideSensitive)202     public void setHideSensitive(boolean hideSensitive) {
203         mHideSensitive = hideSensitive;
204     }
205 
206     /**
207      * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
208      * interaction. This child is then scaled normally and its background is fully opaque.
209      */
setActivatedChild(ActivatableNotificationView activatedChild)210     public void setActivatedChild(ActivatableNotificationView activatedChild) {
211         mActivatedChild = activatedChild;
212     }
213 
isDimmed()214     public boolean isDimmed() {
215         // While we are expanding from pulse, we want the notifications not to be dimmed, otherwise
216         // you'd see the difference to the pulsing notification
217         return mDimmed && !(isPulseExpanding() && mDozeAmount == 1.0f);
218     }
219 
isDark()220     public boolean isDark() {
221         return mDark;
222     }
223 
isHideSensitive()224     public boolean isHideSensitive() {
225         return mHideSensitive;
226     }
227 
getActivatedChild()228     public ActivatableNotificationView getActivatedChild() {
229         return mActivatedChild;
230     }
231 
setOverScrollAmount(float amount, boolean onTop)232     public void setOverScrollAmount(float amount, boolean onTop) {
233         if (onTop) {
234             mOverScrollTopAmount = amount;
235         } else {
236             mOverScrollBottomAmount = amount;
237         }
238     }
239 
getOverScrollAmount(boolean top)240     public float getOverScrollAmount(boolean top) {
241         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
242     }
243 
getSpeedBumpIndex()244     public int getSpeedBumpIndex() {
245         return mSpeedBumpIndex;
246     }
247 
setSpeedBumpIndex(int shelfIndex)248     public void setSpeedBumpIndex(int shelfIndex) {
249         mSpeedBumpIndex = shelfIndex;
250     }
251 
getSectionProvider()252     public SectionProvider getSectionProvider() {
253         return mSectionProvider;
254     }
255 
getStackTranslation()256     public float getStackTranslation() {
257         return mStackTranslation;
258     }
259 
setStackTranslation(float stackTranslation)260     public void setStackTranslation(float stackTranslation) {
261         mStackTranslation = stackTranslation;
262     }
263 
setLayoutHeight(int layoutHeight)264     public void setLayoutHeight(int layoutHeight) {
265         mLayoutHeight = layoutHeight;
266     }
267 
getTopPadding()268     public float getTopPadding() {
269         return mTopPadding;
270     }
271 
setTopPadding(int topPadding)272     public void setTopPadding(int topPadding) {
273         mTopPadding = topPadding;
274     }
275 
getInnerHeight()276     public int getInnerHeight() {
277         return getInnerHeight(false /* ignorePulseHeight */);
278     }
279 
280     /**
281      * @param ignorePulseHeight ignore the pulse height for this request
282      * @return the inner height of the algorithm.
283      */
getInnerHeight(boolean ignorePulseHeight)284     public int getInnerHeight(boolean ignorePulseHeight) {
285         if (mDozeAmount == 1.0f && !isPulseExpanding()) {
286             return mShelf.getHeight();
287         }
288         int height = Math.max(mLayoutMinHeight,
289                 Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding);
290         if (ignorePulseHeight) {
291             return height;
292         }
293         float pulseHeight = Math.min(mPulseHeight, (float) height);
294         return (int) MathUtils.lerp(height, pulseHeight, mDozeAmount);
295     }
296 
isPulseExpanding()297     public boolean isPulseExpanding() {
298         return mPulseHeight != MAX_PULSE_HEIGHT && mDozeAmount != 0.0f && mDarkAmount != 1.0f;
299     }
300 
isShadeExpanded()301     public boolean isShadeExpanded() {
302         return mShadeExpanded;
303     }
304 
setShadeExpanded(boolean shadeExpanded)305     public void setShadeExpanded(boolean shadeExpanded) {
306         mShadeExpanded = shadeExpanded;
307     }
308 
setMaxHeadsUpTranslation(float maxHeadsUpTranslation)309     public void setMaxHeadsUpTranslation(float maxHeadsUpTranslation) {
310         mMaxHeadsUpTranslation = maxHeadsUpTranslation;
311     }
312 
getMaxHeadsUpTranslation()313     public float getMaxHeadsUpTranslation() {
314         return mMaxHeadsUpTranslation;
315     }
316 
setDismissAllInProgress(boolean dismissAllInProgress)317     public void setDismissAllInProgress(boolean dismissAllInProgress) {
318         mDismissAllInProgress = dismissAllInProgress;
319     }
320 
isDismissAllInProgress()321     public boolean isDismissAllInProgress() {
322         return mDismissAllInProgress;
323     }
324 
setLayoutMinHeight(int layoutMinHeight)325     public void setLayoutMinHeight(int layoutMinHeight) {
326         mLayoutMinHeight = layoutMinHeight;
327     }
328 
setShelf(NotificationShelf shelf)329     public void setShelf(NotificationShelf shelf) {
330         mShelf = shelf;
331     }
332 
333     @Nullable
getShelf()334     public NotificationShelf getShelf() {
335         return mShelf;
336     }
337 
setLayoutMaxHeight(int maxLayoutHeight)338     public void setLayoutMaxHeight(int maxLayoutHeight) {
339         mMaxLayoutHeight = maxLayoutHeight;
340     }
341 
342     /**
343      * Sets the last visible view of the host layout, that has a background, i.e the very last
344      * view in the shade, without the clear all button.
345      */
setLastVisibleBackgroundChild( ActivatableNotificationView lastVisibleBackgroundChild)346     public void setLastVisibleBackgroundChild(
347             ActivatableNotificationView lastVisibleBackgroundChild) {
348         mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
349     }
350 
getLastVisibleBackgroundChild()351     public ActivatableNotificationView getLastVisibleBackgroundChild() {
352         return mLastVisibleBackgroundChild;
353     }
354 
setCurrentScrollVelocity(float currentScrollVelocity)355     public void setCurrentScrollVelocity(float currentScrollVelocity) {
356         mCurrentScrollVelocity = currentScrollVelocity;
357     }
358 
getCurrentScrollVelocity()359     public float getCurrentScrollVelocity() {
360         return mCurrentScrollVelocity;
361     }
362 
isOnKeyguard()363     public boolean isOnKeyguard() {
364         return mStatusBarState == StatusBarState.KEYGUARD;
365     }
366 
setStatusBarState(int statusBarState)367     public void setStatusBarState(int statusBarState) {
368         mStatusBarState = statusBarState;
369     }
370 
setExpandingVelocity(float expandingVelocity)371     public void setExpandingVelocity(float expandingVelocity) {
372         mExpandingVelocity = expandingVelocity;
373     }
374 
setExpansionChanging(boolean expansionChanging)375     public void setExpansionChanging(boolean expansionChanging) {
376         mExpansionChanging = expansionChanging;
377     }
378 
isExpansionChanging()379     public boolean isExpansionChanging() {
380         return mExpansionChanging;
381     }
382 
getExpandingVelocity()383     public float getExpandingVelocity() {
384         return mExpandingVelocity;
385     }
386 
setPanelTracking(boolean panelTracking)387     public void setPanelTracking(boolean panelTracking) {
388         mPanelTracking = panelTracking;
389     }
390 
hasPulsingNotifications()391     public boolean hasPulsingNotifications() {
392         return mPulsing && mAmbientPulseManager != null
393                 && mAmbientPulseManager.hasNotifications();
394     }
395 
setPulsing(boolean hasPulsing)396     public void setPulsing(boolean hasPulsing) {
397         mPulsing = hasPulsing;
398     }
399 
400     /**
401      * @return if we're pulsing in general
402      */
isPulsing()403     public boolean isPulsing() {
404         return mPulsing;
405     }
406 
isPulsing(NotificationEntry entry)407     public boolean isPulsing(NotificationEntry entry) {
408         if (!mPulsing || mAmbientPulseManager == null) {
409             return false;
410         }
411         return mAmbientPulseManager.isAlerting(entry.key);
412     }
413 
isPanelTracking()414     public boolean isPanelTracking() {
415         return mPanelTracking;
416     }
417 
isPanelFullWidth()418     public boolean isPanelFullWidth() {
419         return mPanelFullWidth;
420     }
421 
setPanelFullWidth(boolean panelFullWidth)422     public void setPanelFullWidth(boolean panelFullWidth) {
423         mPanelFullWidth = panelFullWidth;
424     }
425 
setUnlockHintRunning(boolean unlockHintRunning)426     public void setUnlockHintRunning(boolean unlockHintRunning) {
427         mUnlockHintRunning = unlockHintRunning;
428     }
429 
isUnlockHintRunning()430     public boolean isUnlockHintRunning() {
431         return mUnlockHintRunning;
432     }
433 
isQsCustomizerShowing()434     public boolean isQsCustomizerShowing() {
435         return mQsCustomizerShowing;
436     }
437 
setQsCustomizerShowing(boolean qsCustomizerShowing)438     public void setQsCustomizerShowing(boolean qsCustomizerShowing) {
439         mQsCustomizerShowing = qsCustomizerShowing;
440     }
441 
setIntrinsicPadding(int intrinsicPadding)442     public void setIntrinsicPadding(int intrinsicPadding) {
443         mIntrinsicPadding = intrinsicPadding;
444     }
445 
getIntrinsicPadding()446     public int getIntrinsicPadding() {
447         return mIntrinsicPadding;
448     }
449 
450     /**
451      * @return whether a view is dozing and not pulsing right now
452      */
isDozingAndNotPulsing(ExpandableView view)453     public boolean isDozingAndNotPulsing(ExpandableView view) {
454         if (view instanceof ExpandableNotificationRow) {
455             return isDozingAndNotPulsing((ExpandableNotificationRow) view);
456         }
457         return false;
458     }
459 
460     /**
461      * @return whether a row is dozing and not pulsing right now
462      */
isDozingAndNotPulsing(ExpandableNotificationRow row)463     public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
464         return isDark() && !isPulsing(row.getEntry());
465     }
466 
setExpandAnimationTopChange(int expandAnimationTopChange)467     public void setExpandAnimationTopChange(int expandAnimationTopChange) {
468         mExpandAnimationTopChange = expandAnimationTopChange;
469     }
470 
setExpandingNotification(ExpandableNotificationRow row)471     public void setExpandingNotification(ExpandableNotificationRow row) {
472         mExpandingNotification = row;
473     }
474 
getExpandingNotification()475     public ExpandableNotificationRow getExpandingNotification() {
476         return mExpandingNotification;
477     }
478 
getExpandAnimationTopChange()479     public int getExpandAnimationTopChange() {
480         return mExpandAnimationTopChange;
481     }
482 
483     /**
484      * @return {@code true } when shade is completely dark: in AOD or ambient display.
485      */
isFullyDark()486     public boolean isFullyDark() {
487         return mDarkAmount == 1;
488     }
489 
isDarkAtAll()490     public boolean isDarkAtAll() {
491         return mDarkAmount != 0;
492     }
493 
setAppearing(boolean appearing)494     public void setAppearing(boolean appearing) {
495         mAppearing = appearing;
496     }
497 
isAppearing()498     public boolean isAppearing() {
499         return mAppearing;
500     }
501 
setPulseHeight(float height)502     public void setPulseHeight(float height) {
503         mPulseHeight = height;
504     }
505 
setDozeAmount(float dozeAmount)506     public void setDozeAmount(float dozeAmount) {
507         if (dozeAmount != mDozeAmount) {
508             mDozeAmount = dozeAmount;
509             if (dozeAmount == 0.0f || dozeAmount == 1.0f) {
510                 // We woke all the way up, let's reset the pulse height
511                 mPulseHeight = MAX_PULSE_HEIGHT;
512             }
513         }
514     }
515 
516     /**
517      * Is the device fully awake, which is different from not tark at all when there are pulsing
518      * notifications.
519      */
isFullyAwake()520     public boolean isFullyAwake() {
521         return mDozeAmount == 0.0f;
522     }
523 }
524