• 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 
24 import com.android.systemui.R;
25 import com.android.systemui.dagger.SysUISingleton;
26 import com.android.systemui.statusbar.NotificationShelf;
27 import com.android.systemui.statusbar.StatusBarState;
28 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
29 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
30 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
31 import com.android.systemui.statusbar.notification.row.ExpandableView;
32 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
33 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
34 
35 import javax.inject.Inject;
36 
37 /**
38  * A global state to track all input states for the algorithm.
39  */
40 @SysUISingleton
41 public class AmbientState {
42 
43     private static final float MAX_PULSE_HEIGHT = 100000f;
44     private static final boolean NOTIFICATIONS_HAVE_SHADOWS = false;
45 
46     private final SectionProvider mSectionProvider;
47     private final BypassController mBypassController;
48     private int mScrollY;
49     private boolean mDimmed;
50     private ActivatableNotificationView mActivatedChild;
51     private float mOverScrollTopAmount;
52     private float mOverScrollBottomAmount;
53     private boolean mDozing;
54     private boolean mHideSensitive;
55     private float mStackTranslation;
56     private int mLayoutHeight;
57     private int mTopPadding;
58     private boolean mShadeExpanded;
59     private float mMaxHeadsUpTranslation;
60     private boolean mDismissAllInProgress;
61     private int mLayoutMinHeight;
62     private NotificationShelf mShelf;
63     private int mZDistanceBetweenElements;
64     private int mBaseZHeight;
65     private int mContentHeight;
66     private ExpandableView mLastVisibleBackgroundChild;
67     private float mCurrentScrollVelocity;
68     private int mStatusBarState;
69     private float mExpandingVelocity;
70     private boolean mPanelTracking;
71     private boolean mExpansionChanging;
72     private boolean mPanelFullWidth;
73     private boolean mPulsing;
74     private boolean mUnlockHintRunning;
75     private boolean mQsCustomizerShowing;
76     private int mIntrinsicPadding;
77     private float mHideAmount;
78     private boolean mAppearing;
79     private float mPulseHeight = MAX_PULSE_HEIGHT;
80     private float mDozeAmount = 0.0f;
81     private Runnable mOnPulseHeightChangedListener;
82     private ExpandableNotificationRow mTrackedHeadsUpRow;
83     private float mAppearFraction;
84     private boolean mIsShadeOpening;
85     private float mOverExpansion;
86 
87     /** Distance of top of notifications panel from top of screen. */
88     private float mStackY = 0;
89 
90     /** Height of notifications panel. */
91     private float mStackHeight = 0;
92 
93     /** Fraction of shade expansion. */
94     private float mExpansionFraction;
95 
96     /** Height of the notifications panel without top padding when expansion completes. */
97     private float mStackEndHeight;
98     private float mTransitionToFullShadeAmount;
99 
100     /**
101      * @return Height of the notifications panel without top padding when expansion completes.
102      */
getStackEndHeight()103     public float getStackEndHeight() {
104         return mStackEndHeight;
105     }
106 
107     /**
108      * @param stackEndHeight Height of the notifications panel without top padding
109      *                       when expansion completes.
110      */
setStackEndHeight(float stackEndHeight)111     public void setStackEndHeight(float stackEndHeight) {
112         mStackEndHeight = stackEndHeight;
113     }
114 
115     /**
116      * @param stackY Distance of top of notifications panel from top of screen.
117      */
setStackY(float stackY)118     public void setStackY(float stackY) {
119         mStackY = stackY;
120     }
121 
122     /**
123      * @return Distance of top of notifications panel from top of screen.
124      */
getStackY()125     public float getStackY() {
126         return mStackY;
127     }
128 
129     /**
130      * @param expansionFraction Fraction of shade expansion.
131      */
setExpansionFraction(float expansionFraction)132     public void setExpansionFraction(float expansionFraction) {
133         mExpansionFraction = expansionFraction;
134     }
135 
136     /**
137      * @return Fraction of shade expansion.
138      */
getExpansionFraction()139     public float getExpansionFraction() {
140         return mExpansionFraction;
141     }
142 
143     /**
144      * @param stackHeight Height of notifications panel.
145      */
setStackHeight(float stackHeight)146     public void setStackHeight(float stackHeight) {
147         mStackHeight = stackHeight;
148     }
149 
150     /**
151      * @return Height of notifications panel.
152      */
getStackHeight()153     public float getStackHeight() {
154         return mStackHeight;
155     }
156 
157     /** Tracks the state from AlertingNotificationManager#hasNotifications() */
158     private boolean mHasAlertEntries;
159 
160     @Inject
AmbientState( Context context, @NonNull SectionProvider sectionProvider, @NonNull BypassController bypassController)161     public AmbientState(
162             Context context,
163             @NonNull SectionProvider sectionProvider,
164             @NonNull BypassController bypassController) {
165         mSectionProvider = sectionProvider;
166         mBypassController = bypassController;
167         reload(context);
168     }
169 
170     /**
171      * Reload the dimens e.g. if the density changed.
172      */
reload(Context context)173     public void reload(Context context) {
174         mZDistanceBetweenElements = getZDistanceBetweenElements(context);
175         mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
176     }
177 
setIsShadeOpening(boolean isOpening)178     public void setIsShadeOpening(boolean isOpening) {
179         mIsShadeOpening = isOpening;
180     }
181 
isShadeOpening()182     public boolean isShadeOpening() {
183         return mIsShadeOpening;
184     }
185 
setOverExpansion(float overExpansion)186     void setOverExpansion(float overExpansion) {
187         mOverExpansion = overExpansion;
188     }
189 
getOverExpansion()190     float getOverExpansion() {
191         return mOverExpansion;
192     }
193 
getZDistanceBetweenElements(Context context)194     private static int getZDistanceBetweenElements(Context context) {
195         return Math.max(1, context.getResources()
196                 .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
197     }
198 
getBaseHeight(int zdistanceBetweenElements)199     private static int getBaseHeight(int zdistanceBetweenElements) {
200         return NOTIFICATIONS_HAVE_SHADOWS ? 4 * zdistanceBetweenElements : 0;
201     }
202 
203     /**
204      * @return the launch height for notifications that are launched
205      */
getNotificationLaunchHeight(Context context)206     public static int getNotificationLaunchHeight(Context context) {
207         int zDistance = getZDistanceBetweenElements(context);
208         return NOTIFICATIONS_HAVE_SHADOWS ? 2 * getBaseHeight(zDistance) : 4 * zDistance;
209     }
210 
211     /**
212      * @return the basic Z height on which notifications remain.
213      */
getBaseZHeight()214     public int getBaseZHeight() {
215         return mBaseZHeight;
216     }
217 
218     /**
219      * @return the distance in Z between two overlaying notifications.
220      */
getZDistanceBetweenElements()221     public int getZDistanceBetweenElements() {
222         return mZDistanceBetweenElements;
223     }
224 
getScrollY()225     public int getScrollY() {
226         return mScrollY;
227     }
228 
229     /**
230      * Set the new Scroll Y position.
231      */
setScrollY(int scrollY)232     public void setScrollY(int scrollY) {
233         // Because we're dealing with an overscroller, scrollY could sometimes become smaller than
234         // 0. However this is only for internal purposes and the scroll position when read
235         // should never be smaller than 0, otherwise it can lead to flickers.
236         this.mScrollY = Math.max(scrollY, 0);
237     }
238 
239     /**
240      * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
241      *               translucent and everything is scaled back a bit.
242      */
setDimmed(boolean dimmed)243     public void setDimmed(boolean dimmed) {
244         mDimmed = dimmed;
245     }
246 
247     /** While dozing, we draw as little as possible, assuming a black background */
setDozing(boolean dozing)248     public void setDozing(boolean dozing) {
249         mDozing = dozing;
250     }
251 
252     /** Hide ratio of the status bar **/
setHideAmount(float hidemount)253     public void setHideAmount(float hidemount) {
254         if (hidemount == 1.0f && mHideAmount != hidemount) {
255             // Whenever we are fully hidden, let's reset the pulseHeight again
256             setPulseHeight(MAX_PULSE_HEIGHT);
257         }
258         mHideAmount = hidemount;
259     }
260 
261     /** Returns the hide ratio of the status bar */
getHideAmount()262     public float getHideAmount() {
263         return mHideAmount;
264     }
265 
setHideSensitive(boolean hideSensitive)266     public void setHideSensitive(boolean hideSensitive) {
267         mHideSensitive = hideSensitive;
268     }
269 
270     /**
271      * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
272      * interaction. This child is then scaled normally and its background is fully opaque.
273      */
setActivatedChild(ActivatableNotificationView activatedChild)274     public void setActivatedChild(ActivatableNotificationView activatedChild) {
275         mActivatedChild = activatedChild;
276     }
277 
isDimmed()278     public boolean isDimmed() {
279         // While we are expanding from pulse, we want the notifications not to be dimmed, otherwise
280         // you'd see the difference to the pulsing notification
281         return mDimmed && !(isPulseExpanding() && mDozeAmount == 1.0f);
282     }
283 
isDozing()284     public boolean isDozing() {
285         return mDozing;
286     }
287 
isHideSensitive()288     public boolean isHideSensitive() {
289         return mHideSensitive;
290     }
291 
getActivatedChild()292     public ActivatableNotificationView getActivatedChild() {
293         return mActivatedChild;
294     }
295 
setOverScrollAmount(float amount, boolean onTop)296     public void setOverScrollAmount(float amount, boolean onTop) {
297         if (onTop) {
298             mOverScrollTopAmount = amount;
299         } else {
300             mOverScrollBottomAmount = amount;
301         }
302     }
303 
304     /**
305      * Is bypass currently enabled?
306      */
isBypassEnabled()307     public boolean isBypassEnabled() {
308         return mBypassController.isBypassEnabled();
309     }
310 
getOverScrollAmount(boolean top)311     public float getOverScrollAmount(boolean top) {
312         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
313     }
314 
getSectionProvider()315     public SectionProvider getSectionProvider() {
316         return mSectionProvider;
317     }
318 
getStackTranslation()319     public float getStackTranslation() {
320         return mStackTranslation;
321     }
322 
setStackTranslation(float stackTranslation)323     public void setStackTranslation(float stackTranslation) {
324         mStackTranslation = stackTranslation;
325     }
326 
setLayoutHeight(int layoutHeight)327     public void setLayoutHeight(int layoutHeight) {
328         mLayoutHeight = layoutHeight;
329     }
330 
getTopPadding()331     public float getTopPadding() {
332         return mTopPadding;
333     }
334 
setTopPadding(int topPadding)335     public void setTopPadding(int topPadding) {
336         mTopPadding = topPadding;
337     }
338 
getInnerHeight()339     public int getInnerHeight() {
340         return getInnerHeight(false /* ignorePulseHeight */);
341     }
342 
343     /**
344      * @param ignorePulseHeight ignore the pulse height for this request
345      * @return the inner height of the algorithm.
346      */
getInnerHeight(boolean ignorePulseHeight)347     public int getInnerHeight(boolean ignorePulseHeight) {
348         if (mDozeAmount == 1.0f && !isPulseExpanding()) {
349             return mShelf.getHeight();
350         }
351         int height = (int) Math.max(mLayoutMinHeight,
352                 Math.min(mLayoutHeight, mContentHeight) - mTopPadding);
353         if (ignorePulseHeight) {
354             return height;
355         }
356         float pulseHeight = Math.min(mPulseHeight, (float) height);
357         return (int) MathUtils.lerp(height, pulseHeight, mDozeAmount);
358     }
359 
isPulseExpanding()360     public boolean isPulseExpanding() {
361         return mPulseHeight != MAX_PULSE_HEIGHT && mDozeAmount != 0.0f && mHideAmount != 1.0f;
362     }
363 
isShadeExpanded()364     public boolean isShadeExpanded() {
365         return mShadeExpanded;
366     }
367 
setShadeExpanded(boolean shadeExpanded)368     public void setShadeExpanded(boolean shadeExpanded) {
369         mShadeExpanded = shadeExpanded;
370     }
371 
setMaxHeadsUpTranslation(float maxHeadsUpTranslation)372     public void setMaxHeadsUpTranslation(float maxHeadsUpTranslation) {
373         mMaxHeadsUpTranslation = maxHeadsUpTranslation;
374     }
375 
getMaxHeadsUpTranslation()376     public float getMaxHeadsUpTranslation() {
377         return mMaxHeadsUpTranslation;
378     }
379 
setDismissAllInProgress(boolean dismissAllInProgress)380     public void setDismissAllInProgress(boolean dismissAllInProgress) {
381         mDismissAllInProgress = dismissAllInProgress;
382     }
383 
isDismissAllInProgress()384     public boolean isDismissAllInProgress() {
385         return mDismissAllInProgress;
386     }
387 
setLayoutMinHeight(int layoutMinHeight)388     public void setLayoutMinHeight(int layoutMinHeight) {
389         mLayoutMinHeight = layoutMinHeight;
390     }
391 
setShelf(NotificationShelf shelf)392     public void setShelf(NotificationShelf shelf) {
393         mShelf = shelf;
394     }
395 
396     @Nullable
getShelf()397     public NotificationShelf getShelf() {
398         return mShelf;
399     }
400 
setContentHeight(int contentHeight)401     public void setContentHeight(int contentHeight) {
402         mContentHeight = contentHeight;
403     }
404 
getContentHeight()405     public float getContentHeight() {
406         return mContentHeight;
407     }
408 
409     /**
410      * Sets the last visible view of the host layout, that has a background, i.e the very last
411      * view in the shade, without the clear all button.
412      */
setLastVisibleBackgroundChild( ExpandableView lastVisibleBackgroundChild)413     public void setLastVisibleBackgroundChild(
414             ExpandableView lastVisibleBackgroundChild) {
415         mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
416     }
417 
getLastVisibleBackgroundChild()418     public ExpandableView getLastVisibleBackgroundChild() {
419         return mLastVisibleBackgroundChild;
420     }
421 
setCurrentScrollVelocity(float currentScrollVelocity)422     public void setCurrentScrollVelocity(float currentScrollVelocity) {
423         mCurrentScrollVelocity = currentScrollVelocity;
424     }
425 
getCurrentScrollVelocity()426     public float getCurrentScrollVelocity() {
427         return mCurrentScrollVelocity;
428     }
429 
isOnKeyguard()430     public boolean isOnKeyguard() {
431         return mStatusBarState == StatusBarState.KEYGUARD;
432     }
433 
setStatusBarState(int statusBarState)434     public void setStatusBarState(int statusBarState) {
435         mStatusBarState = statusBarState;
436     }
437 
setExpandingVelocity(float expandingVelocity)438     public void setExpandingVelocity(float expandingVelocity) {
439         mExpandingVelocity = expandingVelocity;
440     }
441 
setExpansionChanging(boolean expansionChanging)442     public void setExpansionChanging(boolean expansionChanging) {
443         mExpansionChanging = expansionChanging;
444     }
445 
isExpansionChanging()446     public boolean isExpansionChanging() {
447         return mExpansionChanging;
448     }
449 
getExpandingVelocity()450     public float getExpandingVelocity() {
451         return mExpandingVelocity;
452     }
453 
setPanelTracking(boolean panelTracking)454     public void setPanelTracking(boolean panelTracking) {
455         mPanelTracking = panelTracking;
456     }
457 
hasPulsingNotifications()458     public boolean hasPulsingNotifications() {
459         return mPulsing && mHasAlertEntries;
460     }
461 
setPulsing(boolean hasPulsing)462     public void setPulsing(boolean hasPulsing) {
463         mPulsing = hasPulsing;
464     }
465 
466     /**
467      * @return if we're pulsing in general
468      */
isPulsing()469     public boolean isPulsing() {
470         return mPulsing;
471     }
472 
isPulsing(NotificationEntry entry)473     public boolean isPulsing(NotificationEntry entry) {
474         return mPulsing && entry.isAlerting();
475     }
476 
isPanelTracking()477     public boolean isPanelTracking() {
478         return mPanelTracking;
479     }
480 
isPanelFullWidth()481     public boolean isPanelFullWidth() {
482         return mPanelFullWidth;
483     }
484 
setPanelFullWidth(boolean panelFullWidth)485     public void setPanelFullWidth(boolean panelFullWidth) {
486         mPanelFullWidth = panelFullWidth;
487     }
488 
setUnlockHintRunning(boolean unlockHintRunning)489     public void setUnlockHintRunning(boolean unlockHintRunning) {
490         mUnlockHintRunning = unlockHintRunning;
491     }
492 
isUnlockHintRunning()493     public boolean isUnlockHintRunning() {
494         return mUnlockHintRunning;
495     }
496 
isQsCustomizerShowing()497     public boolean isQsCustomizerShowing() {
498         return mQsCustomizerShowing;
499     }
500 
setQsCustomizerShowing(boolean qsCustomizerShowing)501     public void setQsCustomizerShowing(boolean qsCustomizerShowing) {
502         mQsCustomizerShowing = qsCustomizerShowing;
503     }
504 
setIntrinsicPadding(int intrinsicPadding)505     public void setIntrinsicPadding(int intrinsicPadding) {
506         mIntrinsicPadding = intrinsicPadding;
507     }
508 
getIntrinsicPadding()509     public int getIntrinsicPadding() {
510         return mIntrinsicPadding;
511     }
512 
513     /**
514      * @return whether a view is dozing and not pulsing right now
515      */
isDozingAndNotPulsing(ExpandableView view)516     public boolean isDozingAndNotPulsing(ExpandableView view) {
517         if (view instanceof ExpandableNotificationRow) {
518             return isDozingAndNotPulsing((ExpandableNotificationRow) view);
519         }
520         return false;
521     }
522 
523     /**
524      * @return whether a row is dozing and not pulsing right now
525      */
isDozingAndNotPulsing(ExpandableNotificationRow row)526     public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
527         return isDozing() && !isPulsing(row.getEntry());
528     }
529 
530     /**
531      * @return {@code true } when shade is completely hidden: in AOD, ambient display or when
532      * bypassing.
533      */
isFullyHidden()534     public boolean isFullyHidden() {
535         return mHideAmount == 1;
536     }
537 
isHiddenAtAll()538     public boolean isHiddenAtAll() {
539         return mHideAmount != 0;
540     }
541 
setAppearing(boolean appearing)542     public void setAppearing(boolean appearing) {
543         mAppearing = appearing;
544     }
545 
isAppearing()546     public boolean isAppearing() {
547         return mAppearing;
548     }
549 
setPulseHeight(float height)550     public void setPulseHeight(float height) {
551         if (height != mPulseHeight) {
552             mPulseHeight = height;
553             if (mOnPulseHeightChangedListener != null) {
554                 mOnPulseHeightChangedListener.run();
555             }
556         }
557     }
558 
getPulseHeight()559     public float getPulseHeight() {
560         if (mPulseHeight == MAX_PULSE_HEIGHT) {
561             // If we're not pulse expanding, the height should be 0
562             return 0;
563         }
564         return mPulseHeight;
565     }
566 
setDozeAmount(float dozeAmount)567     public void setDozeAmount(float dozeAmount) {
568         if (dozeAmount != mDozeAmount) {
569             mDozeAmount = dozeAmount;
570             if (dozeAmount == 0.0f || dozeAmount == 1.0f) {
571                 // We woke all the way up, let's reset the pulse height
572                 setPulseHeight(MAX_PULSE_HEIGHT);
573             }
574         }
575     }
576 
577     /**
578      * Is the device fully awake, which is different from not tark at all when there are pulsing
579      * notifications.
580      */
isFullyAwake()581     public boolean isFullyAwake() {
582         return mDozeAmount == 0.0f;
583     }
584 
setOnPulseHeightChangedListener(Runnable onPulseHeightChangedListener)585     public void setOnPulseHeightChangedListener(Runnable onPulseHeightChangedListener) {
586         mOnPulseHeightChangedListener = onPulseHeightChangedListener;
587     }
588 
getOnPulseHeightChangedListener()589     public Runnable getOnPulseHeightChangedListener() {
590         return mOnPulseHeightChangedListener;
591     }
592 
setTrackedHeadsUpRow(ExpandableNotificationRow row)593     public void setTrackedHeadsUpRow(ExpandableNotificationRow row) {
594         mTrackedHeadsUpRow = row;
595     }
596 
597     /**
598      * Set the amount of pixels we have currently dragged down if we're transitioning to the full
599      * shade. 0.0f means we're not transitioning yet.
600      */
setTransitionToFullShadeAmount(float transitionToFullShadeAmount)601     public void setTransitionToFullShadeAmount(float transitionToFullShadeAmount) {
602         mTransitionToFullShadeAmount = transitionToFullShadeAmount;
603     }
604 
605     /**
606      * get
607      */
getTransitionToFullShadeAmount()608     public float getTransitionToFullShadeAmount() {
609         return mTransitionToFullShadeAmount;
610     }
611 
612     /**
613      * Returns the currently tracked heads up row, if there is one and it is currently above the
614      * shelf (still appearing).
615      */
getTrackedHeadsUpRow()616     public ExpandableNotificationRow getTrackedHeadsUpRow() {
617         if (mTrackedHeadsUpRow == null || !mTrackedHeadsUpRow.isAboveShelf()) {
618             return null;
619         }
620         return mTrackedHeadsUpRow;
621     }
622 
setAppearFraction(float appearFraction)623     public void setAppearFraction(float appearFraction) {
624         mAppearFraction = appearFraction;
625     }
626 
getAppearFraction()627     public float getAppearFraction() {
628         return mAppearFraction;
629     }
630 
setHasAlertEntries(boolean hasAlertEntries)631     public void setHasAlertEntries(boolean hasAlertEntries) {
632         mHasAlertEntries = hasAlertEntries;
633     }
634 }
635