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
17package com.android.systemui.statusbar.stack;
18
19import android.annotation.Nullable;
20import android.content.Context;
21import android.view.View;
22
23import com.android.systemui.R;
24import com.android.systemui.statusbar.ActivatableNotificationView;
25import com.android.systemui.statusbar.ExpandableNotificationRow;
26import com.android.systemui.statusbar.ExpandableView;
27import com.android.systemui.statusbar.NotificationData;
28import com.android.systemui.statusbar.NotificationShelf;
29import com.android.systemui.statusbar.StatusBarState;
30import com.android.systemui.statusbar.policy.HeadsUpManager;
31
32import java.util.ArrayList;
33
34/**
35 * A global state to track all input states for the algorithm.
36 */
37public 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
76    public AmbientState(Context context) {
77        reload(context);
78    }
79
80    /**
81     * Reload the dimens e.g. if the density changed.
82     */
83    public void reload(Context context) {
84        mZDistanceBetweenElements = getZDistanceBetweenElements(context);
85        mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
86    }
87
88    private static int getZDistanceBetweenElements(Context context) {
89        return Math.max(1, context.getResources()
90                .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
91    }
92
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     */
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     */
108    public int getBaseZHeight() {
109        return mBaseZHeight;
110    }
111
112    /**
113     * @return the distance in Z between two overlaying notifications.
114     */
115    public int getZDistanceBetweenElements() {
116        return mZDistanceBetweenElements;
117    }
118
119    public int getScrollY() {
120        return mScrollY;
121    }
122
123    public void setScrollY(int scrollY) {
124        this.mScrollY = scrollY;
125    }
126
127    public void onBeginDrag(View view) {
128        mDraggedViews.add(view);
129    }
130
131    public void onDragFinished(View view) {
132        mDraggedViews.remove(view);
133    }
134
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     */
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 */
148    public void setDark(boolean dark) {
149        mDark = dark;
150    }
151
152    /** Dark ratio of the status bar **/
153    public void setDarkAmount(float darkAmount) {
154        mDarkAmount = darkAmount;
155    }
156
157    /** Returns the dark ratio of the status bar */
158    public float getDarkAmount() {
159        return mDarkAmount;
160    }
161
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     */
170    public void setActivatedChild(ActivatableNotificationView activatedChild) {
171        mActivatedChild = activatedChild;
172    }
173
174    public boolean isDimmed() {
175        return mDimmed;
176    }
177
178    public boolean isDark() {
179        return mDark;
180    }
181
182    public boolean isHideSensitive() {
183        return mHideSensitive;
184    }
185
186    public ActivatableNotificationView getActivatedChild() {
187        return mActivatedChild;
188    }
189
190    public void setOverScrollAmount(float amount, boolean onTop) {
191        if (onTop) {
192            mOverScrollTopAmount = amount;
193        } else {
194            mOverScrollBottomAmount = amount;
195        }
196    }
197
198    public float getOverScrollAmount(boolean top) {
199        return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
200    }
201
202    public int getSpeedBumpIndex() {
203        return mSpeedBumpIndex;
204    }
205
206    public void setSpeedBumpIndex(int shelfIndex) {
207        mSpeedBumpIndex = shelfIndex;
208    }
209
210    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
211        mHeadsUpManager = headsUpManager;
212    }
213
214    public float getStackTranslation() {
215        return mStackTranslation;
216    }
217
218    public void setStackTranslation(float stackTranslation) {
219        mStackTranslation = stackTranslation;
220    }
221
222    public void setLayoutHeight(int layoutHeight) {
223        mLayoutHeight = layoutHeight;
224    }
225
226    public float getTopPadding() {
227        return mTopPadding;
228    }
229
230    public void setTopPadding(int topPadding) {
231        mTopPadding = topPadding;
232    }
233
234    public int getInnerHeight() {
235        return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding, mLayoutMinHeight);
236    }
237
238    public boolean isShadeExpanded() {
239        return mShadeExpanded;
240    }
241
242    public void setShadeExpanded(boolean shadeExpanded) {
243        mShadeExpanded = shadeExpanded;
244    }
245
246    public void setMaxHeadsUpTranslation(float maxHeadsUpTranslation) {
247        mMaxHeadsUpTranslation = maxHeadsUpTranslation;
248    }
249
250    public float getMaxHeadsUpTranslation() {
251        return mMaxHeadsUpTranslation;
252    }
253
254    public void setDismissAllInProgress(boolean dismissAllInProgress) {
255        mDismissAllInProgress = dismissAllInProgress;
256    }
257
258    public boolean isDismissAllInProgress() {
259        return mDismissAllInProgress;
260    }
261
262    public void setLayoutMinHeight(int layoutMinHeight) {
263        mLayoutMinHeight = layoutMinHeight;
264    }
265
266    public void setShelf(NotificationShelf shelf) {
267        mShelf = shelf;
268    }
269
270    @Nullable
271    public NotificationShelf getShelf() {
272        return mShelf;
273    }
274
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     */
283    public void setLastVisibleBackgroundChild(
284            ActivatableNotificationView lastVisibleBackgroundChild) {
285        mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
286    }
287
288    public ActivatableNotificationView getLastVisibleBackgroundChild() {
289        return mLastVisibleBackgroundChild;
290    }
291
292    public void setCurrentScrollVelocity(float currentScrollVelocity) {
293        mCurrentScrollVelocity = currentScrollVelocity;
294    }
295
296    public float getCurrentScrollVelocity() {
297        return mCurrentScrollVelocity;
298    }
299
300    public boolean isOnKeyguard() {
301        return mStatusBarState == StatusBarState.KEYGUARD;
302    }
303
304    public void setStatusBarState(int statusBarState) {
305        mStatusBarState = statusBarState;
306    }
307
308    public void setExpandingVelocity(float expandingVelocity) {
309        mExpandingVelocity = expandingVelocity;
310    }
311
312    public void setExpansionChanging(boolean expansionChanging) {
313        mExpansionChanging = expansionChanging;
314    }
315
316    public boolean isExpansionChanging() {
317        return mExpansionChanging;
318    }
319
320    public float getExpandingVelocity() {
321        return mExpandingVelocity;
322    }
323
324    public void setPanelTracking(boolean panelTracking) {
325        mPanelTracking = panelTracking;
326    }
327
328    public boolean hasPulsingNotifications() {
329        return mPulsing;
330    }
331
332    public void setPulsing(boolean hasPulsing) {
333        mPulsing = hasPulsing;
334    }
335
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
343    public boolean isPanelTracking() {
344        return mPanelTracking;
345    }
346
347    public boolean isPanelFullWidth() {
348        return mPanelFullWidth;
349    }
350
351    public void setPanelFullWidth(boolean panelFullWidth) {
352        mPanelFullWidth = panelFullWidth;
353    }
354
355    public void setUnlockHintRunning(boolean unlockHintRunning) {
356        mUnlockHintRunning = unlockHintRunning;
357    }
358
359    public boolean isUnlockHintRunning() {
360        return mUnlockHintRunning;
361    }
362
363    public boolean isQsCustomizerShowing() {
364        return mQsCustomizerShowing;
365    }
366
367    public void setQsCustomizerShowing(boolean qsCustomizerShowing) {
368        mQsCustomizerShowing = qsCustomizerShowing;
369    }
370
371    public void setIntrinsicPadding(int intrinsicPadding) {
372        mIntrinsicPadding = intrinsicPadding;
373    }
374
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     */
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     */
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     */
405    public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
406        return isDark() && !isPulsing(row.getEntry());
407    }
408
409    public void setExpandAnimationTopChange(int expandAnimationTopChange) {
410        mExpandAnimationTopChange = expandAnimationTopChange;
411    }
412
413    public void setExpandingNotification(ExpandableNotificationRow row) {
414        mExpandingNotification = row;
415    }
416
417    public ExpandableNotificationRow getExpandingNotification() {
418        return mExpandingNotification;
419    }
420
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     */
428    public boolean isFullyDark() {
429        return mDarkAmount == 1;
430    }
431
432    public void setDarkTopPadding(int darkTopPadding) {
433        mDarkTopPadding = darkTopPadding;
434    }
435
436    public int getDarkTopPadding() {
437        return mDarkTopPadding;
438    }
439
440    public void setAppearing(boolean appearing) {
441        mAppearing = appearing;
442    }
443
444    public boolean isAppearing() {
445        return mAppearing;
446    }
447}
448