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.stack;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.view.View;
22 
23 import com.android.systemui.R;
24 import com.android.systemui.statusbar.ActivatableNotificationView;
25 import com.android.systemui.statusbar.ExpandableNotificationRow;
26 import com.android.systemui.statusbar.ExpandableView;
27 import com.android.systemui.statusbar.NotificationData;
28 import com.android.systemui.statusbar.NotificationShelf;
29 import com.android.systemui.statusbar.StatusBarState;
30 import com.android.systemui.statusbar.policy.HeadsUpManager;
31 
32 import java.util.ArrayList;
33 
34 /**
35  * A global state to track all input states for the algorithm.
36  */
37 public class AmbientState {
38     private ArrayList<View> mDraggedViews = new ArrayList<View>();
39     private int mScrollY;
40     private boolean mDimmed;
41     private ActivatableNotificationView mActivatedChild;
42     private float mOverScrollTopAmount;
43     private float mOverScrollBottomAmount;
44     private int mSpeedBumpIndex = -1;
45     private boolean mDark;
46     private boolean mHideSensitive;
47     private HeadsUpManager mHeadsUpManager;
48     private float mStackTranslation;
49     private int mLayoutHeight;
50     private int mTopPadding;
51     private boolean mShadeExpanded;
52     private float mMaxHeadsUpTranslation;
53     private boolean mDismissAllInProgress;
54     private int mLayoutMinHeight;
55     private NotificationShelf mShelf;
56     private int mZDistanceBetweenElements;
57     private int mBaseZHeight;
58     private int mMaxLayoutHeight;
59     private ActivatableNotificationView mLastVisibleBackgroundChild;
60     private float mCurrentScrollVelocity;
61     private int mStatusBarState;
62     private float mExpandingVelocity;
63     private boolean mPanelTracking;
64     private boolean mExpansionChanging;
65     private boolean mPanelFullWidth;
66     private boolean mPulsing;
67     private boolean mUnlockHintRunning;
68     private boolean mQsCustomizerShowing;
69     private int mIntrinsicPadding;
70     private int mExpandAnimationTopChange;
71     private ExpandableNotificationRow mExpandingNotification;
72     private int mDarkTopPadding;
73     private float mDarkAmount;
74     private boolean mAppearing;
75 
AmbientState(Context context)76     public AmbientState(Context context) {
77         reload(context);
78     }
79 
80     /**
81      * Reload the dimens e.g. if the density changed.
82      */
reload(Context context)83     public void reload(Context context) {
84         mZDistanceBetweenElements = getZDistanceBetweenElements(context);
85         mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
86     }
87 
getZDistanceBetweenElements(Context context)88     private static int getZDistanceBetweenElements(Context context) {
89         return Math.max(1, context.getResources()
90                 .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
91     }
92 
getBaseHeight(int zdistanceBetweenElements)93     private static int getBaseHeight(int zdistanceBetweenElements) {
94         return 4 * zdistanceBetweenElements;
95     }
96 
97     /**
98      * @return the launch height for notifications that are launched
99      */
getNotificationLaunchHeight(Context context)100     public static int getNotificationLaunchHeight(Context context) {
101         int zDistance = getZDistanceBetweenElements(context);
102         return getBaseHeight(zDistance) * 2;
103     }
104 
105     /**
106      * @return the basic Z height on which notifications remain.
107      */
getBaseZHeight()108     public int getBaseZHeight() {
109         return mBaseZHeight;
110     }
111 
112     /**
113      * @return the distance in Z between two overlaying notifications.
114      */
getZDistanceBetweenElements()115     public int getZDistanceBetweenElements() {
116         return mZDistanceBetweenElements;
117     }
118 
getScrollY()119     public int getScrollY() {
120         return mScrollY;
121     }
122 
setScrollY(int scrollY)123     public void setScrollY(int scrollY) {
124         this.mScrollY = scrollY;
125     }
126 
onBeginDrag(View view)127     public void onBeginDrag(View view) {
128         mDraggedViews.add(view);
129     }
130 
onDragFinished(View view)131     public void onDragFinished(View view) {
132         mDraggedViews.remove(view);
133     }
134 
getDraggedViews()135     public ArrayList<View> getDraggedViews() {
136         return mDraggedViews;
137     }
138 
139     /**
140      * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
141      *               translucent and everything is scaled back a bit.
142      */
setDimmed(boolean dimmed)143     public void setDimmed(boolean dimmed) {
144         mDimmed = dimmed;
145     }
146 
147     /** In dark mode, we draw as little as possible, assuming a black background */
setDark(boolean dark)148     public void setDark(boolean dark) {
149         mDark = dark;
150     }
151 
152     /** Dark ratio of the status bar **/
setDarkAmount(float darkAmount)153     public void setDarkAmount(float darkAmount) {
154         mDarkAmount = darkAmount;
155     }
156 
157     /** Returns the dark ratio of the status bar */
getDarkAmount()158     public float getDarkAmount() {
159         return mDarkAmount;
160     }
161 
setHideSensitive(boolean hideSensitive)162     public void setHideSensitive(boolean hideSensitive) {
163         mHideSensitive = hideSensitive;
164     }
165 
166     /**
167      * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
168      * interaction. This child is then scaled normally and its background is fully opaque.
169      */
setActivatedChild(ActivatableNotificationView activatedChild)170     public void setActivatedChild(ActivatableNotificationView activatedChild) {
171         mActivatedChild = activatedChild;
172     }
173 
isDimmed()174     public boolean isDimmed() {
175         return mDimmed;
176     }
177 
isDark()178     public boolean isDark() {
179         return mDark;
180     }
181 
isHideSensitive()182     public boolean isHideSensitive() {
183         return mHideSensitive;
184     }
185 
getActivatedChild()186     public ActivatableNotificationView getActivatedChild() {
187         return mActivatedChild;
188     }
189 
setOverScrollAmount(float amount, boolean onTop)190     public void setOverScrollAmount(float amount, boolean onTop) {
191         if (onTop) {
192             mOverScrollTopAmount = amount;
193         } else {
194             mOverScrollBottomAmount = amount;
195         }
196     }
197 
getOverScrollAmount(boolean top)198     public float getOverScrollAmount(boolean top) {
199         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
200     }
201 
getSpeedBumpIndex()202     public int getSpeedBumpIndex() {
203         return mSpeedBumpIndex;
204     }
205 
setSpeedBumpIndex(int shelfIndex)206     public void setSpeedBumpIndex(int shelfIndex) {
207         mSpeedBumpIndex = shelfIndex;
208     }
209 
setHeadsUpManager(HeadsUpManager headsUpManager)210     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
211         mHeadsUpManager = headsUpManager;
212     }
213 
getStackTranslation()214     public float getStackTranslation() {
215         return mStackTranslation;
216     }
217 
setStackTranslation(float stackTranslation)218     public void setStackTranslation(float stackTranslation) {
219         mStackTranslation = stackTranslation;
220     }
221 
setLayoutHeight(int layoutHeight)222     public void setLayoutHeight(int layoutHeight) {
223         mLayoutHeight = layoutHeight;
224     }
225 
getTopPadding()226     public float getTopPadding() {
227         return mTopPadding;
228     }
229 
setTopPadding(int topPadding)230     public void setTopPadding(int topPadding) {
231         mTopPadding = topPadding;
232     }
233 
getInnerHeight()234     public int getInnerHeight() {
235         return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding, mLayoutMinHeight);
236     }
237 
isShadeExpanded()238     public boolean isShadeExpanded() {
239         return mShadeExpanded;
240     }
241 
setShadeExpanded(boolean shadeExpanded)242     public void setShadeExpanded(boolean shadeExpanded) {
243         mShadeExpanded = shadeExpanded;
244     }
245 
setMaxHeadsUpTranslation(float maxHeadsUpTranslation)246     public void setMaxHeadsUpTranslation(float maxHeadsUpTranslation) {
247         mMaxHeadsUpTranslation = maxHeadsUpTranslation;
248     }
249 
getMaxHeadsUpTranslation()250     public float getMaxHeadsUpTranslation() {
251         return mMaxHeadsUpTranslation;
252     }
253 
setDismissAllInProgress(boolean dismissAllInProgress)254     public void setDismissAllInProgress(boolean dismissAllInProgress) {
255         mDismissAllInProgress = dismissAllInProgress;
256     }
257 
isDismissAllInProgress()258     public boolean isDismissAllInProgress() {
259         return mDismissAllInProgress;
260     }
261 
setLayoutMinHeight(int layoutMinHeight)262     public void setLayoutMinHeight(int layoutMinHeight) {
263         mLayoutMinHeight = layoutMinHeight;
264     }
265 
setShelf(NotificationShelf shelf)266     public void setShelf(NotificationShelf shelf) {
267         mShelf = shelf;
268     }
269 
270     @Nullable
getShelf()271     public NotificationShelf getShelf() {
272         return mShelf;
273     }
274 
setLayoutMaxHeight(int maxLayoutHeight)275     public void setLayoutMaxHeight(int maxLayoutHeight) {
276         mMaxLayoutHeight = maxLayoutHeight;
277     }
278 
279     /**
280      * Sets the last visible view of the host layout, that has a background, i.e the very last
281      * view in the shade, without the clear all button.
282      */
setLastVisibleBackgroundChild( ActivatableNotificationView lastVisibleBackgroundChild)283     public void setLastVisibleBackgroundChild(
284             ActivatableNotificationView lastVisibleBackgroundChild) {
285         mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
286     }
287 
getLastVisibleBackgroundChild()288     public ActivatableNotificationView getLastVisibleBackgroundChild() {
289         return mLastVisibleBackgroundChild;
290     }
291 
setCurrentScrollVelocity(float currentScrollVelocity)292     public void setCurrentScrollVelocity(float currentScrollVelocity) {
293         mCurrentScrollVelocity = currentScrollVelocity;
294     }
295 
getCurrentScrollVelocity()296     public float getCurrentScrollVelocity() {
297         return mCurrentScrollVelocity;
298     }
299 
isOnKeyguard()300     public boolean isOnKeyguard() {
301         return mStatusBarState == StatusBarState.KEYGUARD;
302     }
303 
setStatusBarState(int statusBarState)304     public void setStatusBarState(int statusBarState) {
305         mStatusBarState = statusBarState;
306     }
307 
setExpandingVelocity(float expandingVelocity)308     public void setExpandingVelocity(float expandingVelocity) {
309         mExpandingVelocity = expandingVelocity;
310     }
311 
setExpansionChanging(boolean expansionChanging)312     public void setExpansionChanging(boolean expansionChanging) {
313         mExpansionChanging = expansionChanging;
314     }
315 
isExpansionChanging()316     public boolean isExpansionChanging() {
317         return mExpansionChanging;
318     }
319 
getExpandingVelocity()320     public float getExpandingVelocity() {
321         return mExpandingVelocity;
322     }
323 
setPanelTracking(boolean panelTracking)324     public void setPanelTracking(boolean panelTracking) {
325         mPanelTracking = panelTracking;
326     }
327 
hasPulsingNotifications()328     public boolean hasPulsingNotifications() {
329         return mPulsing;
330     }
331 
setPulsing(boolean hasPulsing)332     public void setPulsing(boolean hasPulsing) {
333         mPulsing = hasPulsing;
334     }
335 
isPulsing(NotificationData.Entry entry)336     public boolean isPulsing(NotificationData.Entry entry) {
337         if (!mPulsing || mHeadsUpManager == null) {
338             return false;
339         }
340         return mHeadsUpManager.getAllEntries().anyMatch(e -> (e == entry));
341     }
342 
isPanelTracking()343     public boolean isPanelTracking() {
344         return mPanelTracking;
345     }
346 
isPanelFullWidth()347     public boolean isPanelFullWidth() {
348         return mPanelFullWidth;
349     }
350 
setPanelFullWidth(boolean panelFullWidth)351     public void setPanelFullWidth(boolean panelFullWidth) {
352         mPanelFullWidth = panelFullWidth;
353     }
354 
setUnlockHintRunning(boolean unlockHintRunning)355     public void setUnlockHintRunning(boolean unlockHintRunning) {
356         mUnlockHintRunning = unlockHintRunning;
357     }
358 
isUnlockHintRunning()359     public boolean isUnlockHintRunning() {
360         return mUnlockHintRunning;
361     }
362 
isQsCustomizerShowing()363     public boolean isQsCustomizerShowing() {
364         return mQsCustomizerShowing;
365     }
366 
setQsCustomizerShowing(boolean qsCustomizerShowing)367     public void setQsCustomizerShowing(boolean qsCustomizerShowing) {
368         mQsCustomizerShowing = qsCustomizerShowing;
369     }
370 
setIntrinsicPadding(int intrinsicPadding)371     public void setIntrinsicPadding(int intrinsicPadding) {
372         mIntrinsicPadding = intrinsicPadding;
373     }
374 
getIntrinsicPadding()375     public int getIntrinsicPadding() {
376         return mIntrinsicPadding;
377     }
378 
379     /**
380      * Similar to the normal is above shelf logic but doesn't allow it to be above in AOD1.
381      *
382      * @param expandableView the view to check
383      */
isAboveShelf(ExpandableView expandableView)384     public boolean isAboveShelf(ExpandableView expandableView) {
385         if (!(expandableView instanceof ExpandableNotificationRow)) {
386             return expandableView.isAboveShelf();
387         }
388         ExpandableNotificationRow row = (ExpandableNotificationRow) expandableView;
389         return row.isAboveShelf() && !isDozingAndNotPulsing(row);
390     }
391 
392     /**
393      * @return whether a view is dozing and not pulsing right now
394      */
isDozingAndNotPulsing(ExpandableView view)395     public boolean isDozingAndNotPulsing(ExpandableView view) {
396         if (view instanceof ExpandableNotificationRow) {
397             return isDozingAndNotPulsing((ExpandableNotificationRow) view);
398         }
399         return false;
400     }
401 
402     /**
403      * @return whether a row is dozing and not pulsing right now
404      */
isDozingAndNotPulsing(ExpandableNotificationRow row)405     public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
406         return isDark() && !isPulsing(row.getEntry());
407     }
408 
setExpandAnimationTopChange(int expandAnimationTopChange)409     public void setExpandAnimationTopChange(int expandAnimationTopChange) {
410         mExpandAnimationTopChange = expandAnimationTopChange;
411     }
412 
setExpandingNotification(ExpandableNotificationRow row)413     public void setExpandingNotification(ExpandableNotificationRow row) {
414         mExpandingNotification = row;
415     }
416 
getExpandingNotification()417     public ExpandableNotificationRow getExpandingNotification() {
418         return mExpandingNotification;
419     }
420 
getExpandAnimationTopChange()421     public int getExpandAnimationTopChange() {
422         return mExpandAnimationTopChange;
423     }
424 
425     /**
426      * @return {@code true } when shade is completely dark: in AOD or ambient display.
427      */
isFullyDark()428     public boolean isFullyDark() {
429         return mDarkAmount == 1;
430     }
431 
setDarkTopPadding(int darkTopPadding)432     public void setDarkTopPadding(int darkTopPadding) {
433         mDarkTopPadding = darkTopPadding;
434     }
435 
getDarkTopPadding()436     public int getDarkTopPadding() {
437         return mDarkTopPadding;
438     }
439 
setAppearing(boolean appearing)440     public void setAppearing(boolean appearing) {
441         mAppearing = appearing;
442     }
443 
isAppearing()444     public boolean isAppearing() {
445         return mAppearing;
446     }
447 }
448