blob: b4989c0dba7fc2e58e880965d54d0d1615da313b [file] [log] [blame]
Daniel Sandler08d05e32012-08-08 16:39:54 -04001/*
2 * Copyright (C) 2012 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.phone;
18
Jason Monk1fd3fc32018-08-14 17:20:09 -040019import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
20 .ExpandAnimationParameters;
Selim Cinek2627d722018-01-19 12:16:49 -080021
Jorim Jaggid7daab72014-05-06 22:22:20 +020022import android.animation.Animator;
23import android.animation.AnimatorListenerAdapter;
Jorim Jaggi75c95042014-05-16 19:09:59 +020024import android.animation.ObjectAnimator;
Jorim Jaggid7daab72014-05-06 22:22:20 +020025import android.animation.ValueAnimator;
Zhentao Sun04f97402015-08-26 17:37:30 -070026import android.app.ActivityManager;
Jason Monk0ceef212016-11-02 14:05:23 -040027import android.app.Fragment;
Jorim Jaggi40aa8812015-09-23 12:59:22 -070028import android.app.StatusBarManager;
Daniel Sandler08d05e32012-08-08 16:39:54 -040029import android.content.Context;
Zhentao Sun04f97402015-08-26 17:37:30 -070030import android.content.pm.ResolveInfo;
Selim Cinek4c6969a2014-05-26 19:22:17 +020031import android.content.res.Configuration;
Anthony Chen04d1ea72017-04-21 14:30:11 -070032import android.content.res.Resources;
Jorim Jaggi58bef332014-11-21 18:10:32 +010033import android.graphics.Canvas;
34import android.graphics.Color;
35import android.graphics.Paint;
shawnlin4ef7ca52018-05-11 16:44:42 +080036import android.graphics.PorterDuff;
37import android.graphics.PorterDuffXfermode;
Jorim Jaggi613f55f2015-07-16 15:30:10 -070038import android.graphics.Rect;
Selim Cineke64f52a2017-08-24 14:48:38 -070039import android.os.PowerManager;
Daniel Sandler08d05e32012-08-08 16:39:54 -040040import android.util.AttributeSet;
Adrian Roos52414e32017-04-28 09:23:19 -070041import android.util.FloatProperty;
Lucas Dupin41ff6952018-02-18 19:39:32 -080042import android.util.Log;
Jorim Jaggi3afddce2014-08-14 20:44:43 +020043import android.util.MathUtils;
Lucas Dupin987f1932017-05-13 21:02:52 -070044import android.view.LayoutInflater;
Daniel Sandler040c2e42012-10-17 00:56:33 -040045import android.view.MotionEvent;
Jorim Jaggid7daab72014-05-06 22:22:20 +020046import android.view.VelocityTracker;
Daniel Sandler13522a22012-09-27 14:46:58 -040047import android.view.View;
Jason Monk0ceef212016-11-02 14:05:23 -040048import android.view.ViewGroup;
Selim Cinekb8f09cf2015-03-16 17:09:28 -070049import android.view.WindowInsets;
Phil Weaver428e3972018-01-18 12:50:05 -080050import android.view.accessibility.AccessibilityManager;
Jorim Jaggic4cf07a2018-07-05 18:28:12 +020051import android.view.animation.Interpolator;
John Spurlock7e6809a2014-08-06 16:03:14 -040052import android.widget.FrameLayout;
Lucas Dupin0cd882f2018-01-30 12:19:49 -080053
Chris Wren49f06f52015-05-01 16:12:12 -040054import com.android.internal.logging.MetricsLogger;
Chris Wren27a52fa2017-02-01 14:21:43 -050055import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jorim Jaggid09def7512014-09-02 18:36:45 +020056import com.android.keyguard.KeyguardStatusView;
Jorim Jaggi613f55f2015-07-16 15:30:10 -070057import com.android.systemui.DejankUtils;
Jason Monk1fd3fc32018-08-14 17:20:09 -040058import com.android.systemui.Dependency;
Winsonc0d70582016-01-29 10:24:39 -080059import com.android.systemui.Interpolators;
Chet Haase4d179dc2012-08-22 07:14:42 -070060import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070061import com.android.systemui.classifier.FalsingManager;
Jason Monk0ceef212016-11-02 14:05:23 -040062import com.android.systemui.fragments.FragmentHostManager;
63import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
64import com.android.systemui.plugins.qs.QS;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +020065import com.android.systemui.statusbar.FlingAnimationUtils;
Daniel Sandler151f00d2012-10-02 22:33:08 -040066import com.android.systemui.statusbar.GestureRecorder;
Selim Cinekbaa23272014-07-08 18:01:07 +020067import com.android.systemui.statusbar.KeyguardAffordanceView;
Lucas Dupin987f1932017-05-13 21:02:52 -070068import com.android.systemui.statusbar.KeyguardIndicationController;
Anthony Chen9e05d462017-04-07 10:10:21 -070069import com.android.systemui.statusbar.NotificationShelf;
Jorim Jaggiecbab362014-04-23 16:13:15 +020070import com.android.systemui.statusbar.StatusBarState;
Jason Monk1fd3fc32018-08-14 17:20:09 -040071import com.android.systemui.statusbar.StatusBarStateController;
72import com.android.systemui.statusbar.StatusBarStateController.StateListener;
Selim Cinek2627d722018-01-19 12:16:49 -080073import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Lucas Dupin60661a62018-04-12 10:50:13 -070074import com.android.systemui.statusbar.notification.AnimatableProperty;
Jason Monk1fd3fc32018-08-14 17:20:09 -040075import com.android.systemui.statusbar.notification.NotificationData;
Lucas Dupin60661a62018-04-12 10:50:13 -070076import com.android.systemui.statusbar.notification.PropertyAnimator;
Jason Monk1fd3fc32018-08-14 17:20:09 -040077import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
78import com.android.systemui.statusbar.notification.row.ExpandableView;
Rohan Shah20790b82018-07-02 17:21:04 -070079import com.android.systemui.statusbar.notification.stack.AnimationProperties;
80import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
81import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
Jason Monk1fd3fc32018-08-14 17:20:09 -040082import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
83import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
Daniel Sandler08d05e32012-08-08 16:39:54 -040084
Lucas Dupinc510d412018-06-12 13:08:23 -070085import java.io.FileDescriptor;
86import java.io.PrintWriter;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080087import java.util.ArrayList;
Zhentao Sun04f97402015-08-26 17:37:30 -070088import java.util.List;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080089import java.util.function.Consumer;
Zhentao Sun04f97402015-08-26 17:37:30 -070090
Jorim Jaggibe565df2014-04-28 17:51:23 +020091public class NotificationPanelView extends PanelView implements
Jason Monk8b9d67f2016-03-02 08:59:08 -050092 ExpandableView.OnHeightChangedListener,
Jorim Jaggi290600a2014-05-30 17:02:20 +020093 View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
Selim Cinekb8f09cf2015-03-16 17:09:28 -070094 KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
Selim Cineka7d4f822016-12-06 14:34:47 -080095 OnHeadsUpChangedListener, QS.HeightListener {
Chet Haase4d179dc2012-08-22 07:14:42 -070096
Jorim Jaggi58bef332014-11-21 18:10:32 +010097 private static final boolean DEBUG = false;
98
Lucas Dupinee63c372018-08-03 11:58:24 -070099 /**
100 * Fling expanding QS.
101 */
102 public static final int FLING_EXPAND = 0;
103
104 /**
105 * Fling collapsing QS, potentially stopping when QS becomes QQS.
106 */
107 public static final int FLING_COLLAPSE = 1;
108
109 /**
110 * Fing until QS is completely hidden.
111 */
112 public static final int FLING_HIDE = 2;
113
Selim Cinekf99d0002014-06-13 07:36:01 +0200114 // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
115 // changed.
116 private static final int CAP_HEIGHT = 1456;
117 private static final int FONT_HEIGHT = 2163;
118
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200119 private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
Selim Cineka02fe522014-05-30 17:01:21 +0200120
Doris Ling3c00afb2016-07-19 17:04:21 -0700121 static final String COUNTER_PANEL_OPEN = "panel_open";
122 static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
Chris Wren49f06f52015-05-01 16:12:12 -0400123 private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
124
Jorim Jaggi613f55f2015-07-16 15:30:10 -0700125 private static final Rect mDummyDirtyRect = new Rect(0, 0, 1, 1);
126
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100127 public static final long DOZE_ANIMATION_DURATION = 700;
John Spurlock8b12f222014-09-09 11:54:11 -0400128
Lucas Dupin60661a62018-04-12 10:50:13 -0700129 private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties()
130 .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Adrian Roos52414e32017-04-28 09:23:19 -0700131 private static final FloatProperty<NotificationPanelView> SET_DARK_AMOUNT_PROPERTY =
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200132 new FloatProperty<NotificationPanelView>("mInterpolatedDarkAmount") {
133
Adrian Roos52414e32017-04-28 09:23:19 -0700134 @Override
135 public void setValue(NotificationPanelView object, float value) {
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200136 object.setDarkAmount(value, object.mDarkInterpolator.getInterpolation(value));
Adrian Roos52414e32017-04-28 09:23:19 -0700137 }
138
139 @Override
140 public Float get(NotificationPanelView object) {
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200141 return object.mLinearDarkAmount;
Adrian Roos52414e32017-04-28 09:23:19 -0700142 }
143 };
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200144
145 private Interpolator mDarkInterpolator;
Selim Cineke64f52a2017-08-24 14:48:38 -0700146 private final PowerManager mPowerManager;
Phil Weaver428e3972018-01-18 12:50:05 -0800147 private final AccessibilityManager mAccessibilityManager;
Adrian Roos52414e32017-04-28 09:23:19 -0700148
Adrian Roose31f30e2017-01-25 14:48:15 -0800149 private KeyguardAffordanceHelper mAffordanceHelper;
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200150 private KeyguardUserSwitcher mKeyguardUserSwitcher;
Jorim Jaggi4538027d2014-07-30 15:43:13 +0200151 private KeyguardStatusBarView mKeyguardStatusBar;
Jason Monk0ceef212016-11-02 14:05:23 -0400152 private QS mQs;
153 private FrameLayout mQsFrame;
Jorim Jaggid09def7512014-09-02 18:36:45 +0200154 private KeyguardStatusView mKeyguardStatusView;
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200155 private View mQsNavbarScrim;
Xiaohui Chen5da71352016-02-22 10:04:41 -0800156 protected NotificationsQuickSettingsContainer mNotificationContainerParent;
Xiaohui Chen9528f432016-02-12 15:03:18 -0800157 protected NotificationStackScrollLayout mNotificationStackScroller;
Lucas Dupin60661a62018-04-12 10:50:13 -0700158 private boolean mAnimateNextPositionUpdate;
Chet Haase4d179dc2012-08-22 07:14:42 -0700159
Jorim Jaggid7daab72014-05-06 22:22:20 +0200160 private int mTrackingPointer;
Selim Cinekd5ab6452016-12-08 16:34:00 -0800161 private VelocityTracker mQsVelocityTracker;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200162 private boolean mQsTracking;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200163
164 /**
Jorim Jaggidc96d632014-07-01 18:48:52 +0200165 * If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
166 * the expansion for quick settings.
167 */
168 private boolean mConflictingQsExpansionGesture;
169
170 /**
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200171 * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
172 * intercepted yet.
173 */
174 private boolean mIntercepting;
Selim Cinek4a21a7f2015-05-19 11:00:38 -0700175 private boolean mPanelExpanded;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200176 private boolean mQsExpanded;
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200177 private boolean mQsExpandedWhenExpandingStarted;
John Spurlockbc3a5e92014-05-30 16:20:05 -0400178 private boolean mQsFullyExpanded;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200179 private boolean mKeyguardShowing;
John Spurlockd54da8a2014-08-03 23:23:52 -0400180 private boolean mDozing;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +0100181 private boolean mDozingOnDown;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400182 protected int mBarState;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200183 private float mInitialHeightOnTouch;
184 private float mInitialTouchX;
185 private float mInitialTouchY;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200186 private float mLastTouchX;
187 private float mLastTouchY;
Xiaohui Chen9528f432016-02-12 15:03:18 -0800188 protected float mQsExpansionHeight;
189 protected int mQsMinExpansionHeight;
190 protected int mQsMaxExpansionHeight;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200191 private int mQsPeekHeight;
Lucas Dupin4c2aa392018-03-28 18:00:45 -0700192 private int mBouncerTop;
Jorim Jaggi290600a2014-05-30 17:02:20 +0200193 private boolean mStackScrollerOverscrolling;
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200194 private boolean mQsExpansionFromOverscroll;
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200195 private float mLastOverscroll;
Muyuan Li59690042016-03-23 16:45:16 -0700196 protected boolean mQsExpansionEnabled = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200197 private ValueAnimator mQsExpansionAnimator;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +0200198 private FlingAnimationUtils mFlingAnimationUtils;
Selim Cinek9dbbca82014-05-15 15:23:37 +0200199 private int mStatusBarMinHeight;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200200 private boolean mUnlockIconActive;
Jorim Jaggi457cc352014-06-02 22:47:42 +0200201 private int mNotificationsHeaderCollideDistance;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200202 private int mUnlockMoveDistance;
Jorim Jaggi48bc36a2014-07-25 23:16:04 +0200203 private float mEmptyDragAmount;
John Spurlock3e04cc82014-05-30 12:34:03 -0400204
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200205 private KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
206 new KeyguardClockPositionAlgorithm();
207 private KeyguardClockPositionAlgorithm.Result mClockPositionResult =
208 new KeyguardClockPositionAlgorithm.Result();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200209 private boolean mIsExpanding;
Selim Cinekf99d0002014-06-13 07:36:01 +0200210
Selim Cinek4c6969a2014-05-26 19:22:17 +0200211 private boolean mBlockTouches;
Jason Monk3c68ca22015-01-30 11:30:29 -0500212 // Used for two finger gesture as well as accessibility shortcut to QS.
213 private boolean mQsExpandImmediate;
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200214 private boolean mTwoFingerQsExpandPossible;
Jorim Jaggi56306252014-07-03 00:40:09 +0200215
216 /**
217 * If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
218 * need to take this into account in our panel height calculation.
219 */
Jorim Jaggibd003102014-07-04 00:02:42 +0200220 private boolean mQsAnimatorExpand;
Selim Cinekbaa23272014-07-08 18:01:07 +0200221 private boolean mIsLaunchTransitionFinished;
222 private boolean mIsLaunchTransitionRunning;
223 private Runnable mLaunchAnimationEndRunnable;
224 private boolean mOnlyAffordanceInThisMotion;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200225 private boolean mKeyguardStatusViewAnimating;
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100226 private ValueAnimator mQsSizeChangeAnimator;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200227
Selim Cinek24176c32017-03-01 16:50:30 -0800228 private boolean mShowEmptyShadeView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200229
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200230 private boolean mQsScrimEnabled = true;
Selim Cinek90c94652014-08-18 16:46:22 +0200231 private boolean mLastAnnouncementWasQuickSettings;
Selim Cinek19c8c702014-08-25 22:09:19 +0200232 private boolean mQsTouchAboveFalsingThreshold;
233 private int mQsFalsingThreshold;
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200234
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100235 private float mKeyguardStatusBarAnimateAlpha = 1f;
Jorim Jaggi0a818222014-11-10 19:04:34 +0100236 private int mOldLayoutDirection;
Selim Cinek684a4422015-04-15 16:18:39 -0700237 private HeadsUpTouchHelper mHeadsUpTouchHelper;
238 private boolean mIsExpansionFromHeadsUp;
Selim Cinek79d79c42015-05-21 16:14:45 -0700239 private boolean mListenForHeadsUp;
Selim Cinek684a4422015-04-15 16:18:39 -0700240 private int mNavigationBarBottomHeight;
Selim Cinekd2281152015-04-10 14:37:46 -0700241 private boolean mExpandingFromHeadsUp;
Selim Cinek684a4422015-04-15 16:18:39 -0700242 private boolean mCollapsedOnDown;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700243 private int mPositionMinSideMargin;
Selim Cineka981d082016-08-03 14:45:31 -0700244 private int mMaxFadeoutHeight;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700245 private int mLastOrientation = -1;
Selim Cinekbbc580b2015-06-03 14:11:03 +0200246 private boolean mClosingWithAlphaFadeOut;
Selim Cinek0fccc722015-07-29 17:04:36 -0700247 private boolean mHeadsUpAnimatingAway;
Selim Cinek372d1bd2015-08-14 13:19:37 -0700248 private boolean mLaunchingAffordance;
Lucas Dupin193677c2018-06-11 19:16:03 -0700249 private boolean mAffordanceHasPreview;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700250 private FalsingManager mFalsingManager;
Jorim Jaggi40aa8812015-09-23 12:59:22 -0700251 private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700252
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700253 private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
254 @Override
255 public void run() {
Selim Cinekcafa87f2016-10-26 17:00:17 -0700256 setHeadsUpAnimatingAway(false);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700257 notifyBarPanelExpansionChanged();
258 }
259 };
Selim Cinek53f8e7d2016-03-25 02:28:01 -0700260 private NotificationGroupManager mGroupManager;
Selim Cinek24176c32017-03-01 16:50:30 -0800261 private boolean mShowIconsWhenExpanded;
Selim Cinek378053a2016-12-07 15:41:28 -0800262 private int mIndicationBottomPadding;
Adrian Roos75fa9642017-04-18 11:34:56 -0700263 private int mAmbientIndicationBottomPadding;
Selim Cinekfcff4c62016-12-27 14:26:06 +0100264 private boolean mIsFullWidth;
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200265
266 /**
267 * Current dark amount that follows regular interpolation curve of animation.
268 */
269 private float mInterpolatedDarkAmount;
270
271 /**
272 * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the
273 * interpolation curve is different.
274 */
275 private float mLinearDarkAmount;
276
Adrian Roos51465ea2017-07-27 13:57:35 +0200277 private float mDarkAmountTarget;
Lucas Dupin56057342018-04-10 11:49:18 -0700278 private boolean mPulsing;
Chris Wren27a52fa2017-02-01 14:21:43 -0500279 private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
Selim Cinek24176c32017-03-01 16:50:30 -0800280 private boolean mNoVisibleNotifications = true;
Adrian Roos52414e32017-04-28 09:23:19 -0700281 private ValueAnimator mDarkAnimator;
Lucas Dupin987f1932017-05-13 21:02:52 -0700282 private boolean mUserSetupComplete;
Selim Cinekd7768f42017-11-22 06:43:44 -0800283 private int mQsNotificationTopPadding;
Selim Cinek2627d722018-01-19 12:16:49 -0800284 private float mExpandOffset;
285 private boolean mHideIconsDuringNotificationLaunch = true;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800286 private int mStackScrollerMeasuringPass;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800287 private ArrayList<Consumer<ExpandableNotificationRow>> mTrackingHeadsUpListeners
288 = new ArrayList<>();
Selim Cinek60ffea62018-03-22 13:16:44 -0700289 private ArrayList<Runnable> mVerticalTranslationListener = new ArrayList<>();
Selim Cinek332c23f2018-03-16 17:37:50 -0700290 private HeadsUpAppearanceController mHeadsUpAppearanceController;
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100291
shawnlin4ef7ca52018-05-11 16:44:42 +0800292 private int mPanelAlpha;
293 private int mCurrentPanelAlpha;
294 private final Paint mAlphaPaint = new Paint();
295 private Runnable mPanelAlphaEndAction;
296 private AnimatorListenerAdapter mAnimatorListenerAdapter = new AnimatorListenerAdapter() {
297 @Override
298 public void onAnimationEnd(Animator animation) {
299 if (mPanelAlphaEndAction != null) {
300 mPanelAlphaEndAction.run();
301 }
302 }
303 };
304 private final AnimatableProperty PANEL_ALPHA = AnimatableProperty.from(
305 "panelAlpha",
306 NotificationPanelView::setPanelAlphaInternal,
307 NotificationPanelView::getCurrentPanelAlpha,
308 R.id.panel_alpha_animator_tag,
309 R.id.panel_alpha_animator_start_tag,
310 R.id.panel_alpha_animator_end_tag);
311 private final AnimationProperties PANEL_ALPHA_OUT_PROPERTIES = new AnimationProperties()
312 .setDuration(150)
313 .setCustomInterpolator(PANEL_ALPHA.getProperty(), Interpolators.ALPHA_OUT);
314 private final AnimationProperties PANEL_ALPHA_IN_PROPERTIES = new AnimationProperties()
315 .setDuration(200)
316 .setAnimationFinishListener(mAnimatorListenerAdapter)
317 .setCustomInterpolator(PANEL_ALPHA.getProperty(), Interpolators.ALPHA_IN);
318
Jason Monk1fd3fc32018-08-14 17:20:09 -0400319 private final StateListener mListener = this::setBarState;
320
Daniel Sandler08d05e32012-08-08 16:39:54 -0400321 public NotificationPanelView(Context context, AttributeSet attrs) {
322 super(context, attrs);
Jorim Jaggi58bef332014-11-21 18:10:32 +0100323 setWillNotDraw(!DEBUG);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700324 mFalsingManager = FalsingManager.getInstance(context);
Selim Cineke64f52a2017-08-24 14:48:38 -0700325 mPowerManager = context.getSystemService(PowerManager.class);
Phil Weaver428e3972018-01-18 12:50:05 -0800326 mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
327 setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
shawnlin4ef7ca52018-05-11 16:44:42 +0800328 mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
329 setPanelAlpha(255, false /* animate */);
Daniel Sandler13522a22012-09-27 14:46:58 -0400330 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700331
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500332 public void setStatusBar(StatusBar bar) {
Daniel Sandler040c2e42012-10-17 00:56:33 -0400333 mStatusBar = bar;
Lucas Dupin987f1932017-05-13 21:02:52 -0700334 mKeyguardBottomArea.setStatusBar(mStatusBar);
Daniel Sandler040c2e42012-10-17 00:56:33 -0400335 }
336
Daniel Sandler13522a22012-09-27 14:46:58 -0400337 @Override
338 protected void onFinishInflate() {
339 super.onFinishInflate();
Alan Viverette51efddb2017-04-05 10:00:01 -0400340 mKeyguardStatusBar = findViewById(R.id.keyguard_header);
341 mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
Jason Monkd075b212016-05-25 12:30:51 -0400342
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800343 mNotificationContainerParent = findViewById(R.id.notification_container_parent);
344 mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
Jason Monkd075b212016-05-25 12:30:51 -0400345 mNotificationStackScroller.setOnHeightChangedListener(this);
346 mNotificationStackScroller.setOverscrollTopChangedListener(this);
347 mNotificationStackScroller.setOnEmptySpaceClickListener(this);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800348 addTrackingHeadsUpListener(mNotificationStackScroller::setTrackingHeadsUp);
Alan Viverette51efddb2017-04-05 10:00:01 -0400349 mKeyguardBottomArea = findViewById(R.id.keyguard_bottom_area);
Jason Monkd075b212016-05-25 12:30:51 -0400350 mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
Jason Monkd075b212016-05-25 12:30:51 -0400351 mLastOrientation = getResources().getConfiguration().orientation;
352
Lucas Dupin987f1932017-05-13 21:02:52 -0700353 initBottomArea();
354
Alan Viverette51efddb2017-04-05 10:00:01 -0400355 mQsFrame = findViewById(R.id.qs_frame);
Jason Monk0ceef212016-11-02 14:05:23 -0400356 }
John Spurlockbceed062014-08-10 18:04:16 -0400357
Jason Monk0ceef212016-11-02 14:05:23 -0400358 @Override
359 protected void onAttachedToWindow() {
360 super.onAttachedToWindow();
361 FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener);
Jason Monk1fd3fc32018-08-14 17:20:09 -0400362 Dependency.get(StatusBarStateController.class).addListener(mListener);
Jason Monk0ceef212016-11-02 14:05:23 -0400363 }
364
365 @Override
366 protected void onDetachedFromWindow() {
367 super.onDetachedFromWindow();
368 FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener);
Jason Monk1fd3fc32018-08-14 17:20:09 -0400369 Dependency.get(StatusBarStateController.class).removeListener(mListener);
Jorim Jaggi069cd032014-05-15 03:09:01 +0200370 }
371
372 @Override
373 protected void loadDimens() {
374 super.loadDimens();
Jorim Jaggi1d480692014-05-20 19:41:58 +0200375 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
Selim Cinek9dbbca82014-05-15 15:23:37 +0200376 mStatusBarMinHeight = getResources().getDimensionPixelSize(
377 com.android.internal.R.dimen.status_bar_height);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200378 mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200379 mNotificationsHeaderCollideDistance =
380 getResources().getDimensionPixelSize(R.dimen.header_notifications_collide_distance);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200381 mUnlockMoveDistance = getResources().getDimensionPixelOffset(R.dimen.unlock_move_distance);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200382 mClockPositionAlgorithm.loadDimens(getResources());
Selim Cinek19c8c702014-08-25 22:09:19 +0200383 mQsFalsingThreshold = getResources().getDimensionPixelSize(
384 R.dimen.qs_falsing_threshold);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700385 mPositionMinSideMargin = getResources().getDimensionPixelSize(
386 R.dimen.notification_panel_min_side_margin);
Selim Cineka981d082016-08-03 14:45:31 -0700387 mMaxFadeoutHeight = getResources().getDimensionPixelSize(
388 R.dimen.max_notification_fadeout_height);
Selim Cinek378053a2016-12-07 15:41:28 -0800389 mIndicationBottomPadding = getResources().getDimensionPixelSize(
390 R.dimen.keyguard_indication_bottom_padding);
Selim Cinekd7768f42017-11-22 06:43:44 -0800391 mQsNotificationTopPadding = getResources().getDimensionPixelSize(
Selim Cinekb95fd182017-12-21 13:03:32 -0800392 R.dimen.qs_notification_padding);
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200393 }
394
John Spurlock7e6809a2014-08-06 16:03:14 -0400395 public void updateResources() {
Anthony Chen04d1ea72017-04-21 14:30:11 -0700396 Resources res = getResources();
397 int qsWidth = res.getDimensionPixelSize(R.dimen.qs_panel_width);
John Spurlock7e6809a2014-08-06 16:03:14 -0400398 int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
Jason Monk845b3b92016-03-10 14:38:13 -0500399 FrameLayout.LayoutParams lp =
Jason Monk0ceef212016-11-02 14:05:23 -0400400 (FrameLayout.LayoutParams) mQsFrame.getLayoutParams();
Anthony Chen04d1ea72017-04-21 14:30:11 -0700401 if (lp.width != qsWidth || lp.gravity != panelGravity) {
402 lp.width = qsWidth;
John Spurlock7e6809a2014-08-06 16:03:14 -0400403 lp.gravity = panelGravity;
Jason Monk0ceef212016-11-02 14:05:23 -0400404 mQsFrame.setLayoutParams(lp);
John Spurlock7e6809a2014-08-06 16:03:14 -0400405 }
406
Anthony Chen04d1ea72017-04-21 14:30:11 -0700407 int panelWidth = res.getDimensionPixelSize(R.dimen.notification_panel_width);
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200408 lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
Selim Cinek9e87cba2017-02-17 13:01:01 -0800409 if (lp.width != panelWidth || lp.gravity != panelGravity) {
John Spurlock7e6809a2014-08-06 16:03:14 -0400410 lp.width = panelWidth;
411 lp.gravity = panelGravity;
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200412 mNotificationStackScroller.setLayoutParams(lp);
413 }
John Spurlock7e6809a2014-08-06 16:03:14 -0400414 }
415
Lucas Dupin8c51ce22017-11-21 13:21:05 -0800416 public void onThemeChanged() {
Lucas Dupin987f1932017-05-13 21:02:52 -0700417 // Re-inflate the status view group.
418 int index = indexOfChild(mKeyguardStatusView);
419 removeView(mKeyguardStatusView);
420 mKeyguardStatusView = (KeyguardStatusView) LayoutInflater.from(mContext).inflate(
421 R.layout.keyguard_status_view,
422 this,
423 false);
424 addView(mKeyguardStatusView, index);
425
426 // Update keyguard bottom area
427 index = indexOfChild(mKeyguardBottomArea);
428 removeView(mKeyguardBottomArea);
429 mKeyguardBottomArea = (KeyguardBottomAreaView) LayoutInflater.from(mContext).inflate(
430 R.layout.keyguard_bottom_area,
431 this,
432 false);
433 addView(mKeyguardBottomArea, index);
434 initBottomArea();
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200435 setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount);
Jason Monkbd9745a2017-07-06 16:03:01 -0400436
Jason Monk1fd3fc32018-08-14 17:20:09 -0400437 setKeyguardStatusViewVisibility(mBarState, false, false);
438 setKeyguardBottomAreaVisibility(mBarState, false);
Lucas Dupin987f1932017-05-13 21:02:52 -0700439 }
440
441 private void initBottomArea() {
442 mAffordanceHelper = new KeyguardAffordanceHelper(this, getContext());
443 mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
444 mKeyguardBottomArea.setStatusBar(mStatusBar);
445 mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
446 }
447
448 public void setKeyguardIndicationController(KeyguardIndicationController indicationController) {
449 mKeyguardBottomArea.setKeyguardIndicationController(indicationController);
450 }
451
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200452 @Override
453 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
454 super.onLayout(changed, left, top, right, bottom);
Selim Cinekfcff4c62016-12-27 14:26:06 +0100455 setIsFullWidth(mNotificationStackScroller.getWidth() == getWidth());
Jorim Jaggid7daab72014-05-06 22:22:20 +0200456
Selim Cinekf99d0002014-06-13 07:36:01 +0200457 // Update Clock Pivot
458 mKeyguardStatusView.setPivotX(getWidth() / 2);
Lucas Dupin987f1932017-05-13 21:02:52 -0700459 mKeyguardStatusView.setPivotY((FONT_HEIGHT - CAP_HEIGHT) / 2048f *
460 mKeyguardStatusView.getClockTextSize());
Selim Cinekf99d0002014-06-13 07:36:01 +0200461
Jorim Jaggid7daab72014-05-06 22:22:20 +0200462 // Calculate quick setting heights.
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100463 int oldMaxHeight = mQsMaxExpansionHeight;
Jason Monk0ceef212016-11-02 14:05:23 -0400464 if (mQs != null) {
465 mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
466 mQsMaxExpansionHeight = mQs.getDesiredHeight();
shawnlin8e4e92c2018-04-12 18:47:24 +0800467 mNotificationStackScroller.setMaxTopPadding(
468 mQsMaxExpansionHeight + mQsNotificationTopPadding);
Jason Monk0ceef212016-11-02 14:05:23 -0400469 }
Selim Cinek237a7012014-09-10 18:12:18 +0200470 positionClockAndNotifications();
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100471 if (mQsExpanded && mQsFullyExpanded) {
472 mQsExpansionHeight = mQsMaxExpansionHeight;
473 requestScrollerTopPaddingUpdate(false /* animate */);
474 requestPanelHeightUpdate();
475
476 // Size has changed, start an animation.
477 if (mQsMaxExpansionHeight != oldMaxHeight) {
478 startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
John Spurlockbc3a5e92014-05-30 16:20:05 -0400479 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100480 } else if (!mQsExpanded) {
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200481 setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200482 }
Selim Cinekbc243a92016-09-27 16:35:13 -0700483 updateExpandedHeight(getExpandedHeight());
Jorim Jaggi0bc49172014-11-03 15:52:13 +0100484 updateHeader();
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100485
486 // If we are running a size change animation, the animation takes care of the height of
487 // the container. However, if we are not animating, we always need to make the QS container
488 // the desired height so when closing the QS detail, it stays smaller after the size change
489 // animation is finished but the detail view is still being animated away (this animation
490 // takes longer than the size change animation).
Jason Monk0ceef212016-11-02 14:05:23 -0400491 if (mQsSizeChangeAnimator == null && mQs != null) {
492 mQs.setHeightOverride(mQs.getDesiredHeight());
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100493 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700494 updateMaxHeadsUpTranslation();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200495 }
496
Selim Cinekfcff4c62016-12-27 14:26:06 +0100497 private void setIsFullWidth(boolean isFullWidth) {
498 mIsFullWidth = isFullWidth;
499 mNotificationStackScroller.setIsFullWidth(isFullWidth);
500 }
501
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100502 private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
503 if (mQsSizeChangeAnimator != null) {
504 oldHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
505 mQsSizeChangeAnimator.cancel();
506 }
507 mQsSizeChangeAnimator = ValueAnimator.ofInt(oldHeight, newHeight);
508 mQsSizeChangeAnimator.setDuration(300);
Selim Cinekc18010f2016-01-20 13:41:30 -0800509 mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100510 mQsSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
511 @Override
512 public void onAnimationUpdate(ValueAnimator animation) {
513 requestScrollerTopPaddingUpdate(false /* animate */);
514 requestPanelHeightUpdate();
515 int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
Jason Monk0ceef212016-11-02 14:05:23 -0400516 mQs.setHeightOverride(height);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100517 }
518 });
519 mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
520 @Override
521 public void onAnimationEnd(Animator animation) {
522 mQsSizeChangeAnimator = null;
523 }
524 });
525 mQsSizeChangeAnimator.start();
526 }
527
Jorim Jaggi069cd032014-05-15 03:09:01 +0200528 /**
529 * Positions the clock and notifications dynamically depending on how many notifications are
530 * showing.
531 */
532 private void positionClockAndNotifications() {
Selim Cinekf99d0002014-06-13 07:36:01 +0200533 boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
Lucas Dupin60661a62018-04-12 10:50:13 -0700534 boolean animateClock = animate || mAnimateNextPositionUpdate;
Selim Cinek1408eb52014-06-02 14:45:38 +0200535 int stackScrollerPadding;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400536 if (mBarState != StatusBarState.KEYGUARD) {
Selim Cinekb95fd182017-12-21 13:03:32 -0800537 stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
538 + mQsNotificationTopPadding;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200539 } else {
Lucas Dupin60661a62018-04-12 10:50:13 -0700540 int totalHeight = getHeight();
541 int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200542 mClockPositionAlgorithm.setup(
Lucas Dupin41ff6952018-02-18 19:39:32 -0800543 mStatusBarMinHeight,
544 totalHeight - bottomPadding,
Lucas Dupin60661a62018-04-12 10:50:13 -0700545 mNotificationStackScroller.getIntrinsicContentHeight(),
546 getExpandedFraction(),
Lucas Dupin41ff6952018-02-18 19:39:32 -0800547 totalHeight,
Jorim Jaggi48bc36a2014-07-25 23:16:04 +0200548 mKeyguardStatusView.getHeight(),
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200549 mInterpolatedDarkAmount,
Selim Cinekdbf172e2018-08-08 18:31:45 +0000550 mStatusBar.isKeyguardCurrentlySecure(),
Lucas Dupin56057342018-04-10 11:49:18 -0700551 mPulsing,
Lucas Dupin4c2aa392018-03-28 18:00:45 -0700552 mBouncerTop);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200553 mClockPositionAlgorithm.run(mClockPositionResult);
Lucas Dupin60661a62018-04-12 10:50:13 -0700554 PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X,
555 mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
556 PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
557 mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800558 updateClock();
Selim Cinek1408eb52014-06-02 14:45:38 +0200559 stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200560 }
Selim Cinek1408eb52014-06-02 14:45:38 +0200561 mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
Lucas Dupin0cd882f2018-01-30 12:19:49 -0800562 mNotificationStackScroller.setAntiBurnInOffsetX(mClockPositionResult.clockX);
Lucas Dupin4272f442018-01-13 22:00:35 -0800563 mKeyguardBottomArea.setBurnInXOffset(mClockPositionResult.clockX);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800564
565 mStackScrollerMeasuringPass++;
Selim Cinekf99d0002014-06-13 07:36:01 +0200566 requestScrollerTopPaddingUpdate(animate);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800567 mStackScrollerMeasuringPass = 0;
Lucas Dupin60661a62018-04-12 10:50:13 -0700568 mAnimateNextPositionUpdate = false;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200569 }
570
Selim Cinek5f71bee2015-11-18 10:25:23 -0800571 /**
572 * @param maximum the maximum to return at most
573 * @return the maximum keyguard notifications that can fit on the screen
574 */
575 public int computeMaxKeyguardNotifications(int maximum) {
Lucas Dupin41ff6952018-02-18 19:39:32 -0800576 float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
Selim Cinekcacc6042016-01-21 16:16:41 -0800577 int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
578 R.dimen.notification_divider_height));
Anthony Chen9e05d462017-04-07 10:10:21 -0700579 NotificationShelf shelf = mNotificationStackScroller.getNotificationShelf();
580 float shelfSize = shelf.getVisibility() == GONE ? 0
581 : shelf.getIntrinsicHeight() + notificationPadding;
Selim Cinek378053a2016-12-07 15:41:28 -0800582 float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize
Alex Chauff7653d2018-02-01 17:18:08 +0000583 - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
584 - mKeyguardStatusView.getLogoutButtonHeight();
Selim Cinek5f71bee2015-11-18 10:25:23 -0800585 int count = 0;
586 for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
587 ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
588 if (!(child instanceof ExpandableNotificationRow)) {
589 continue;
590 }
Selim Cinekfa760d42016-05-10 15:50:53 -0400591 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek53f8e7d2016-03-25 02:28:01 -0700592 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
Selim Cinekfa760d42016-05-10 15:50:53 -0400593 row.getStatusBarNotification());
Selim Cinek53f8e7d2016-03-25 02:28:01 -0700594 if (suppressedSummary) {
595 continue;
596 }
Eliot Courtney09322282017-11-09 15:31:19 +0900597 if (!mStatusBar.getNotificationLockscreenUserManager().shouldShowOnKeyguard(
598 row.getStatusBarNotification())) {
Selim Cinekfa760d42016-05-10 15:50:53 -0400599 continue;
600 }
601 if (row.isRemoved()) {
602 continue;
603 }
Selim Cinekeb3fc3d2017-09-15 13:37:14 -0700604 availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */)
605 + notificationPadding;
Selim Cinek5f71bee2015-11-18 10:25:23 -0800606 if (availableSpace >= 0 && count < maximum) {
607 count++;
Selim Cinek281c2022016-10-13 19:14:43 -0700608 } else if (availableSpace > -shelfSize) {
609 // if we are exactly the last view, then we can show us still!
610 for (int j = i + 1; j < mNotificationStackScroller.getChildCount(); j++) {
611 if (mNotificationStackScroller.getChildAt(j)
612 instanceof ExpandableNotificationRow) {
613 return count;
614 }
615 }
616 count++;
617 return count;
Selim Cinek5f71bee2015-11-18 10:25:23 -0800618 } else {
619 return count;
620 }
621 }
622 return count;
623 }
624
Lucas Dupin4c2aa392018-03-28 18:00:45 -0700625 public void setBouncerTop(int bouncerTop) {
626 mBouncerTop = bouncerTop;
627 positionClockAndNotifications();
628 }
629
Lucas Dupin41ff6952018-02-18 19:39:32 -0800630 private void updateClock() {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200631 if (!mKeyguardStatusViewAnimating) {
Lucas Dupin78db0902018-02-24 19:42:06 -0800632 mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200633 }
Jorim Jaggi069cd032014-05-15 03:09:01 +0200634 }
635
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200636 public void animateToFullShade(long delay) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200637 mNotificationStackScroller.goToFullShade(delay);
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200638 requestLayout();
Lucas Dupin60661a62018-04-12 10:50:13 -0700639 mAnimateNextPositionUpdate = true;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400640 }
641
Jorim Jaggid7daab72014-05-06 22:22:20 +0200642 public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
643 mQsExpansionEnabled = qsExpansionEnabled;
Jason Monk0ceef212016-11-02 14:05:23 -0400644 if (mQs == null) return;
645 mQs.setHeaderClickable(qsExpansionEnabled);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200646 }
647
Selim Cinek3c4635c2014-05-29 02:12:47 +0200648 @Override
Lucas Dupinee63c372018-08-03 11:58:24 -0700649 public void resetViews(boolean animate) {
Selim Cinekbaa23272014-07-08 18:01:07 +0200650 mIsLaunchTransitionFinished = false;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200651 mBlockTouches = false;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200652 mUnlockIconActive = false;
Selim Cinek372d1bd2015-08-14 13:19:37 -0700653 if (!mLaunchingAffordance) {
Adrian Roose31f30e2017-01-25 14:48:15 -0800654 mAffordanceHelper.reset(false);
Jorim Jaggi40aa8812015-09-23 12:59:22 -0700655 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
Selim Cinek372d1bd2015-08-14 13:19:37 -0700656 }
Eliot Courtney47098cb2017-10-18 17:30:30 +0900657 mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
Mady Mellorc2dbe492017-03-30 13:22:03 -0700658 true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
Lucas Dupinee63c372018-08-03 11:58:24 -0700659 if (animate) {
660 animateCloseQs(true /* animateAway */);
661 } else {
662 closeQs();
663 }
664 mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, animate,
665 !animate /* cancelAnimators */);
Selim Cinekb24e0a92015-06-09 20:17:30 -0700666 mNotificationStackScroller.resetScrollPosition();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200667 }
668
shawnlin8e4e92c2018-04-12 18:47:24 +0800669 @Override
670 public void collapse(boolean delayed, float speedUpFactor) {
671 if (!canPanelBeCollapsed()) {
672 return;
673 }
674
675 if (mQsExpanded) {
676 mQsExpandImmediate = true;
677 mNotificationStackScroller.setShouldShowShelfOnly(true);
678 }
679 super.collapse(delayed, speedUpFactor);
680 }
681
Jorim Jaggid7daab72014-05-06 22:22:20 +0200682 public void closeQs() {
Selim Cinek831941f2015-06-17 15:09:30 -0700683 cancelQsAnimation();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200684 setQsExpansion(mQsMinExpansionHeight);
685 }
686
Lucas Dupinee63c372018-08-03 11:58:24 -0700687 /**
688 * Animate QS closing by flinging it.
689 * If QS is expanded, it will collapse into QQS and stop.
690 *
691 * @param animateAway Do not stop when QS becomes QQS. Fling until QS isn't visible anymore.
692 */
693 public void animateCloseQs(boolean animateAway) {
Jorim Jaggibd003102014-07-04 00:02:42 +0200694 if (mQsExpansionAnimator != null) {
695 if (!mQsAnimatorExpand) {
696 return;
697 }
698 float height = mQsExpansionHeight;
699 mQsExpansionAnimator.cancel();
700 setQsExpansion(height);
701 }
Lucas Dupinee63c372018-08-03 11:58:24 -0700702 flingSettings(0 /* vel */, animateAway ? FLING_HIDE : FLING_COLLAPSE);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200703 }
704
Jason Monk3c68ca22015-01-30 11:30:29 -0500705 public void expandWithQs() {
706 if (mQsExpansionEnabled) {
707 mQsExpandImmediate = true;
shawnlin8e4e92c2018-04-12 18:47:24 +0800708 mNotificationStackScroller.setShouldShowShelfOnly(true);
Jason Monk3c68ca22015-01-30 11:30:29 -0500709 }
Oren Blasberg8d3fea12015-07-10 14:21:44 -0700710 expand(true /* animate */);
Jason Monk3c68ca22015-01-30 11:30:29 -0500711 }
712
Eugene Susla2de69552018-03-20 13:22:17 -0700713 public void expandWithoutQs() {
714 if (isQsExpanded()) {
Lucas Dupinee63c372018-08-03 11:58:24 -0700715 flingSettings(0 /* velocity */, FLING_COLLAPSE);
Eugene Susla2de69552018-03-20 13:22:17 -0700716 } else {
717 expand(true /* animate */);
718 }
719 }
720
Daniel Sandler08d05e32012-08-08 16:39:54 -0400721 @Override
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200722 public void fling(float vel, boolean expand) {
Daniel Sandler151f00d2012-10-02 22:33:08 -0400723 GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
724 if (gr != null) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200725 gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
Daniel Sandler151f00d2012-10-02 22:33:08 -0400726 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200727 super.fling(vel, expand);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400728 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700729
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -0700730 @Override
Jorim Jaggif3b3bee2015-04-16 14:57:34 -0700731 protected void flingToHeight(float vel, boolean expand, float target,
Selim Cinek9db71052015-04-24 18:54:30 -0700732 float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700733 mHeadsUpTouchHelper.notifyFling(!expand);
Selim Cinek48ff9b42016-11-09 19:31:51 -0800734 setClosingWithAlphaFadeout(!expand && getFadeoutAlpha() == 1.0f);
Selim Cinek9db71052015-04-24 18:54:30 -0700735 super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700736 }
737
738 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700739 public boolean onInterceptTouchEvent(MotionEvent event) {
Jason Monk231b0522018-01-04 10:49:55 -0500740 if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200741 return false;
742 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +0100743 initDownStates(event);
Charles He2eda2422017-09-24 17:55:21 +0100744 if (mBar.panelEnabled() && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
Selim Cinek684a4422015-04-15 16:18:39 -0700745 mIsExpansionFromHeadsUp = true;
Chris Wren49f06f52015-05-01 16:12:12 -0400746 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
747 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700748 return true;
749 }
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800750
Anthony Chen54daefe2017-04-07 17:19:54 -0700751 if (!isFullyCollapsed() && onQsIntercept(event)) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700752 return true;
753 }
754 return super.onInterceptTouchEvent(event);
755 }
756
757 private boolean onQsIntercept(MotionEvent event) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200758 int pointerIndex = event.findPointerIndex(mTrackingPointer);
759 if (pointerIndex < 0) {
760 pointerIndex = 0;
761 mTrackingPointer = event.getPointerId(pointerIndex);
John Spurlock73203eb2014-04-15 16:14:46 -0400762 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200763 final float x = event.getX(pointerIndex);
764 final float y = event.getY(pointerIndex);
765
766 switch (event.getActionMasked()) {
767 case MotionEvent.ACTION_DOWN:
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200768 mIntercepting = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200769 mInitialTouchY = y;
770 mInitialTouchX = x;
771 initVelocityTracker();
772 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200773 if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200774 getParent().requestDisallowInterceptTouchEvent(true);
775 }
Jorim Jaggi54045422014-07-03 18:30:40 +0200776 if (mQsExpansionAnimator != null) {
777 onQsExpansionStarted();
778 mInitialHeightOnTouch = mQsExpansionHeight;
779 mQsTracking = true;
780 mIntercepting = false;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000781 mNotificationStackScroller.cancelLongPress();
Jorim Jaggi54045422014-07-03 18:30:40 +0200782 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200783 break;
784 case MotionEvent.ACTION_POINTER_UP:
785 final int upPointer = event.getPointerId(event.getActionIndex());
786 if (mTrackingPointer == upPointer) {
787 // gesture is ongoing, find a new pointer to track
788 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
789 mTrackingPointer = event.getPointerId(newIndex);
790 mInitialTouchX = event.getX(newIndex);
791 mInitialTouchY = event.getY(newIndex);
792 }
793 break;
794
795 case MotionEvent.ACTION_MOVE:
796 final float h = y - mInitialTouchY;
797 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200798 if (mQsTracking) {
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200799
800 // Already tracking because onOverscrolled was called. We need to update here
801 // so we don't stop for a frame until the next touch event gets handled in
802 // onTouchEvent.
803 setQsExpansion(h + mInitialHeightOnTouch);
804 trackMovement(event);
805 mIntercepting = false;
806 return true;
807 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200808 if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
Selim Cinek4c6969a2014-05-26 19:22:17 +0200809 && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
Jorim Jaggi58bef332014-11-21 18:10:32 +0100810 mQsTracking = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200811 onQsExpansionStarted();
Jorim Jaggi26aa04c2015-07-29 14:52:22 -0700812 notifyExpandingFinished();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200813 mInitialHeightOnTouch = mQsExpansionHeight;
814 mInitialTouchY = y;
815 mInitialTouchX = x;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200816 mIntercepting = false;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000817 mNotificationStackScroller.cancelLongPress();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200818 return true;
819 }
820 break;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200821
822 case MotionEvent.ACTION_CANCEL:
823 case MotionEvent.ACTION_UP:
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200824 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200825 if (mQsTracking) {
Chris Wren49f06f52015-05-01 16:12:12 -0400826 flingQsWithCurrentVelocity(y,
Jorim Jaggiaea80f42014-11-10 22:41:54 +0100827 event.getActionMasked() == MotionEvent.ACTION_CANCEL);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200828 mQsTracking = false;
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200829 }
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200830 mIntercepting = false;
831 break;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200832 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700833 return false;
John Spurlock73203eb2014-04-15 16:14:46 -0400834 }
835
Selim Cinekab1dc952014-10-30 20:20:29 +0100836 @Override
837 protected boolean isInContentBounds(float x, float y) {
Selim Cinekab1dc952014-10-30 20:20:29 +0100838 float stackScrollerX = mNotificationStackScroller.getX();
Selim Cinek04fb2582015-06-02 19:58:09 +0200839 return !mNotificationStackScroller.isBelowLastNotification(x - stackScrollerX, y)
840 && stackScrollerX < x && x < stackScrollerX + mNotificationStackScroller.getWidth();
Selim Cinekab1dc952014-10-30 20:20:29 +0100841 }
842
Jorim Jaggi1cf6e102015-01-20 16:45:05 +0100843 private void initDownStates(MotionEvent event) {
Selim Cinekbaa23272014-07-08 18:01:07 +0200844 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
845 mOnlyAffordanceInThisMotion = false;
Selim Cinek19c8c702014-08-25 22:09:19 +0200846 mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +0100847 mDozingOnDown = isDozing();
Selim Cinek684a4422015-04-15 16:18:39 -0700848 mCollapsedOnDown = isFullyCollapsed();
Selim Cinek79d79c42015-05-21 16:14:45 -0700849 mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
Selim Cinekbaa23272014-07-08 18:01:07 +0200850 }
851 }
852
Chris Wren49f06f52015-05-01 16:12:12 -0400853 private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
Selim Cinekd5ab6452016-12-08 16:34:00 -0800854 float vel = getCurrentQSVelocity();
Chris Wren49f06f52015-05-01 16:12:12 -0400855 final boolean expandsQs = flingExpandsQs(vel);
856 if (expandsQs) {
857 logQsSwipeDown(y);
858 }
Lucas Dupinee63c372018-08-03 11:58:24 -0700859 flingSettings(vel, expandsQs && !isCancelMotionEvent ? FLING_EXPAND : FLING_COLLAPSE);
Chris Wren49f06f52015-05-01 16:12:12 -0400860 }
861
862 private void logQsSwipeDown(float y) {
Selim Cinekd5ab6452016-12-08 16:34:00 -0800863 float vel = getCurrentQSVelocity();
Jason Monk1fd3fc32018-08-14 17:20:09 -0400864 final int gesture = mBarState == StatusBarState.KEYGUARD
Chris Wren27a52fa2017-02-01 14:21:43 -0500865 ? MetricsEvent.ACTION_LS_QS
866 : MetricsEvent.ACTION_SHADE_QS_PULL;
867 mLockscreenGestureLogger.write(gesture,
Chris Wren49f06f52015-05-01 16:12:12 -0400868 (int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
869 (int) (vel / mStatusBar.getDisplayDensity()));
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200870 }
871
Jorim Jaggidc96d632014-07-01 18:48:52 +0200872 private boolean flingExpandsQs(float vel) {
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700873 if (isFalseTouch()) {
Selim Cinek19c8c702014-08-25 22:09:19 +0200874 return false;
875 }
Jorim Jaggidc96d632014-07-01 18:48:52 +0200876 if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
877 return getQsExpansionFraction() > 0.5f;
878 } else {
879 return vel > 0;
880 }
881 }
882
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700883 private boolean isFalseTouch() {
Adrian Roos6a70b882016-04-19 17:09:07 -0700884 if (!needsAntiFalsing()) {
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700885 return false;
886 }
887 if (mFalsingManager.isClassiferEnabled()) {
888 return mFalsingManager.isFalseTouch();
889 }
890 return !mQsTouchAboveFalsingThreshold;
Selim Cinek5386fb32014-09-03 16:37:36 +0200891 }
892
Jorim Jaggidc96d632014-07-01 18:48:52 +0200893 private float getQsExpansionFraction() {
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200894 return Math.min(1f, (mQsExpansionHeight - mQsMinExpansionHeight)
Selim Cinekd7768f42017-11-22 06:43:44 -0800895 / (mQsMaxExpansionHeight - mQsMinExpansionHeight));
Jorim Jaggidc96d632014-07-01 18:48:52 +0200896 }
Jorim Jaggi54045422014-07-03 18:30:40 +0200897
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200898 @Override
Selim Cinek48ff9b42016-11-09 19:31:51 -0800899 protected float getOpeningHeight() {
Selim Cinekfcff4c62016-12-27 14:26:06 +0100900 return mNotificationStackScroller.getOpeningHeight();
Selim Cinek48ff9b42016-11-09 19:31:51 -0800901 }
902
903 @Override
Daniel Sandler040c2e42012-10-17 00:56:33 -0400904 public boolean onTouchEvent(MotionEvent event) {
Jason Monk0ceef212016-11-02 14:05:23 -0400905 if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200906 return false;
907 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +0100908 initDownStates(event);
Selim Cinek79d79c42015-05-21 16:14:45 -0700909 if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
910 && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
911 mIsExpansionFromHeadsUp = true;
Selim Cinek79d79c42015-05-21 16:14:45 -0700912 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
913 }
Adrian Roos8008bd12017-02-22 15:02:09 +0100914 boolean handled = false;
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200915 if ((!mIsExpanding || mHintAnimationRunning)
916 && !mQsExpanded
Jason Monk1fd3fc32018-08-14 17:20:09 -0400917 && mBarState != StatusBarState.SHADE
Adrian Roos2a318412017-01-25 14:48:26 -0800918 && !mDozing) {
Adrian Roos8008bd12017-02-22 15:02:09 +0100919 handled |= mAffordanceHelper.onTouchEvent(event);
Selim Cinekbaa23272014-07-08 18:01:07 +0200920 }
921 if (mOnlyAffordanceInThisMotion) {
922 return true;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200923 }
Adrian Roos8008bd12017-02-22 15:02:09 +0100924 handled |= mHeadsUpTouchHelper.onTouchEvent(event);
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800925
Anthony Chen54daefe2017-04-07 17:19:54 -0700926 if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700927 return true;
928 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700929 if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
Chris Wren49f06f52015-05-01 16:12:12 -0400930 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700931 updateVerticalPanelPosition(event.getX());
Adrian Roos8008bd12017-02-22 15:02:09 +0100932 handled = true;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700933 }
Adrian Roos8008bd12017-02-22 15:02:09 +0100934 handled |= super.onTouchEvent(event);
935 return mDozing ? handled : true;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700936 }
937
Selim Cinek684a4422015-04-15 16:18:39 -0700938 private boolean handleQsTouch(MotionEvent event) {
Mady Melloraaf32f62015-05-01 17:06:50 -0700939 final int action = event.getActionMasked();
940 if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
Jason Monk1fd3fc32018-08-14 17:20:09 -0400941 && mBarState != StatusBarState.KEYGUARD && !mQsExpanded
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200942 && mQsExpansionEnabled) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200943
Jorim Jaggidc96d632014-07-01 18:48:52 +0200944 // Down in the empty area while fully expanded - go to QS.
945 mQsTracking = true;
946 mConflictingQsExpansionGesture = true;
947 onQsExpansionStarted();
948 mInitialHeightOnTouch = mQsExpansionHeight;
949 mInitialTouchY = event.getX();
950 mInitialTouchX = event.getY();
951 }
Selim Cinek684a4422015-04-15 16:18:39 -0700952 if (!isFullyCollapsed()) {
Jorim Jaggi853b0702014-07-05 04:31:14 +0200953 handleQsDown(event);
954 }
Jason Monk3c68ca22015-01-30 11:30:29 -0500955 if (!mQsExpandImmediate && mQsTracking) {
Jorim Jaggidc96d632014-07-01 18:48:52 +0200956 onQsTouch(event);
957 if (!mConflictingQsExpansionGesture) {
958 return true;
959 }
960 }
Mady Melloraaf32f62015-05-01 17:06:50 -0700961 if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
Jorim Jaggidc96d632014-07-01 18:48:52 +0200962 mConflictingQsExpansionGesture = false;
963 }
Mady Melloraaf32f62015-05-01 17:06:50 -0700964 if (action == MotionEvent.ACTION_DOWN && isFullyCollapsed()
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200965 && mQsExpansionEnabled) {
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200966 mTwoFingerQsExpandPossible = true;
967 }
Mady Mellor3a4bc792015-05-27 09:10:22 -0700968 if (mTwoFingerQsExpandPossible && isOpenQsEvent(event)
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200969 && event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
Chris Wren49f06f52015-05-01 16:12:12 -0400970 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1);
Jason Monk3c68ca22015-01-30 11:30:29 -0500971 mQsExpandImmediate = true;
shawnlin8e4e92c2018-04-12 18:47:24 +0800972 mNotificationStackScroller.setShouldShowShelfOnly(true);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200973 requestPanelHeightUpdate();
Jorim Jaggi8599a332014-08-14 21:44:23 +0200974
975 // Normally, we start listening when the panel is expanded, but here we need to start
976 // earlier so the state is already up to date when dragging down.
977 setListening(true);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200978 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700979 return false;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200980 }
981
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200982 private boolean isInQsArea(float x, float y) {
Jason Monk0ceef212016-11-02 14:05:23 -0400983 return (x >= mQsFrame.getX()
984 && x <= mQsFrame.getX() + mQsFrame.getWidth())
Jason Monk85686d62016-03-29 12:34:28 -0400985 && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
Jason Monk0ceef212016-11-02 14:05:23 -0400986 || y <= mQs.getView().getY() + mQs.getView().getHeight());
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200987 }
988
Mady Mellor3a4bc792015-05-27 09:10:22 -0700989 private boolean isOpenQsEvent(MotionEvent event) {
990 final int pointerCount = event.getPointerCount();
991 final int action = event.getActionMasked();
992
993 final boolean twoFingerDrag = action == MotionEvent.ACTION_POINTER_DOWN
994 && pointerCount == 2;
995
996 final boolean stylusButtonClickDrag = action == MotionEvent.ACTION_DOWN
997 && (event.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)
998 || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
999
1000 final boolean mouseButtonClickDrag = action == MotionEvent.ACTION_DOWN
1001 && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
1002 || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
1003
1004 return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag;
1005 }
1006
Jorim Jaggi853b0702014-07-05 04:31:14 +02001007 private void handleQsDown(MotionEvent event) {
1008 if (event.getActionMasked() == MotionEvent.ACTION_DOWN
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001009 && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001010 mFalsingManager.onQsDown();
Jorim Jaggi853b0702014-07-05 04:31:14 +02001011 mQsTracking = true;
1012 onQsExpansionStarted();
1013 mInitialHeightOnTouch = mQsExpansionHeight;
1014 mInitialTouchY = event.getX();
1015 mInitialTouchX = event.getY();
Jorim Jaggi8599a332014-08-14 21:44:23 +02001016
1017 // If we interrupt an expansion gesture here, make sure to update the state correctly.
Jorim Jaggi26aa04c2015-07-29 14:52:22 -07001018 notifyExpandingFinished();
Jorim Jaggi853b0702014-07-05 04:31:14 +02001019 }
1020 }
1021
Selim Cinek4c6969a2014-05-26 19:22:17 +02001022 @Override
Selim Cinek9db71052015-04-24 18:54:30 -07001023 protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
1024 boolean expands = super.flingExpands(vel, vectorVel, x, y);
Jorim Jaggidc96d632014-07-01 18:48:52 +02001025
1026 // If we are already running a QS expansion, make sure that we keep the panel open.
1027 if (mQsExpansionAnimator != null) {
1028 expands = true;
1029 }
1030 return expands;
1031 }
1032
1033 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +02001034 protected boolean hasConflictingGestures() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04001035 return mBarState != StatusBarState.SHADE;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001036 }
1037
Selim Cinek9db71052015-04-24 18:54:30 -07001038 @Override
1039 protected boolean shouldGestureIgnoreXTouchSlop(float x, float y) {
Adrian Roose31f30e2017-01-25 14:48:15 -08001040 return !mAffordanceHelper.isOnAffordanceIcon(x, y);
Selim Cinek9db71052015-04-24 18:54:30 -07001041 }
1042
Jorim Jaggidc96d632014-07-01 18:48:52 +02001043 private void onQsTouch(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +02001044 int pointerIndex = event.findPointerIndex(mTrackingPointer);
1045 if (pointerIndex < 0) {
1046 pointerIndex = 0;
1047 mTrackingPointer = event.getPointerId(pointerIndex);
1048 }
1049 final float y = event.getY(pointerIndex);
1050 final float x = event.getX(pointerIndex);
Chris Wren49f06f52015-05-01 16:12:12 -04001051 final float h = y - mInitialTouchY;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001052
1053 switch (event.getActionMasked()) {
1054 case MotionEvent.ACTION_DOWN:
1055 mQsTracking = true;
1056 mInitialTouchY = y;
1057 mInitialTouchX = x;
1058 onQsExpansionStarted();
1059 mInitialHeightOnTouch = mQsExpansionHeight;
1060 initVelocityTracker();
1061 trackMovement(event);
1062 break;
1063
1064 case MotionEvent.ACTION_POINTER_UP:
1065 final int upPointer = event.getPointerId(event.getActionIndex());
1066 if (mTrackingPointer == upPointer) {
1067 // gesture is ongoing, find a new pointer to track
1068 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
1069 final float newY = event.getY(newIndex);
1070 final float newX = event.getX(newIndex);
1071 mTrackingPointer = event.getPointerId(newIndex);
1072 mInitialHeightOnTouch = mQsExpansionHeight;
1073 mInitialTouchY = newY;
1074 mInitialTouchX = newX;
1075 }
1076 break;
1077
1078 case MotionEvent.ACTION_MOVE:
Selim Cinek4c6969a2014-05-26 19:22:17 +02001079 setQsExpansion(h + mInitialHeightOnTouch);
Selim Cinek34cf5c42014-09-26 15:39:00 +02001080 if (h >= getFalsingThreshold()) {
Selim Cinek19c8c702014-08-25 22:09:19 +02001081 mQsTouchAboveFalsingThreshold = true;
1082 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02001083 trackMovement(event);
1084 break;
1085
1086 case MotionEvent.ACTION_UP:
1087 case MotionEvent.ACTION_CANCEL:
1088 mQsTracking = false;
1089 mTrackingPointer = -1;
1090 trackMovement(event);
Selim Cinek84e6de72016-02-22 20:57:43 -08001091 float fraction = getQsExpansionFraction();
1092 if (fraction != 0f || y >= mInitialTouchY) {
1093 flingQsWithCurrentVelocity(y,
1094 event.getActionMasked() == MotionEvent.ACTION_CANCEL);
1095 }
Selim Cinekd5ab6452016-12-08 16:34:00 -08001096 if (mQsVelocityTracker != null) {
1097 mQsVelocityTracker.recycle();
1098 mQsVelocityTracker = null;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001099 }
1100 break;
1101 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001102 }
1103
Selim Cinek34cf5c42014-09-26 15:39:00 +02001104 private int getFalsingThreshold() {
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07001105 float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
Selim Cinek34cf5c42014-09-26 15:39:00 +02001106 return (int) (mQsFalsingThreshold * factor);
1107 }
1108
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001109 @Override
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001110 public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
Selim Cinek831941f2015-06-17 15:09:30 -07001111 cancelQsAnimation();
Jorim Jaggi18bd04f2014-08-15 00:03:09 +02001112 if (!mQsExpansionEnabled) {
1113 amount = 0f;
1114 }
Jorim Jaggi290600a2014-05-30 17:02:20 +02001115 float rounded = amount >= 1f ? amount : 0f;
Jason Monke1be3422016-02-09 10:51:40 -05001116 setOverScrolling(rounded != 0f && isRubberbanded);
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001117 mQsExpansionFromOverscroll = rounded != 0f;
Jorim Jaggi11c071a2014-08-14 19:17:11 +02001118 mLastOverscroll = rounded;
Jorim Jaggi290600a2014-05-30 17:02:20 +02001119 updateQsState();
Jorim Jaggi90e0df22014-07-30 01:10:35 +02001120 setQsExpansion(mQsMinExpansionHeight + rounded);
Jorim Jaggi290600a2014-05-30 17:02:20 +02001121 }
1122
Selim Cinek1408eb52014-06-02 14:45:38 +02001123 @Override
1124 public void flingTopOverscroll(float velocity, boolean open) {
Jorim Jaggib7a33032014-08-20 16:21:36 +02001125 mLastOverscroll = 0f;
Selim Cinekf91de682016-05-11 13:01:02 -04001126 mQsExpansionFromOverscroll = false;
Selim Cinek1408eb52014-06-02 14:45:38 +02001127 setQsExpansion(mQsExpansionHeight);
Lucas Dupinee63c372018-08-03 11:58:24 -07001128 flingSettings(!mQsExpansionEnabled && open ? 0f : velocity,
1129 open && mQsExpansionEnabled ? FLING_EXPAND : FLING_COLLAPSE,
Jorim Jaggi18bd04f2014-08-15 00:03:09 +02001130 new Runnable() {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001131 @Override
1132 public void run() {
1133 mStackScrollerOverscrolling = false;
Jason Monke1be3422016-02-09 10:51:40 -05001134 setOverScrolling(false);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001135 updateQsState();
1136 }
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07001137 }, false /* isClick */);
Selim Cinek1408eb52014-06-02 14:45:38 +02001138 }
1139
Jason Monke1be3422016-02-09 10:51:40 -05001140 private void setOverScrolling(boolean overscrolling) {
1141 mStackScrollerOverscrolling = overscrolling;
Jason Monk0ceef212016-11-02 14:05:23 -04001142 if (mQs == null) return;
1143 mQs.setOverscrolling(overscrolling);
Jason Monke1be3422016-02-09 10:51:40 -05001144 }
1145
Jorim Jaggid7daab72014-05-06 22:22:20 +02001146 private void onQsExpansionStarted() {
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001147 onQsExpansionStarted(0);
1148 }
1149
Muyuan Li0e9f5382016-04-27 15:51:15 -07001150 protected void onQsExpansionStarted(int overscrollAmount) {
Selim Cinek831941f2015-06-17 15:09:30 -07001151 cancelQsAnimation();
1152 cancelHeightAnimator();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001153
1154 // Reset scroll position and apply that position to the expanded height.
Jason Monk16ac3772016-02-10 15:39:21 -05001155 float height = mQsExpansionHeight - overscrollAmount;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001156 setQsExpansion(height);
Jorim Jaggi58bef332014-11-21 18:10:32 +01001157 requestPanelHeightUpdate();
Mady Mellorc2dbe492017-03-30 13:22:03 -07001158 mNotificationStackScroller.checkSnoozeLeavebehind();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001159 }
1160
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001161 private void setQsExpanded(boolean expanded) {
1162 boolean changed = mQsExpanded != expanded;
1163 if (changed) {
1164 mQsExpanded = expanded;
1165 updateQsState();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001166 requestPanelHeightUpdate();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001167 mFalsingManager.setQsExpanded(expanded);
Jorim Jaggib690f0d2014-07-03 23:25:44 +02001168 mStatusBar.setQsExpanded(expanded);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001169 mNotificationContainerParent.setQsExpanded(expanded);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001170 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001171 }
1172
Jason Monk1fd3fc32018-08-14 17:20:09 -04001173 private void setBarState(int statusBarState) {
1174 boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
1175 boolean keyguardFadingAway = mKeyguardMonitor.isKeyguardFadingAway();
1176 int oldState = mBarState;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001177 boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001178 setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
1179 setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001180
Jason Monk1fd3fc32018-08-14 17:20:09 -04001181 mBarState = statusBarState;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001182 mKeyguardShowing = keyguardShowing;
Jason Monk0ceef212016-11-02 14:05:23 -04001183 if (mQs != null) {
1184 mQs.setKeyguardShowing(mKeyguardShowing);
1185 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001186
Selim Cinek5f2ca6b2016-10-07 14:45:55 -04001187 if (oldState == StatusBarState.KEYGUARD
1188 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001189 animateKeyguardStatusBarOut();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001190 long delay = mBarState == StatusBarState.SHADE_LOCKED
1191 ? 0 : mKeyguardMonitor.calculateGoingToFullShadeDelay();
Jason Monk0ceef212016-11-02 14:05:23 -04001192 mQs.animateHeaderSlidingIn(delay);
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001193 } else if (oldState == StatusBarState.SHADE_LOCKED
1194 && statusBarState == StatusBarState.KEYGUARD) {
1195 animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Jason Monk0ceef212016-11-02 14:05:23 -04001196 mQs.animateHeaderSlidingOut();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001197 } else {
1198 mKeyguardStatusBar.setAlpha(1f);
1199 mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
Jason Monk1fd3fc32018-08-14 17:20:09 -04001200 if (keyguardShowing && oldState != mBarState) {
Selim Cinek5f145022016-08-02 16:00:12 -07001201 mKeyguardBottomArea.onKeyguardShowingChanged();
Jason Monk0ceef212016-11-02 14:05:23 -04001202 if (mQs != null) {
1203 mQs.hideImmediately();
1204 }
Selim Cineke70d6532015-04-24 16:46:13 -07001205 }
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001206 }
Jorim Jaggi0e0942d2015-06-05 14:12:20 -07001207 if (keyguardShowing) {
1208 updateDozingVisibilities(false /* animate */);
1209 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07001210 resetVerticalPanelPosition();
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001211 updateQsState();
1212 }
1213
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001214 private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() {
1215 @Override
1216 public void run() {
1217 mKeyguardStatusViewAnimating = false;
Lucas Dupin93752552018-03-19 21:32:19 -07001218 mKeyguardStatusView.setVisibility(View.INVISIBLE);
1219 }
1220 };
1221
1222 private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = new Runnable() {
1223 @Override
1224 public void run() {
1225 mKeyguardStatusViewAnimating = false;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001226 mKeyguardStatusView.setVisibility(View.GONE);
1227 }
1228 };
1229
1230 private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = new Runnable() {
1231 @Override
1232 public void run() {
1233 mKeyguardStatusViewAnimating = false;
1234 }
1235 };
1236
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001237 private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
1238 @Override
1239 public void run() {
1240 mKeyguardStatusBar.setVisibility(View.INVISIBLE);
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001241 mKeyguardStatusBar.setAlpha(1f);
1242 mKeyguardStatusBarAnimateAlpha = 1f;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001243 }
1244 };
1245
1246 private void animateKeyguardStatusBarOut() {
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001247 ValueAnimator anim = ValueAnimator.ofFloat(mKeyguardStatusBar.getAlpha(), 0f);
1248 anim.addUpdateListener(mStatusBarAnimateAlphaListener);
Jason Monk1fd3fc32018-08-14 17:20:09 -04001249 anim.setStartDelay(mKeyguardMonitor.isKeyguardFadingAway()
1250 ? mKeyguardMonitor.getKeyguardFadingAwayDelay()
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001251 : 0);
Jason Monk1fd3fc32018-08-14 17:20:09 -04001252 anim.setDuration(mKeyguardMonitor.isKeyguardFadingAway()
1253 ? mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001254 : StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc18010f2016-01-20 13:41:30 -08001255 anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001256 anim.addListener(new AnimatorListenerAdapter() {
1257 @Override
1258 public void onAnimationEnd(Animator animation) {
1259 mAnimateKeyguardStatusBarInvisibleEndRunnable.run();
1260 }
1261 });
1262 anim.start();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001263 }
1264
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001265 private final ValueAnimator.AnimatorUpdateListener mStatusBarAnimateAlphaListener =
1266 new ValueAnimator.AnimatorUpdateListener() {
1267 @Override
1268 public void onAnimationUpdate(ValueAnimator animation) {
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001269 mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
1270 updateHeaderKeyguardAlpha();
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001271 }
1272 };
1273
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001274 private void animateKeyguardStatusBarIn(long duration) {
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001275 mKeyguardStatusBar.setVisibility(View.VISIBLE);
1276 mKeyguardStatusBar.setAlpha(0f);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001277 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
1278 anim.addUpdateListener(mStatusBarAnimateAlphaListener);
1279 anim.setDuration(duration);
Selim Cinekc18010f2016-01-20 13:41:30 -08001280 anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001281 anim.start();
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001282 }
1283
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001284 private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = new Runnable() {
1285 @Override
1286 public void run() {
1287 mKeyguardBottomArea.setVisibility(View.GONE);
1288 }
1289 };
1290
1291 private void setKeyguardBottomAreaVisibility(int statusBarState,
1292 boolean goingToFullShade) {
Xiaohui Chen9528f432016-02-12 15:03:18 -08001293 mKeyguardBottomArea.animate().cancel();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001294 if (goingToFullShade) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001295 mKeyguardBottomArea.animate()
1296 .alpha(0f)
Jason Monk1fd3fc32018-08-14 17:20:09 -04001297 .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
1298 .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
Selim Cinekc18010f2016-01-20 13:41:30 -08001299 .setInterpolator(Interpolators.ALPHA_OUT)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001300 .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
1301 .start();
1302 } else if (statusBarState == StatusBarState.KEYGUARD
1303 || statusBarState == StatusBarState.SHADE_LOCKED) {
Adrian Roos91ba3072017-02-14 16:50:46 +01001304 mKeyguardBottomArea.setVisibility(View.VISIBLE);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001305 mKeyguardBottomArea.setAlpha(1f);
1306 } else {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001307 mKeyguardBottomArea.setVisibility(View.GONE);
1308 mKeyguardBottomArea.setAlpha(1f);
1309 }
1310 }
1311
1312 private void setKeyguardStatusViewVisibility(int statusBarState, boolean keyguardFadingAway,
1313 boolean goingToFullShade) {
Lucas Dupin93752552018-03-19 21:32:19 -07001314 mKeyguardStatusView.animate().cancel();
1315 mKeyguardStatusViewAnimating = false;
Jason Monk1fd3fc32018-08-14 17:20:09 -04001316 if ((!keyguardFadingAway && mBarState == StatusBarState.KEYGUARD
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001317 && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001318 mKeyguardStatusViewAnimating = true;
1319 mKeyguardStatusView.animate()
1320 .alpha(0f)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001321 .setStartDelay(0)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001322 .setDuration(160)
Selim Cinekc18010f2016-01-20 13:41:30 -08001323 .setInterpolator(Interpolators.ALPHA_OUT)
Lucas Dupin93752552018-03-19 21:32:19 -07001324 .withEndAction(mAnimateKeyguardStatusViewGoneEndRunnable);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001325 if (keyguardFadingAway) {
1326 mKeyguardStatusView.animate()
Jason Monk1fd3fc32018-08-14 17:20:09 -04001327 .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
1328 .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration()/2)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001329 .start();
1330 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001331 } else if (mBarState == StatusBarState.SHADE_LOCKED
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001332 && statusBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001333 mKeyguardStatusView.setVisibility(View.VISIBLE);
1334 mKeyguardStatusViewAnimating = true;
1335 mKeyguardStatusView.setAlpha(0f);
1336 mKeyguardStatusView.animate()
1337 .alpha(1f)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001338 .setStartDelay(0)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001339 .setDuration(320)
Selim Cinekc18010f2016-01-20 13:41:30 -08001340 .setInterpolator(Interpolators.ALPHA_IN)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001341 .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
1342 } else if (statusBarState == StatusBarState.KEYGUARD) {
Lucas Dupin93752552018-03-19 21:32:19 -07001343 if (keyguardFadingAway) {
1344 mKeyguardStatusViewAnimating = true;
1345 mKeyguardStatusView.animate()
1346 .alpha(0)
1347 .translationYBy(-getHeight() * 0.05f)
1348 .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
1349 .setDuration(125)
1350 .setStartDelay(0)
1351 .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable)
1352 .start();
1353 } else {
1354 mKeyguardStatusView.setVisibility(View.VISIBLE);
1355 mKeyguardStatusView.setAlpha(1f);
1356 }
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001357 } else {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001358 mKeyguardStatusView.setVisibility(View.GONE);
1359 mKeyguardStatusView.setAlpha(1f);
1360 }
1361 }
1362
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001363 private void updateQsState() {
Selim Cinekbc243a92016-09-27 16:35:13 -07001364 mNotificationStackScroller.setQsExpanded(mQsExpanded);
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001365 mNotificationStackScroller.setScrollingEnabled(
Jason Monk1fd3fc32018-08-14 17:20:09 -04001366 mBarState != StatusBarState.KEYGUARD && (!mQsExpanded
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001367 || mQsExpansionFromOverscroll));
Jorim Jaggia2052ea2014-08-05 16:22:30 +02001368 updateEmptyShadeView();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001369 mQsNavbarScrim.setVisibility(mBarState == StatusBarState.SHADE && mQsExpanded
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001370 && !mStackScrollerOverscrolling && mQsScrimEnabled
Selim Cinek684a4422015-04-15 16:18:39 -07001371 ? View.VISIBLE
1372 : View.INVISIBLE);
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001373 if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
Adrian Roos2d1ef302014-10-24 18:42:51 +02001374 mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001375 }
Jason Monk0ceef212016-11-02 14:05:23 -04001376 if (mQs == null) return;
1377 mQs.setExpanded(mQsExpanded);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001378 }
1379
1380 private void setQsExpansion(float height) {
1381 height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
Jason Monkbd28a85b2015-02-10 13:29:02 -05001382 mQsFullyExpanded = height == mQsMaxExpansionHeight && mQsMaxExpansionHeight != 0;
Jorim Jaggi290600a2014-05-30 17:02:20 +02001383 if (height > mQsMinExpansionHeight && !mQsExpanded && !mStackScrollerOverscrolling) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001384 setQsExpanded(true);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001385 } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001386 setQsExpanded(false);
John Spurlock73203eb2014-04-15 16:14:46 -04001387 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001388 mQsExpansionHeight = height;
Jason Monke1be3422016-02-09 10:51:40 -05001389 updateQsExpansion();
Selim Cinek1408eb52014-06-02 14:45:38 +02001390 requestScrollerTopPaddingUpdate(false /* animate */);
Selim Cinekfc222962018-07-20 20:09:23 -07001391 updateHeaderKeyguardAlpha();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001392 if (mBarState == StatusBarState.SHADE_LOCKED
1393 || mBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001394 updateKeyguardBottomAreaAlpha();
1395 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001396 if (mBarState == StatusBarState.SHADE && mQsExpanded
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001397 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
1398 mQsNavbarScrim.setAlpha(getQsExpansionFraction());
1399 }
Selim Cinek90c94652014-08-18 16:46:22 +02001400
Phil Weaver428e3972018-01-18 12:50:05 -08001401 if (mAccessibilityManager.isEnabled()) {
1402 setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
Selim Cinek90c94652014-08-18 16:46:22 +02001403 }
Phil Weaver428e3972018-01-18 12:50:05 -08001404
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001405 if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
Blazej Magnowski72323322015-07-24 11:49:40 -07001406 mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
Felipe Lemeee5d6302016-04-22 16:11:19 -07001407 false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
Blazej Magnowski72323322015-07-24 11:49:40 -07001408 }
Jorim Jaggi58bef332014-11-21 18:10:32 +01001409 if (DEBUG) {
1410 invalidate();
1411 }
Selim Cinek90c94652014-08-18 16:46:22 +02001412 }
1413
Xiaohui Chen9528f432016-02-12 15:03:18 -08001414 protected void updateQsExpansion() {
Jason Monk0ceef212016-11-02 14:05:23 -04001415 if (mQs == null) return;
shawnlin8e4e92c2018-04-12 18:47:24 +08001416 float qsExpansionFraction = getQsExpansionFraction();
1417 mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
1418 mNotificationStackScroller.setQsExpansionFraction(qsExpansionFraction);
Jason Monke1be3422016-02-09 10:51:40 -05001419 }
1420
Phil Weaver428e3972018-01-18 12:50:05 -08001421 private String determineAccessibilityPaneTitle() {
Jason Monk7a952882016-11-15 15:38:30 -05001422 if (mQs != null && mQs.isCustomizing()) {
Jason Monk39c98e62016-03-16 09:18:35 -04001423 return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
Phil Weaver428e3972018-01-18 12:50:05 -08001424 } else if (mQsExpansionHeight != 0.0f && mQsFullyExpanded) {
1425 // Upon initialisation when we are not layouted yet we don't want to announce that we
1426 // are fully expanded, hence the != 0.0f check.
1427 return getContext().getString(R.string.accessibility_desc_quick_settings);
Jason Monk1fd3fc32018-08-14 17:20:09 -04001428 } else if (mBarState == StatusBarState.KEYGUARD) {
Selim Cinek90c94652014-08-18 16:46:22 +02001429 return getContext().getString(R.string.accessibility_desc_lock_screen);
1430 } else {
1431 return getContext().getString(R.string.accessibility_desc_notification_shade);
1432 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001433 }
1434
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001435 private float calculateQsTopPadding() {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001436 if (mKeyguardShowing
Jason Monk3c68ca22015-01-30 11:30:29 -05001437 && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001438
1439 // Either QS pushes the notifications down when fully expanded, or QS is fully above the
Lucas Dupin41ff6952018-02-18 19:39:32 -08001440 // notifications (mostly on tablets). maxNotificationPadding denotes the normal top
1441 // padding on Keyguard, maxQsPadding denotes the top padding from the quick settings
1442 // panel. We need to take the maximum and linearly interpolate with the panel expansion
1443 // for a nice motion.
1444 int maxNotificationPadding = mClockPositionResult.stackScrollerPadding;
1445 int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
Jason Monk1fd3fc32018-08-14 17:20:09 -04001446 int max = mBarState == StatusBarState.KEYGUARD
Lucas Dupin41ff6952018-02-18 19:39:32 -08001447 ? Math.max(maxNotificationPadding, maxQsPadding)
1448 : maxQsPadding;
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001449 return (int) interpolate(getExpandedFraction(),
1450 mQsMinExpansionHeight, max);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001451 } else if (mQsSizeChangeAnimator != null) {
1452 return (int) mQsSizeChangeAnimator.getAnimatedValue();
Jason Monk16ac3772016-02-10 15:39:21 -05001453 } else if (mKeyguardShowing) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001454 // We can only do the smoother transition on Keyguard when we also are not collapsing
1455 // from a scrolled quick settings.
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001456 return interpolate(getQsExpansionFraction(),
Selim Cinek33d46142016-01-15 18:58:39 -08001457 mNotificationStackScroller.getIntrinsicPadding(),
Selim Cinekd7768f42017-11-22 06:43:44 -08001458 mQsMaxExpansionHeight + mQsNotificationTopPadding);
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001459 } else {
Selim Cinekb95fd182017-12-21 13:03:32 -08001460 return mQsExpansionHeight + mQsNotificationTopPadding;
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001461 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001462 }
1463
Xiaohui Chen9528f432016-02-12 15:03:18 -08001464 protected void requestScrollerTopPaddingUpdate(boolean animate) {
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001465 mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
Lucas Dupin60661a62018-04-12 10:50:13 -07001466 animate, mKeyguardShowing
Jason Monk3c68ca22015-01-30 11:30:29 -05001467 && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted));
Jorim Jaggid7daab72014-05-06 22:22:20 +02001468 }
1469
1470 private void trackMovement(MotionEvent event) {
Selim Cinekd5ab6452016-12-08 16:34:00 -08001471 if (mQsVelocityTracker != null) mQsVelocityTracker.addMovement(event);
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001472 mLastTouchX = event.getX();
1473 mLastTouchY = event.getY();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001474 }
1475
1476 private void initVelocityTracker() {
Selim Cinekd5ab6452016-12-08 16:34:00 -08001477 if (mQsVelocityTracker != null) {
1478 mQsVelocityTracker.recycle();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001479 }
Selim Cinekd5ab6452016-12-08 16:34:00 -08001480 mQsVelocityTracker = VelocityTracker.obtain();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001481 }
1482
Selim Cinekd5ab6452016-12-08 16:34:00 -08001483 private float getCurrentQSVelocity() {
1484 if (mQsVelocityTracker == null) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001485 return 0;
1486 }
Selim Cinekd5ab6452016-12-08 16:34:00 -08001487 mQsVelocityTracker.computeCurrentVelocity(1000);
1488 return mQsVelocityTracker.getYVelocity();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001489 }
1490
Selim Cinek831941f2015-06-17 15:09:30 -07001491 private void cancelQsAnimation() {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001492 if (mQsExpansionAnimator != null) {
1493 mQsExpansionAnimator.cancel();
1494 }
1495 }
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001496
Lucas Dupinee63c372018-08-03 11:58:24 -07001497 /**
1498 * @see #flingSettings(float, int, Runnable, boolean)
1499 */
1500 public void flingSettings(float vel, int type) {
1501 flingSettings(vel, type, null, false /* isClick */);
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001502 }
1503
Lucas Dupinee63c372018-08-03 11:58:24 -07001504 /**
1505 * Animates QS or QQS as if the user had swiped up or down.
1506 *
1507 * @param vel Finger velocity or 0 when not initiated by touch events.
1508 * @param type Either {@link #FLING_EXPAND}, {@link #FLING_COLLAPSE} or {@link #FLING_HIDE}.
1509 * @param onFinishRunnable Runnable to be executed at the end of animation.
1510 * @param isClick If originated by click (different interpolator and duration.)
1511 */
1512 protected void flingSettings(float vel, int type, final Runnable onFinishRunnable,
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07001513 boolean isClick) {
Lucas Dupinee63c372018-08-03 11:58:24 -07001514 float target;
1515 switch (type) {
1516 case FLING_EXPAND:
1517 target = mQsMaxExpansionHeight;
1518 break;
1519 case FLING_COLLAPSE:
1520 target = mQsMinExpansionHeight;
1521 break;
1522 case FLING_HIDE:
1523 default:
1524 target = 0;
1525 }
Jorim Jaggi9cd731a2014-05-22 14:26:06 +02001526 if (target == mQsExpansionHeight) {
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001527 if (onFinishRunnable != null) {
1528 onFinishRunnable.run();
1529 }
Jorim Jaggi9cd731a2014-05-22 14:26:06 +02001530 return;
1531 }
Jorim Jaggi519779e2016-10-12 16:52:14 +02001532
1533 // If we move in the opposite direction, reset velocity and use a different duration.
1534 boolean oppositeDirection = false;
Lucas Dupinee63c372018-08-03 11:58:24 -07001535 boolean expanding = type == FLING_EXPAND;
1536 if (vel > 0 && !expanding || vel < 0 && expanding) {
Selim Cinek5386fb32014-09-03 16:37:36 +02001537 vel = 0;
Jorim Jaggi519779e2016-10-12 16:52:14 +02001538 oppositeDirection = true;
Selim Cinek5386fb32014-09-03 16:37:36 +02001539 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001540 ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07001541 if (isClick) {
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08001542 animator.setInterpolator(Interpolators.TOUCH_RESPONSE);
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07001543 animator.setDuration(368);
1544 } else {
1545 mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
1546 }
Jorim Jaggi519779e2016-10-12 16:52:14 +02001547 if (oppositeDirection) {
Selim Cinek5386fb32014-09-03 16:37:36 +02001548 animator.setDuration(350);
1549 }
Lucas Dupinee63c372018-08-03 11:58:24 -07001550 animator.addUpdateListener(animation -> {
1551 setQsExpansion((Float) animation.getAnimatedValue());
Jorim Jaggid7daab72014-05-06 22:22:20 +02001552 });
1553 animator.addListener(new AnimatorListenerAdapter() {
1554 @Override
1555 public void onAnimationEnd(Animator animation) {
Mady Mellorc2dbe492017-03-30 13:22:03 -07001556 mNotificationStackScroller.resetCheckSnoozeLeavebehind();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001557 mQsExpansionAnimator = null;
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001558 if (onFinishRunnable != null) {
1559 onFinishRunnable.run();
1560 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001561 }
1562 });
1563 animator.start();
1564 mQsExpansionAnimator = animator;
Lucas Dupinee63c372018-08-03 11:58:24 -07001565 mQsAnimatorExpand = expanding;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001566 }
1567
1568 /**
1569 * @return Whether we should intercept a gesture to open Quick Settings.
1570 */
Selim Cinek4c6969a2014-05-26 19:22:17 +02001571 private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
Selim Cinek684a4422015-04-15 16:18:39 -07001572 if (!mQsExpansionEnabled || mCollapsedOnDown) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001573 return false;
1574 }
Jason Monk0ceef212016-11-02 14:05:23 -04001575 View header = mKeyguardShowing ? mKeyguardStatusBar : mQs.getHeader();
1576 final boolean onHeader = x >= mQsFrame.getX()
1577 && x <= mQsFrame.getX() + mQsFrame.getWidth()
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001578 && y >= header.getTop() && y <= header.getBottom();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001579 if (mQsExpanded) {
Jason Monk16ac3772016-02-10 15:39:21 -05001580 return onHeader || (yDiff < 0 && isInQsArea(x, y));
Jorim Jaggid7daab72014-05-06 22:22:20 +02001581 } else {
1582 return onHeader;
1583 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001584 }
1585
1586 @Override
1587 protected boolean isScrolledToBottom() {
1588 if (!isInSettings()) {
Jason Monk1fd3fc32018-08-14 17:20:09 -04001589 return mBarState == StatusBarState.KEYGUARD
Jorim Jaggi58bef332014-11-21 18:10:32 +01001590 || mNotificationStackScroller.isScrolledToBottom();
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001591 } else {
Jason Monk16ac3772016-02-10 15:39:21 -05001592 return true;
Chris Wren64161cc2012-12-17 16:49:30 -05001593 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001594 }
1595
1596 @Override
1597 protected int getMaxPanelHeight() {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001598 int min = mStatusBarMinHeight;
Jason Monk1fd3fc32018-08-14 17:20:09 -04001599 if (mBarState != StatusBarState.KEYGUARD
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001600 && mNotificationStackScroller.getNotGoneChildCount() == 0) {
Selim Cinek94c2d822016-07-13 18:50:04 -07001601 int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001602 min = Math.max(min, minHeight);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001603 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001604 int maxHeight;
Jason Monk3c68ca22015-01-30 11:30:29 -05001605 if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) {
Jorim Jaggi58bef332014-11-21 18:10:32 +01001606 maxHeight = calculatePanelHeightQsExpanded();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001607 } else {
Lucas Dupin60661a62018-04-12 10:50:13 -07001608 maxHeight = calculatePanelHeightShade();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001609 }
1610 maxHeight = Math.max(maxHeight, min);
Jorim Jaggi1d480692014-05-20 19:41:58 +02001611 return maxHeight;
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001612 }
1613
Jim Miller07e03842016-06-22 15:18:13 -07001614 public boolean isInSettings() {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001615 return mQsExpanded;
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001616 }
1617
Jim Miller07e03842016-06-22 15:18:13 -07001618 public boolean isExpanding() {
1619 return mIsExpanding;
1620 }
1621
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001622 @Override
1623 protected void onHeightUpdated(float expandedHeight) {
Jason Monk3c68ca22015-01-30 11:30:29 -05001624 if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
Lucas Dupin41ff6952018-02-18 19:39:32 -08001625 // Updating the clock position will set the top padding which might
1626 // trigger a new panel height and re-position the clock.
1627 // This is a circular dependency and should be avoided, otherwise we'll have
1628 // a stack overflow.
1629 if (mStackScrollerMeasuringPass > 2) {
1630 if (DEBUG) Log.d(TAG, "Unstable notification panel height. Aborting.");
1631 } else {
1632 positionClockAndNotifications();
1633 }
Jorim Jaggi7d16bb12014-05-22 04:24:50 +02001634 }
Jason Monk3c68ca22015-01-30 11:30:29 -05001635 if (mQsExpandImmediate || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001636 && !mQsExpansionFromOverscroll) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001637 float t;
1638 if (mKeyguardShowing) {
Jorim Jaggi54045422014-07-03 18:30:40 +02001639
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001640 // On Keyguard, interpolate the QS expansion linearly to the panel expansion
Selim Cinek48ff9b42016-11-09 19:31:51 -08001641 t = expandedHeight / (getMaxPanelHeight());
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001642 } else {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001643 // In Shade, interpolate linearly such that QS is closed whenever panel height is
1644 // minimum QS expansion + minStackHeight
1645 float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
Selim Cinekd1ad9ab2016-03-01 17:52:20 -08001646 + mNotificationStackScroller.getLayoutMinHeight();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001647 float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
1648 t = (expandedHeight - panelHeightQsCollapsed)
1649 / (panelHeightQsExpanded - panelHeightQsCollapsed);
1650 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001651 setQsExpansion(mQsMinExpansionHeight
Selim Cinekd7768f42017-11-22 06:43:44 -08001652 + t * (mQsMaxExpansionHeight - mQsMinExpansionHeight));
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001653 }
Selim Cinekbc243a92016-09-27 16:35:13 -07001654 updateExpandedHeight(expandedHeight);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001655 updateHeader();
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001656 updateUnlockIcon();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001657 updateNotificationTranslucency();
Selim Cinek4a21a7f2015-05-19 11:00:38 -07001658 updatePanelExpanded();
Selim Cinek684a4422015-04-15 16:18:39 -07001659 mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
Jorim Jaggi58bef332014-11-21 18:10:32 +01001660 if (DEBUG) {
1661 invalidate();
1662 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001663 }
1664
Selim Cinek4a21a7f2015-05-19 11:00:38 -07001665 private void updatePanelExpanded() {
1666 boolean isExpanded = !isFullyCollapsed();
1667 if (mPanelExpanded != isExpanded) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +09001668 mHeadsUpManager.setIsPanelExpanded(isExpanded);
Selim Cinek4a21a7f2015-05-19 11:00:38 -07001669 mStatusBar.setPanelExpanded(isExpanded);
1670 mPanelExpanded = isExpanded;
1671 }
1672 }
1673
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001674 private int calculatePanelHeightShade() {
1675 int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
Lucas Dupin41ff6952018-02-18 19:39:32 -08001676 int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin;
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001677 maxHeight += mNotificationStackScroller.getTopPaddingOverflow();
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001678
Jason Monk1fd3fc32018-08-14 17:20:09 -04001679 if (mBarState == StatusBarState.KEYGUARD) {
Lucas Dupin60661a62018-04-12 10:50:13 -07001680 int minKeyguardPanelBottom = mClockPositionAlgorithm.getExpandedClockPosition()
1681 + mKeyguardStatusView.getHeight()
1682 + mNotificationStackScroller.getIntrinsicContentHeight();
1683 return Math.max(maxHeight, minKeyguardPanelBottom);
1684 } else {
1685 return maxHeight;
1686 }
Lucas Dupin41ff6952018-02-18 19:39:32 -08001687 }
1688
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001689 private int calculatePanelHeightQsExpanded() {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001690 float notificationHeight = mNotificationStackScroller.getHeight()
1691 - mNotificationStackScroller.getEmptyBottomMargin()
1692 - mNotificationStackScroller.getTopPadding();
Jorim Jaggi0cce70c2014-11-04 16:13:41 +01001693
1694 // When only empty shade view is visible in QS collapsed state, simulate that we would have
1695 // it in expanded QS state as well so we don't run into troubles when fading the view in/out
1696 // and expanding/collapsing the whole panel from/to quick settings.
Julia Reynolds34f14962018-05-03 12:40:20 +00001697 if (mNotificationStackScroller.getNotGoneChildCount() == 0
1698 && mShowEmptyShadeView) {
Selim Cinekdb167372016-11-17 15:41:17 -08001699 notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
Jorim Jaggi0cce70c2014-11-04 16:13:41 +01001700 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001701 int maxQsHeight = mQsMaxExpansionHeight;
1702
Selim Cinekd7768f42017-11-22 06:43:44 -08001703 if (mKeyguardShowing) {
1704 maxQsHeight += mQsNotificationTopPadding;
1705 }
1706
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001707 // If an animation is changing the size of the QS panel, take the animated value.
1708 if (mQsSizeChangeAnimator != null) {
1709 maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
1710 }
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001711 float totalHeight = Math.max(
Jason Monk1fd3fc32018-08-14 17:20:09 -04001712 maxQsHeight, mBarState == StatusBarState.KEYGUARD
Lucas Dupin41ff6952018-02-18 19:39:32 -08001713 ? mClockPositionResult.stackScrollerPadding : 0)
Selim Cinekbc243a92016-09-27 16:35:13 -07001714 + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001715 if (totalHeight > mNotificationStackScroller.getHeight()) {
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001716 float fullyCollapsedHeight = maxQsHeight
Selim Cinekd1ad9ab2016-03-01 17:52:20 -08001717 + mNotificationStackScroller.getLayoutMinHeight();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001718 totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
1719 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001720 return (int) totalHeight;
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001721 }
1722
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001723 private void updateNotificationTranslucency() {
Selim Cinekbbc580b2015-06-03 14:11:03 +02001724 float alpha = 1f;
Lucas Dupin60661a62018-04-12 10:50:13 -07001725 if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp &&
1726 !mHeadsUpManager.hasPinnedHeadsUp()) {
Selim Cinekbbc580b2015-06-03 14:11:03 +02001727 alpha = getFadeoutAlpha();
Jorim Jaggi5ad92c52014-07-28 21:07:32 +02001728 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001729 mNotificationStackScroller.setAlpha(alpha);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001730 }
1731
Selim Cinekbbc580b2015-06-03 14:11:03 +02001732 private float getFadeoutAlpha() {
Selim Cinek816c8e42015-11-19 12:00:45 -08001733 float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
Selim Cinekdb167372016-11-17 15:41:17 -08001734 / mQsMinExpansionHeight;
Selim Cinekbbc580b2015-06-03 14:11:03 +02001735 alpha = Math.max(0, Math.min(alpha, 1));
1736 alpha = (float) Math.pow(alpha, 0.75);
1737 return alpha;
1738 }
1739
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001740 @Override
1741 protected float getOverExpansionAmount() {
1742 return mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */);
1743 }
1744
1745 @Override
1746 protected float getOverExpansionPixels() {
1747 return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
1748 }
1749
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001750 private void updateUnlockIcon() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04001751 if (mBarState == StatusBarState.KEYGUARD
1752 || mBarState == StatusBarState.SHADE_LOCKED) {
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001753 boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
Selim Cinekbaa23272014-07-08 18:01:07 +02001754 KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001755 if (active && !mUnlockIconActive && mTracking) {
Selim Cinekc18010f2016-01-20 13:41:30 -08001756 lockIcon.setImageAlpha(1.0f, true, 150, Interpolators.FAST_OUT_LINEAR_IN, null);
Selim Cinekbaa23272014-07-08 18:01:07 +02001757 lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
Selim Cinekc18010f2016-01-20 13:41:30 -08001758 Interpolators.FAST_OUT_LINEAR_IN);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001759 } else if (!active && mUnlockIconActive && mTracking) {
Jorim Jaggi27c9b742015-04-09 10:34:49 -07001760 lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true /* animate */,
Selim Cinekc18010f2016-01-20 13:41:30 -08001761 150, Interpolators.FAST_OUT_LINEAR_IN, null);
Selim Cinekbaa23272014-07-08 18:01:07 +02001762 lockIcon.setImageScale(1.0f, true, 150,
Selim Cinekc18010f2016-01-20 13:41:30 -08001763 Interpolators.FAST_OUT_LINEAR_IN);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001764 }
1765 mUnlockIconActive = active;
1766 }
Jorim Jaggi457cc352014-06-02 22:47:42 +02001767 }
1768
1769 /**
1770 * Hides the header when notifications are colliding with it.
1771 */
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001772 private void updateHeader() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04001773 if (mBarState == StatusBarState.KEYGUARD) {
Jason Monke1be3422016-02-09 10:51:40 -05001774 updateHeaderKeyguardAlpha();
Jorim Jaggi457cc352014-06-02 22:47:42 +02001775 }
Jason Monke1be3422016-02-09 10:51:40 -05001776 updateQsExpansion();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001777 }
1778
Xiaohui Chen9528f432016-02-12 15:03:18 -08001779 protected float getHeaderTranslation() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04001780 if (mBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001781 return 0;
1782 }
Selim Cinek2627d722018-01-19 12:16:49 -08001783 float translation = MathUtils.lerp(-mQsMinExpansionHeight, 0,
1784 Math.min(1.0f, mNotificationStackScroller.getAppearFraction(mExpandedHeight)))
1785 + mExpandOffset;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001786 return Math.min(0, translation);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001787 }
1788
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001789 /**
1790 * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
1791 * during swiping up
1792 */
1793 private float getKeyguardContentsAlpha() {
1794 float alpha;
Jason Monk1fd3fc32018-08-14 17:20:09 -04001795 if (mBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001796
1797 // When on Keyguard, we hide the header as soon as the top card of the notification
1798 // stack scroller is close enough (collision distance) to the bottom of the header.
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001799 alpha = getNotificationsTopY()
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001800 /
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001801 (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001802 } else {
1803
1804 // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
1805 // soon as we start translating the stack.
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001806 alpha = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001807 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001808 alpha = MathUtils.constrain(alpha, 0, 1);
1809 alpha = (float) Math.pow(alpha, 0.75);
1810 return alpha;
1811 }
1812
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001813 private void updateHeaderKeyguardAlpha() {
Selim Cinekfc222962018-07-20 20:09:23 -07001814 if (!mKeyguardShowing) {
1815 return;
1816 }
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001817 float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001818 mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001819 * mKeyguardStatusBarAnimateAlpha);
Selim Cinek8f2d767f2015-06-15 20:55:04 -07001820 mKeyguardStatusBar.setVisibility(mKeyguardStatusBar.getAlpha() != 0f
1821 && !mDozing ? VISIBLE : INVISIBLE);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001822 }
1823
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001824 private void updateKeyguardBottomAreaAlpha() {
Lucas Dupinbc9aac12018-03-04 20:18:15 -08001825 // There are two possible panel expansion behaviors:
1826 // • User dragging up to unlock: we want to fade out as quick as possible
1827 // (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area.
1828 // • User tapping on lock screen: bouncer won't be visible but panel expansion will
1829 // change due to "unlock hint animation." In this case, fading out the bottom area
1830 // would also hide the message that says "swipe to unlock," we don't want to do that.
1831 float expansionAlpha = MathUtils.map(isUnlockHintRunning()
1832 ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
1833 0f, 1f, getExpandedFraction());
1834 float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
Adrian Roos14410b02015-06-10 13:35:41 -07001835 mKeyguardBottomArea.setAlpha(alpha);
1836 mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
1837 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
1838 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
Adrian Roos8d4e99f2017-05-25 18:03:58 -07001839 View ambientIndicationContainer = mStatusBar.getAmbientIndicationContainer();
1840 if (ambientIndicationContainer != null) {
1841 ambientIndicationContainer.setAlpha(alpha);
1842 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001843 }
1844
Jorim Jaggiad46ffef2014-07-04 18:05:06 +02001845 private float getNotificationsTopY() {
1846 if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
1847 return getExpandedHeight();
1848 }
1849 return mNotificationStackScroller.getNotificationsTopY();
1850 }
1851
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001852 @Override
Selim Cinek1685e632014-04-08 02:27:49 +02001853 protected void onExpandingStarted() {
1854 super.onExpandingStarted();
1855 mNotificationStackScroller.onExpansionStarted();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001856 mIsExpanding = true;
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001857 mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
Jorim Jaggi56306252014-07-03 00:40:09 +02001858 if (mQsExpanded) {
Jorim Jaggi56306252014-07-03 00:40:09 +02001859 onQsExpansionStarted();
1860 }
Jason Monkb5ece9a2016-04-22 11:40:36 -04001861 // Since there are QS tiles in the header now, we need to make sure we start listening
1862 // immediately so they can be up to date.
Jason Monkf4e019a2016-11-03 09:07:20 -04001863 if (mQs == null) return;
Jason Monk0ceef212016-11-02 14:05:23 -04001864 mQs.setHeaderListening(true);
Selim Cinek1685e632014-04-08 02:27:49 +02001865 }
1866
1867 @Override
1868 protected void onExpandingFinished() {
1869 super.onExpandingFinished();
1870 mNotificationStackScroller.onExpansionStopped();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001871 mHeadsUpManager.onExpandingFinished();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001872 mIsExpanding = false;
Selim Cinek684a4422015-04-15 16:18:39 -07001873 if (isFullyCollapsed()) {
Jorim Jaggi613f55f2015-07-16 15:30:10 -07001874 DejankUtils.postAfterTraversal(new Runnable() {
1875 @Override
1876 public void run() {
1877 setListening(false);
1878 }
1879 });
1880
1881 // Workaround b/22639032: Make sure we invalidate something because else RenderThread
1882 // thinks we are actually drawing a frame put in reality we don't, so RT doesn't go
1883 // ahead with rendering and we jank.
1884 postOnAnimation(new Runnable() {
1885 @Override
1886 public void run() {
1887 getParent().invalidateChild(NotificationPanelView.this, mDummyDirtyRect);
1888 }
1889 });
Jorim Jaggie65e3102014-07-01 22:00:50 +02001890 } else {
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001891 setListening(true);
Jorim Jaggie65e3102014-07-01 22:00:50 +02001892 }
Jason Monk3c68ca22015-01-30 11:30:29 -05001893 mQsExpandImmediate = false;
shawnlin8e4e92c2018-04-12 18:47:24 +08001894 mNotificationStackScroller.setShouldShowShelfOnly(false);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001895 mTwoFingerQsExpandPossible = false;
Selim Cinek684a4422015-04-15 16:18:39 -07001896 mIsExpansionFromHeadsUp = false;
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001897 notifyListenersTrackingHeadsUp(null);
Selim Cinek684a4422015-04-15 16:18:39 -07001898 mExpandingFromHeadsUp = false;
Selim Cinek3d395c62015-06-16 19:37:37 -07001899 setPanelScrimMinFraction(0.0f);
Jorim Jaggie65e3102014-07-01 22:00:50 +02001900 }
1901
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001902 private void notifyListenersTrackingHeadsUp(ExpandableNotificationRow pickedChild) {
1903 for (int i = 0; i < mTrackingHeadsUpListeners.size(); i++) {
1904 Consumer<ExpandableNotificationRow> listener
1905 = mTrackingHeadsUpListeners.get(i);
1906 listener.accept(pickedChild);
1907 }
1908 }
1909
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001910 private void setListening(boolean listening) {
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001911 mKeyguardStatusBar.setListening(listening);
Jason Monk0ceef212016-11-02 14:05:23 -04001912 if (mQs == null) return;
1913 mQs.setListening(listening);
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001914 }
1915
Jorim Jaggie65e3102014-07-01 22:00:50 +02001916 @Override
Oren Blasberg8d3fea12015-07-10 14:21:44 -07001917 public void expand(boolean animate) {
1918 super.expand(animate);
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001919 setListening(true);
Selim Cinek1685e632014-04-08 02:27:49 +02001920 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001921
1922 @Override
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001923 protected void setOverExpansion(float overExpansion, boolean isPixels) {
Jason Monk3c68ca22015-01-30 11:30:29 -05001924 if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
Jorim Jaggidc96d632014-07-01 18:48:52 +02001925 return;
1926 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001927 if (mBarState != StatusBarState.KEYGUARD) {
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001928 mNotificationStackScroller.setOnHeightChangedListener(null);
1929 if (isPixels) {
1930 mNotificationStackScroller.setOverScrolledPixels(
1931 overExpansion, true /* onTop */, false /* animate */);
1932 } else {
1933 mNotificationStackScroller.setOverScrollAmount(
1934 overExpansion, true /* onTop */, false /* animate */);
1935 }
1936 mNotificationStackScroller.setOnHeightChangedListener(this);
Selim Cinek1408eb52014-06-02 14:45:38 +02001937 }
Selim Cinek24120a52014-05-26 10:05:42 +02001938 }
1939
1940 @Override
Jorim Jaggi282a6152014-06-02 23:37:53 +02001941 protected void onTrackingStarted() {
Lucas Dupinbc9aac12018-03-04 20:18:15 -08001942 mFalsingManager.onTrackingStarted(mStatusBar.isKeyguardCurrentlySecure());
Jorim Jaggi282a6152014-06-02 23:37:53 +02001943 super.onTrackingStarted();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001944 if (mQsFullyExpanded) {
Jason Monk3c68ca22015-01-30 11:30:29 -05001945 mQsExpandImmediate = true;
shawnlin8e4e92c2018-04-12 18:47:24 +08001946 mNotificationStackScroller.setShouldShowShelfOnly(true);
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001947 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001948 if (mBarState == StatusBarState.KEYGUARD
1949 || mBarState == StatusBarState.SHADE_LOCKED) {
Adrian Roose31f30e2017-01-25 14:48:15 -08001950 mAffordanceHelper.animateHideLeftRightIcon();
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001951 }
Jorim Jaggie4b840d2015-06-30 16:19:17 -07001952 mNotificationStackScroller.onPanelTrackingStarted();
Jorim Jaggi282a6152014-06-02 23:37:53 +02001953 }
1954
1955 @Override
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +02001956 protected void onTrackingStopped(boolean expand) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001957 mFalsingManager.onTrackingStopped();
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +02001958 super.onTrackingStopped(expand);
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001959 if (expand) {
1960 mNotificationStackScroller.setOverScrolledPixels(
1961 0.0f, true /* onTop */, true /* animate */);
1962 }
Jorim Jaggie4b840d2015-06-30 16:19:17 -07001963 mNotificationStackScroller.onPanelTrackingStopped();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001964 if (expand && (mBarState == StatusBarState.KEYGUARD
1965 || mBarState == StatusBarState.SHADE_LOCKED)) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001966 if (!mHintAnimationRunning) {
Adrian Roose31f30e2017-01-25 14:48:15 -08001967 mAffordanceHelper.reset(true);
Selim Cinekbaa23272014-07-08 18:01:07 +02001968 }
Jorim Jaggi282a6152014-06-02 23:37:53 +02001969 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001970 if (!expand && (mBarState == StatusBarState.KEYGUARD
1971 || mBarState == StatusBarState.SHADE_LOCKED)) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001972 KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
Selim Cinekc18010f2016-01-20 13:41:30 -08001973 lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
1974 lockIcon.setImageScale(2.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001975 }
Selim Cinek24120a52014-05-26 10:05:42 +02001976 }
1977
Selim Cinek24120a52014-05-26 10:05:42 +02001978 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001979 public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001980
1981 // Block update if we are in quick settings and just the top padding changed
1982 // (i.e. view == null).
1983 if (view == null && mQsExpanded) {
1984 return;
1985 }
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02001986 if (needsAnimation && mInterpolatedDarkAmount == 0) {
Lucas Dupin60661a62018-04-12 10:50:13 -07001987 mAnimateNextPositionUpdate = true;
1988 }
Selim Cinekbc243a92016-09-27 16:35:13 -07001989 ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
1990 ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow
1991 ? (ExpandableNotificationRow) firstChildNotGone
1992 : null;
1993 if (firstRow != null
1994 && (view == firstRow || (firstRow.getNotificationParent() == firstRow))) {
Lucas Dupin60661a62018-04-12 10:50:13 -07001995 requestScrollerTopPaddingUpdate(false /* animate */);
Selim Cinekbc243a92016-09-27 16:35:13 -07001996 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001997 requestPanelHeightUpdate();
1998 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001999
2000 @Override
Selim Cineka5e211b2014-08-11 17:35:48 +02002001 public void onReset(ExpandableView view) {
2002 }
2003
Jason Monk8b9d67f2016-03-02 08:59:08 -05002004 public void onQsHeightChanged() {
Jason Monkf4e019a2016-11-03 09:07:20 -04002005 mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0;
Jason Monkf50e8822016-06-01 11:19:26 -04002006 if (mQsExpanded && mQsFullyExpanded) {
Jason Monk8b9d67f2016-03-02 08:59:08 -05002007 mQsExpansionHeight = mQsMaxExpansionHeight;
Selim Cinek1408eb52014-06-02 14:45:38 +02002008 requestScrollerTopPaddingUpdate(false /* animate */);
Jorim Jaggi56306252014-07-03 00:40:09 +02002009 requestPanelHeightUpdate();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002010 }
Phil Weaver428e3972018-01-18 12:50:05 -08002011 if (mAccessibilityManager.isEnabled()) {
2012 setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
2013 }
shawnlin8e4e92c2018-04-12 18:47:24 +08002014 mNotificationStackScroller.setMaxTopPadding(
2015 mQsMaxExpansionHeight + mQsNotificationTopPadding);
Jorim Jaggid7daab72014-05-06 22:22:20 +02002016 }
2017
2018 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +02002019 protected void onConfigurationChanged(Configuration newConfig) {
2020 super.onConfigurationChanged(newConfig);
Adrian Roose31f30e2017-01-25 14:48:15 -08002021 mAffordanceHelper.onConfigurationChanged();
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002022 if (newConfig.orientation != mLastOrientation) {
2023 resetVerticalPanelPosition();
2024 }
2025 mLastOrientation = newConfig.orientation;
Selim Cinek4c6969a2014-05-26 19:22:17 +02002026 }
2027
2028 @Override
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002029 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Adrian Roos5153d4a2016-03-22 10:01:56 -07002030 mNavigationBarBottomHeight = insets.getStableInsetBottom();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002031 updateMaxHeadsUpTranslation();
2032 return insets;
2033 }
2034
2035 private void updateMaxHeadsUpTranslation() {
Selim Cinek684a4422015-04-15 16:18:39 -07002036 mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002037 }
2038
2039 @Override
Jorim Jaggi0a818222014-11-10 19:04:34 +01002040 public void onRtlPropertiesChanged(int layoutDirection) {
2041 if (layoutDirection != mOldLayoutDirection) {
Adrian Roose31f30e2017-01-25 14:48:15 -08002042 mAffordanceHelper.onRtlPropertiesChanged();
Jorim Jaggi0a818222014-11-10 19:04:34 +01002043 mOldLayoutDirection = layoutDirection;
2044 }
2045 }
2046
2047 @Override
Jorim Jaggid7daab72014-05-06 22:22:20 +02002048 public void onClick(View v) {
Amin Shaikh8a3e23c2018-04-17 11:14:32 -04002049 onQsExpansionStarted();
2050 if (mQsExpanded) {
Lucas Dupinee63c372018-08-03 11:58:24 -07002051 flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */,
2052 true /* isClick */);
Amin Shaikh8a3e23c2018-04-17 11:14:32 -04002053 } else if (mQsExpansionEnabled) {
2054 mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0);
Lucas Dupinee63c372018-08-03 11:58:24 -07002055 flingSettings(0 /* vel */, FLING_EXPAND, null /* onFinishRunnable */,
2056 true /* isClick */);
Jorim Jaggid7daab72014-05-06 22:22:20 +02002057 }
2058 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02002059
2060 @Override
Christoph Studerb0183992014-12-22 21:02:26 +01002061 public void onAnimationToSideStarted(boolean rightPage, float translation, float vel) {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002062 boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage;
Selim Cinekbaa23272014-07-08 18:01:07 +02002063 mIsLaunchTransitionRunning = true;
2064 mLaunchAnimationEndRunnable = null;
Christoph Studerb0183992014-12-22 21:02:26 +01002065 float displayDensity = mStatusBar.getDisplayDensity();
2066 int lengthDp = Math.abs((int) (translation / displayDensity));
2067 int velocityDp = Math.abs((int) (vel / displayDensity));
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002068 if (start) {
Chris Wren27a52fa2017-02-01 14:21:43 -05002069 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
Blazej Magnowski72323322015-07-24 11:49:40 -07002070
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002071 mFalsingManager.onLeftAffordanceOn();
2072 if (mFalsingManager.shouldEnforceBouncer()) {
Blazej Magnowski72323322015-07-24 11:49:40 -07002073 mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
2074 @Override
2075 public void run() {
2076 mKeyguardBottomArea.launchLeftAffordance();
2077 }
Felipe Lemeee5d6302016-04-22 16:11:19 -07002078 }, null, true /* dismissShade */, false /* afterKeyguardGone */,
2079 true /* deferred */);
Blazej Magnowski72323322015-07-24 11:49:40 -07002080 }
2081 else {
2082 mKeyguardBottomArea.launchLeftAffordance();
2083 }
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002084 } else {
Jorim Jaggi40aa8812015-09-23 12:59:22 -07002085 if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals(
2086 mLastCameraLaunchSource)) {
Chris Wren27a52fa2017-02-01 14:21:43 -05002087 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
Jorim Jaggi40aa8812015-09-23 12:59:22 -07002088 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002089 mFalsingManager.onCameraOn();
2090 if (mFalsingManager.shouldEnforceBouncer()) {
Blazej Magnowski72323322015-07-24 11:49:40 -07002091 mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
2092 @Override
2093 public void run() {
Jorim Jaggifc832e32015-09-25 11:54:05 -07002094 mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
Blazej Magnowski72323322015-07-24 11:49:40 -07002095 }
Felipe Lemeee5d6302016-04-22 16:11:19 -07002096 }, null, true /* dismissShade */, false /* afterKeyguardGone */,
2097 true /* deferred */);
Blazej Magnowski72323322015-07-24 11:49:40 -07002098 }
2099 else {
Jorim Jaggifc832e32015-09-25 11:54:05 -07002100 mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
Blazej Magnowski72323322015-07-24 11:49:40 -07002101 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02002102 }
Jorim Jaggi826730a2014-12-08 21:05:13 +01002103 mStatusBar.startLaunchTransitionTimeout();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002104 mBlockTouches = true;
2105 }
2106
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002107 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002108 public void onAnimationToSideEnded() {
2109 mIsLaunchTransitionRunning = false;
2110 mIsLaunchTransitionFinished = true;
2111 if (mLaunchAnimationEndRunnable != null) {
2112 mLaunchAnimationEndRunnable.run();
2113 mLaunchAnimationEndRunnable = null;
2114 }
Jorim Jaggife762342016-10-13 14:33:27 +02002115 mStatusBar.readyForKeyguardDone();
Selim Cinekbaa23272014-07-08 18:01:07 +02002116 }
2117
2118 @Override
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002119 protected void startUnlockHintAnimation() {
Selim Cineke64f52a2017-08-24 14:48:38 -07002120 if (mPowerManager.isPowerSaveMode()) {
2121 onUnlockHintStarted();
2122 onUnlockHintFinished();
2123 return;
2124 }
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002125 super.startUnlockHintAnimation();
2126 startHighlightIconAnimation(getCenterIcon());
2127 }
2128
2129 /**
2130 * Starts the highlight (making it fully opaque) animation on an icon.
2131 */
Selim Cinekbaa23272014-07-08 18:01:07 +02002132 private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
2133 icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
Selim Cinekc18010f2016-01-20 13:41:30 -08002134 Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002135 @Override
2136 public void run() {
Jorim Jaggi27c9b742015-04-09 10:34:49 -07002137 icon.setImageAlpha(icon.getRestingAlpha(),
2138 true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
Selim Cinekc18010f2016-01-20 13:41:30 -08002139 Interpolators.FAST_OUT_SLOW_IN, null);
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002140 }
2141 });
2142 }
2143
2144 @Override
Selim Cinek6746c282015-04-21 19:58:31 -07002145 public float getMaxTranslationDistance() {
2146 return (float) Math.hypot(getWidth(), getHeight());
Selim Cinek4c6969a2014-05-26 19:22:17 +02002147 }
2148
2149 @Override
Jorim Jaggid9449862015-05-29 14:49:08 -07002150 public void onSwipingStarted(boolean rightIcon) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002151 mFalsingManager.onAffordanceSwipingStarted(rightIcon);
Jorim Jaggid9449862015-05-29 14:49:08 -07002152 boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon
2153 : rightIcon;
2154 if (camera) {
Jorim Jaggid9449862015-05-29 14:49:08 -07002155 mKeyguardBottomArea.bindCameraPrewarmService();
Jorim Jaggia86790b2015-04-02 16:32:29 -07002156 }
Selim Cinekbaa23272014-07-08 18:01:07 +02002157 requestDisallowInterceptTouchEvent(true);
2158 mOnlyAffordanceInThisMotion = true;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002159 mQsTracking = false;
Selim Cinek4c6969a2014-05-26 19:22:17 +02002160 }
2161
2162 @Override
Jorim Jaggia86790b2015-04-02 16:32:29 -07002163 public void onSwipingAborted() {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002164 mFalsingManager.onAffordanceSwipingAborted();
Jorim Jaggid9449862015-05-29 14:49:08 -07002165 mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
Jorim Jaggia86790b2015-04-02 16:32:29 -07002166 }
2167
2168 @Override
Selim Cinek6746c282015-04-21 19:58:31 -07002169 public void onIconClicked(boolean rightIcon) {
2170 if (mHintAnimationRunning) {
2171 return;
2172 }
2173 mHintAnimationRunning = true;
Adrian Roose31f30e2017-01-25 14:48:15 -08002174 mAffordanceHelper.startHintAnimation(rightIcon, new Runnable() {
Selim Cinek6746c282015-04-21 19:58:31 -07002175 @Override
2176 public void run() {
2177 mHintAnimationRunning = false;
2178 mStatusBar.onHintFinished();
2179 }
2180 });
2181 rightIcon = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon : rightIcon;
2182 if (rightIcon) {
2183 mStatusBar.onCameraHintStarted();
2184 } else {
Selim Cineke70d6532015-04-24 16:46:13 -07002185 if (mKeyguardBottomArea.isLeftVoiceAssist()) {
2186 mStatusBar.onVoiceAssistHintStarted();
2187 } else {
2188 mStatusBar.onPhoneHintStarted();
2189 }
Selim Cinek6746c282015-04-21 19:58:31 -07002190 }
2191 }
2192
2193 @Override
Selim Cinekec29d342017-05-05 18:31:49 -07002194 protected void onUnlockHintFinished() {
2195 super.onUnlockHintFinished();
2196 mNotificationStackScroller.setUnlockHintRunning(false);
2197 }
2198
2199 @Override
2200 protected void onUnlockHintStarted() {
2201 super.onUnlockHintStarted();
2202 mNotificationStackScroller.setUnlockHintRunning(true);
2203 }
2204
2205 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002206 public KeyguardAffordanceView getLeftIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002207 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002208 ? mKeyguardBottomArea.getRightView()
2209 : mKeyguardBottomArea.getLeftView();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002210 }
2211
2212 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002213 public KeyguardAffordanceView getCenterIcon() {
Selim Cinek4c6969a2014-05-26 19:22:17 +02002214 return mKeyguardBottomArea.getLockIcon();
2215 }
2216
2217 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002218 public KeyguardAffordanceView getRightIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002219 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002220 ? mKeyguardBottomArea.getLeftView()
2221 : mKeyguardBottomArea.getRightView();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002222 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002223
2224 @Override
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02002225 public View getLeftPreview() {
2226 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002227 ? mKeyguardBottomArea.getRightPreview()
2228 : mKeyguardBottomArea.getLeftPreview();
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02002229 }
2230
2231 @Override
2232 public View getRightPreview() {
2233 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002234 ? mKeyguardBottomArea.getLeftPreview()
2235 : mKeyguardBottomArea.getRightPreview();
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02002236 }
2237
2238 @Override
Selim Cinek34cf5c42014-09-26 15:39:00 +02002239 public float getAffordanceFalsingFactor() {
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07002240 return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
Selim Cinek34cf5c42014-09-26 15:39:00 +02002241 }
2242
2243 @Override
Adrian Roos6a70b882016-04-19 17:09:07 -07002244 public boolean needsAntiFalsing() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002245 return mBarState == StatusBarState.KEYGUARD;
Adrian Roos6a70b882016-04-19 17:09:07 -07002246 }
2247
2248 @Override
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002249 protected float getPeekHeight() {
2250 if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
2251 return mNotificationStackScroller.getPeekHeight();
2252 } else {
Selim Cinek94c2d822016-07-13 18:50:04 -07002253 return mQsMinExpansionHeight;
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002254 }
2255 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002256
2257 @Override
Selim Cinek2411f762016-12-28 17:05:08 +01002258 protected boolean shouldUseDismissingAnimation() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002259 return mBarState != StatusBarState.SHADE
Selim Cinekdf5501b2017-04-14 20:01:27 -07002260 && (!mStatusBar.isKeyguardCurrentlySecure() || !isTracking());
Selim Cinek2411f762016-12-28 17:05:08 +01002261 }
2262
2263 @Override
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002264 protected boolean fullyExpandedClearAllVisible() {
Julia Reynoldsed1c9af2018-03-21 15:21:09 -04002265 return mNotificationStackScroller.isFooterViewNotGone()
Jason Monk3c68ca22015-01-30 11:30:29 -05002266 && mNotificationStackScroller.isScrolledToBottom() && !mQsExpandImmediate;
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002267 }
2268
2269 @Override
2270 protected boolean isClearAllVisible() {
Selim Cinek38475442018-05-18 11:11:46 -07002271 return mNotificationStackScroller.isFooterViewContentVisible();
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002272 }
2273
2274 @Override
2275 protected int getClearAllHeight() {
Julia Reynoldsed1c9af2018-03-21 15:21:09 -04002276 return mNotificationStackScroller.getFooterViewHeight();
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002277 }
2278
2279 @Override
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002280 protected boolean isTrackingBlocked() {
2281 return mConflictingQsExpansionGesture && mQsExpanded;
2282 }
Jorim Jaggi54045422014-07-03 18:30:40 +02002283
Jorim Jaggibd003102014-07-04 00:02:42 +02002284 public boolean isQsExpanded() {
2285 return mQsExpanded;
2286 }
Jorim Jaggi853b0702014-07-05 04:31:14 +02002287
John Spurlockf7ae4422014-08-01 12:45:18 -04002288 public boolean isQsDetailShowing() {
Jason Monk0ceef212016-11-02 14:05:23 -04002289 return mQs.isShowingDetail();
John Spurlockf7ae4422014-08-01 12:45:18 -04002290 }
2291
2292 public void closeQsDetail() {
Jason Monk0ceef212016-11-02 14:05:23 -04002293 mQs.closeDetail();
John Spurlockf7ae4422014-08-01 12:45:18 -04002294 }
2295
Jorim Jaggi853b0702014-07-05 04:31:14 +02002296 @Override
2297 public boolean shouldDelayChildPressedState() {
2298 return true;
2299 }
Selim Cinekbaa23272014-07-08 18:01:07 +02002300
2301 public boolean isLaunchTransitionFinished() {
2302 return mIsLaunchTransitionFinished;
2303 }
2304
2305 public boolean isLaunchTransitionRunning() {
2306 return mIsLaunchTransitionRunning;
2307 }
2308
2309 public void setLaunchTransitionEndRunnable(Runnable r) {
2310 mLaunchAnimationEndRunnable = r;
2311 }
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02002312
2313 public void setEmptyDragAmount(float amount) {
Selim Cinek5386fb32014-09-03 16:37:36 +02002314 float factor = 0.8f;
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02002315 if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
Selim Cinek5386fb32014-09-03 16:37:36 +02002316 factor = 0.4f;
Christoph Studerc8db24b2014-07-25 17:50:30 +02002317 } else if (!mStatusBar.hasActiveNotifications()) {
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02002318 factor = 0.4f;
2319 }
2320 mEmptyDragAmount = amount * factor;
2321 positionClockAndNotifications();
2322 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002323
2324 private static float interpolate(float t, float start, float end) {
2325 return (1 - t) * start + t * end;
2326 }
John Spurlockd54da8a2014-08-03 23:23:52 -04002327
Jorim Jaggi0e0942d2015-06-05 14:12:20 -07002328 private void updateDozingVisibilities(boolean animate) {
John Spurlockd54da8a2014-08-03 23:23:52 -04002329 if (mDozing) {
Jorim Jaggi16423aa2014-10-28 11:42:58 +01002330 mKeyguardStatusBar.setVisibility(View.INVISIBLE);
Adrian Roos91ba3072017-02-14 16:50:46 +01002331 mKeyguardBottomArea.setDozing(mDozing, animate);
John Spurlockd54da8a2014-08-03 23:23:52 -04002332 } else {
Jorim Jaggi16423aa2014-10-28 11:42:58 +01002333 mKeyguardStatusBar.setVisibility(View.VISIBLE);
Adrian Roos91ba3072017-02-14 16:50:46 +01002334 mKeyguardBottomArea.setDozing(mDozing, animate);
Jorim Jaggi16423aa2014-10-28 11:42:58 +01002335 if (animate) {
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002336 animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION);
Jorim Jaggi16423aa2014-10-28 11:42:58 +01002337 }
John Spurlockd54da8a2014-08-03 23:23:52 -04002338 }
John Spurlockd54da8a2014-08-03 23:23:52 -04002339 }
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002340
Jorim Jaggid7912d22014-09-30 17:38:19 +02002341 @Override
John Spurlockcf5d3c92014-09-21 17:55:01 -04002342 public boolean isDozing() {
2343 return mDozing;
2344 }
2345
Selim Cinek24176c32017-03-01 16:50:30 -08002346 public void showEmptyShadeView(boolean emptyShadeViewVisible) {
2347 mShowEmptyShadeView = emptyShadeViewVisible;
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002348 updateEmptyShadeView();
2349 }
2350
2351 private void updateEmptyShadeView() {
Julia Reynolds34f14962018-05-03 12:40:20 +00002352
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002353 // Hide "No notifications" in QS.
Selim Cinek24176c32017-03-01 16:50:30 -08002354 mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002355 }
Jorim Jaggidd5b8862014-08-05 21:04:39 +02002356
2357 public void setQsScrimEnabled(boolean qsScrimEnabled) {
2358 boolean changed = mQsScrimEnabled != qsScrimEnabled;
2359 mQsScrimEnabled = qsScrimEnabled;
2360 if (changed) {
2361 updateQsState();
2362 }
2363 }
John Spurlock7e6809a2014-08-06 16:03:14 -04002364
Jorim Jaggibf1899e2014-08-07 02:04:18 +02002365 public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
2366 mKeyguardUserSwitcher = keyguardUserSwitcher;
2367 }
2368
Jorim Jaggi93739112015-08-13 15:53:14 -07002369 public void onScreenTurningOn() {
Lucas Dupin9fedb892018-05-04 17:42:33 -07002370 mKeyguardStatusView.dozeTimeTick();
Jorim Jaggid09def7512014-09-02 18:36:45 +02002371 }
Selim Cinek3a9c10a2014-10-28 14:21:10 +01002372
2373 @Override
2374 public void onEmptySpaceClicked(float x, float y) {
2375 onEmptySpaceClick(x);
2376 }
Jorim Jaggi58bef332014-11-21 18:10:32 +01002377
Jim Miller07e03842016-06-22 15:18:13 -07002378 @Override
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002379 protected boolean onMiddleClicked() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002380 switch (mBarState) {
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002381 case StatusBarState.KEYGUARD:
2382 if (!mDozingOnDown) {
Chris Wren27a52fa2017-02-01 14:21:43 -05002383 mLockscreenGestureLogger.write(
2384 MetricsEvent.ACTION_LS_HINT,
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002385 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
2386 startUnlockHintAnimation();
2387 }
2388 return true;
2389 case StatusBarState.SHADE_LOCKED:
2390 if (!mQsExpanded) {
2391 mStatusBar.goToKeyguard();
2392 }
2393 return true;
2394 case StatusBarState.SHADE:
2395
2396 // This gets called in the middle of the touch handling, where the state is still
2397 // that we are tracking the panel. Collapse the panel after this is done.
2398 post(mPostCollapseRunnable);
2399 return false;
2400 default:
2401 return true;
2402 }
2403 }
2404
Jorim Jaggi58bef332014-11-21 18:10:32 +01002405 @Override
shawnlin4ef7ca52018-05-11 16:44:42 +08002406 protected void dispatchDraw(Canvas canvas) {
2407 super.dispatchDraw(canvas);
2408 if (mCurrentPanelAlpha != 255) {
2409 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
2410 }
2411 }
2412
2413 public float getCurrentPanelAlpha() {
2414 return mCurrentPanelAlpha;
2415 }
2416
2417 public boolean setPanelAlpha(int alpha, boolean animate) {
2418 if (mPanelAlpha != alpha) {
2419 mPanelAlpha = alpha;
2420 PropertyAnimator.setProperty(this, PANEL_ALPHA, alpha,
2421 alpha == 255 ? PANEL_ALPHA_IN_PROPERTIES : PANEL_ALPHA_OUT_PROPERTIES, animate);
2422 return true;
2423 }
2424 return false;
2425 }
2426
2427 public void setPanelAlphaInternal(float alpha) {
2428 mCurrentPanelAlpha = (int) alpha;
2429 mAlphaPaint.setARGB(mCurrentPanelAlpha, 255, 255, 255);
2430 invalidate();
2431 }
2432
2433 public void setPanelAlphaEndAction(Runnable r) {
2434 mPanelAlphaEndAction = r;
2435 }
2436
2437 @Override
Lucas Dupin41ff6952018-02-18 19:39:32 -08002438 protected void onDraw(Canvas canvas) {
2439 super.onDraw(canvas);
2440
Jorim Jaggi58bef332014-11-21 18:10:32 +01002441 if (DEBUG) {
2442 Paint p = new Paint();
2443 p.setColor(Color.RED);
2444 p.setStrokeWidth(2);
2445 p.setStyle(Paint.Style.STROKE);
2446 canvas.drawLine(0, getMaxPanelHeight(), getWidth(), getMaxPanelHeight(), p);
2447 p.setColor(Color.BLUE);
2448 canvas.drawLine(0, getExpandedHeight(), getWidth(), getExpandedHeight(), p);
2449 p.setColor(Color.GREEN);
2450 canvas.drawLine(0, calculatePanelHeightQsExpanded(), getWidth(),
2451 calculatePanelHeightQsExpanded(), p);
2452 p.setColor(Color.YELLOW);
2453 canvas.drawLine(0, calculatePanelHeightShade(), getWidth(),
2454 calculatePanelHeightShade(), p);
2455 p.setColor(Color.MAGENTA);
2456 canvas.drawLine(0, calculateQsTopPadding(), getWidth(),
2457 calculateQsTopPadding(), p);
2458 p.setColor(Color.CYAN);
Lucas Dupin60661a62018-04-12 10:50:13 -07002459 canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, getWidth(),
Jorim Jaggi58bef332014-11-21 18:10:32 +01002460 mNotificationStackScroller.getTopPadding(), p);
Lucas Dupin60661a62018-04-12 10:50:13 -07002461 p.setColor(Color.GRAY);
2462 canvas.drawLine(0, mClockPositionResult.clockY, getWidth(),
2463 mClockPositionResult.clockY, p);
Jorim Jaggi58bef332014-11-21 18:10:32 +01002464 }
2465 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002466
2467 @Override
John Spurlockb349af572015-04-29 12:24:19 -04002468 public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07002469 mNotificationStackScroller.setInHeadsUpPinnedMode(inPinnedMode);
Selim Cinek684a4422015-04-15 16:18:39 -07002470 if (inPinnedMode) {
2471 mHeadsUpExistenceChangedRunnable.run();
2472 updateNotificationTranslucency();
2473 } else {
Selim Cinekcafa87f2016-10-26 17:00:17 -07002474 setHeadsUpAnimatingAway(true);
Selim Cinek684a4422015-04-15 16:18:39 -07002475 mNotificationStackScroller.runAfterAnimationFinished(
2476 mHeadsUpExistenceChangedRunnable);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002477 }
2478 }
2479
Selim Cinekcafa87f2016-10-26 17:00:17 -07002480 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
2481 mHeadsUpAnimatingAway = headsUpAnimatingAway;
2482 mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway);
2483 }
2484
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002485 @Override
Selim Cinek684a4422015-04-15 16:18:39 -07002486 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
2487 mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
Selim Cinek1f3f5442015-04-10 17:54:46 -07002488 }
2489
2490 @Override
Selim Cinek684a4422015-04-15 16:18:39 -07002491 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
Selim Cineka303a642018-03-08 21:24:55 -08002492
2493 // When we're unpinning the notification via active edge they remain heads-upped,
2494 // we need to make sure that an animation happens in this case, otherwise the notification
2495 // will stick to the top without any interaction.
2496 if (isFullyCollapsed() && headsUp.isHeadsUp()) {
2497 mNotificationStackScroller.generateHeadsUpAnimation(headsUp, false);
2498 headsUp.setHeadsUpIsVisible();
2499 }
Selim Cinek684a4422015-04-15 16:18:39 -07002500 }
2501
2502 @Override
2503 public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002504 mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002505 }
2506
Selim Cineka59ecc32015-04-07 10:51:49 -07002507 @Override
yoshiki iguchi4e30e762018-02-06 12:09:23 +09002508 public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002509 super.setHeadsUpManager(headsUpManager);
Selim Cinek684a4422015-04-15 16:18:39 -07002510 mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller,
2511 this);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002512 }
2513
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002514 public void setTrackedHeadsUp(ExpandableNotificationRow pickedChild) {
2515 if (pickedChild != null) {
2516 notifyListenersTrackingHeadsUp(pickedChild);
Selim Cinekd2281152015-04-10 14:37:46 -07002517 mExpandingFromHeadsUp = true;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002518 }
Selim Cinek684a4422015-04-15 16:18:39 -07002519 // otherwise we update the state when the expansion is finished
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002520 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002521
2522 @Override
2523 protected void onClosingFinished() {
2524 super.onClosingFinished();
2525 resetVerticalPanelPosition();
Selim Cinekbbc580b2015-06-03 14:11:03 +02002526 setClosingWithAlphaFadeout(false);
2527 }
2528
2529 private void setClosingWithAlphaFadeout(boolean closing) {
2530 mClosingWithAlphaFadeOut = closing;
2531 mNotificationStackScroller.forceNoOverlappingRendering(closing);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002532 }
2533
2534 /**
2535 * Updates the vertical position of the panel so it is positioned closer to the touch
2536 * responsible for opening the panel.
2537 *
2538 * @param x the x-coordinate the touch event
2539 */
Xiaohui Chen9528f432016-02-12 15:03:18 -08002540 protected void updateVerticalPanelPosition(float x) {
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002541 if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
2542 resetVerticalPanelPosition();
2543 return;
2544 }
2545 float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2;
2546 float rightMost = getWidth() - mPositionMinSideMargin
2547 - mNotificationStackScroller.getWidth() / 2;
2548 if (Math.abs(x - getWidth() / 2) < mNotificationStackScroller.getWidth() / 4) {
2549 x = getWidth() / 2;
2550 }
2551 x = Math.min(rightMost, Math.max(leftMost, x));
2552 setVerticalPanelTranslation(x -
Selim Cinek3d395c62015-06-16 19:37:37 -07002553 (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2));
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002554 }
2555
2556 private void resetVerticalPanelPosition() {
2557 setVerticalPanelTranslation(0f);
2558 }
2559
Xiaohui Chenf43491f2016-02-01 12:19:35 -08002560 protected void setVerticalPanelTranslation(float translation) {
Bill Line60aa1e2018-06-13 18:07:15 +08002561 mNotificationStackScroller.setVerticalPanelTranslation(translation);
Jason Monk0ceef212016-11-02 14:05:23 -04002562 mQsFrame.setTranslationX(translation);
Selim Cinek60ffea62018-03-22 13:16:44 -07002563 int size = mVerticalTranslationListener.size();
2564 for (int i = 0; i < size; i++) {
2565 mVerticalTranslationListener.get(i).run();
Selim Cinek332c23f2018-03-16 17:37:50 -07002566 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002567 }
Xiyuan Xiab3a6f1e2015-04-28 16:17:18 -07002568
Selim Cinekbc243a92016-09-27 16:35:13 -07002569 protected void updateExpandedHeight(float expandedHeight) {
Selim Cinekd5ab6452016-12-08 16:34:00 -08002570 if (mTracking) {
2571 mNotificationStackScroller.setExpandingVelocity(getCurrentExpandVelocity());
2572 }
Selim Cinekbc243a92016-09-27 16:35:13 -07002573 mNotificationStackScroller.setExpandedHeight(expandedHeight);
Xiyuan Xiab3a6f1e2015-04-28 16:17:18 -07002574 updateKeyguardBottomAreaAlpha();
Selim Cinek24176c32017-03-01 16:50:30 -08002575 updateStatusBarIcons();
Selim Cinekfcff4c62016-12-27 14:26:06 +01002576 }
2577
2578 /**
2579 * @return whether the notifications are displayed full width and don't have any margins on
2580 * the side.
2581 */
2582 public boolean isFullWidth() {
2583 return mIsFullWidth;
Selim Cinek48ff9b42016-11-09 19:31:51 -08002584 }
2585
Selim Cinek24176c32017-03-01 16:50:30 -08002586 private void updateStatusBarIcons() {
felkachangca4eee82018-06-29 15:34:28 +08002587 boolean showIconsWhenExpanded = (isPanelVisibleBecauseOfHeadsUp() || isFullWidth())
2588 && getExpandedHeight() < getOpeningHeight();
Selim Cinek24176c32017-03-01 16:50:30 -08002589 if (showIconsWhenExpanded && mNoVisibleNotifications && isOnKeyguard()) {
2590 showIconsWhenExpanded = false;
2591 }
2592 if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
2593 mShowIconsWhenExpanded = showIconsWhenExpanded;
Selim Cinek48ff9b42016-11-09 19:31:51 -08002594 mStatusBar.recomputeDisableFlags(false);
2595 }
Xiyuan Xiab3a6f1e2015-04-28 16:17:18 -07002596 }
Selim Cinek3d395c62015-06-16 19:37:37 -07002597
Selim Cinek24176c32017-03-01 16:50:30 -08002598 private boolean isOnKeyguard() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002599 return mBarState == StatusBarState.KEYGUARD;
Selim Cinek24176c32017-03-01 16:50:30 -08002600 }
2601
Selim Cinek3d395c62015-06-16 19:37:37 -07002602 public void setPanelScrimMinFraction(float minFraction) {
2603 mBar.panelScrimMinFractionChanged(minFraction);
2604 }
Chris Wren16895942015-06-23 11:22:20 -04002605
Xiaohui Chen9528f432016-02-12 15:03:18 -08002606 public void clearNotificationEffects() {
Chris Wren16895942015-06-23 11:22:20 -04002607 mStatusBar.clearNotificationEffects();
2608 }
Selim Cinek0fccc722015-07-29 17:04:36 -07002609
Jim Miller07e03842016-06-22 15:18:13 -07002610 @Override
Selim Cinek0fccc722015-07-29 17:04:36 -07002611 protected boolean isPanelVisibleBecauseOfHeadsUp() {
2612 return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
2613 }
Jorim Jaggi90978852015-08-18 19:55:53 -07002614
2615 @Override
2616 public boolean hasOverlappingRendering() {
2617 return !mDozing;
2618 }
Selim Cinek372d1bd2015-08-14 13:19:37 -07002619
Jorim Jaggi40aa8812015-09-23 12:59:22 -07002620 public void launchCamera(boolean animate, int source) {
2621 if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
2622 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
2623 } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
2624 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
Jonathan Solnita4138162017-05-10 21:06:04 -07002625 } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER) {
2626 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER;
Jorim Jaggi40aa8812015-09-23 12:59:22 -07002627 } else {
2628
2629 // Default.
2630 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
2631 }
2632
Selim Cinek372d1bd2015-08-14 13:19:37 -07002633 // If we are launching it when we are occluded already we don't want it to animate,
2634 // nor setting these flags, since the occluded state doesn't change anymore, hence it's
2635 // never reset.
2636 if (!isFullyCollapsed()) {
2637 mLaunchingAffordance = true;
2638 setLaunchingAffordance(true);
2639 } else {
2640 animate = false;
2641 }
Lucas Dupin193677c2018-06-11 19:16:03 -07002642 mAffordanceHasPreview = mKeyguardBottomArea.getRightPreview() != null;
Adrian Roose31f30e2017-01-25 14:48:15 -08002643 mAffordanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
Selim Cinek372d1bd2015-08-14 13:19:37 -07002644 }
2645
2646 public void onAffordanceLaunchEnded() {
2647 mLaunchingAffordance = false;
2648 setLaunchingAffordance(false);
2649 }
2650
Selim Cinek07304f5222016-05-19 18:31:36 -07002651 @Override
2652 public void setAlpha(float alpha) {
2653 super.setAlpha(alpha);
Adrian Roos88e61aa2017-05-23 16:16:50 -07002654 updateFullyVisibleState(false /* forceNotFullyVisible */);
2655 }
2656
2657 /**
2658 * Must be called before starting a ViewPropertyAnimator alpha animation because those
2659 * do NOT call setAlpha and therefore don't properly update the fullyVisibleState.
2660 */
2661 public void notifyStartFading() {
2662 updateFullyVisibleState(true /* forceNotFullyVisible */);
Selim Cinek48ff9b42016-11-09 19:31:51 -08002663 }
2664
2665 @Override
2666 public void setVisibility(int visibility) {
2667 super.setVisibility(visibility);
Adrian Roos88e61aa2017-05-23 16:16:50 -07002668 updateFullyVisibleState(false /* forceNotFullyVisible */);
Selim Cinek48ff9b42016-11-09 19:31:51 -08002669 }
2670
Adrian Roos88e61aa2017-05-23 16:16:50 -07002671 private void updateFullyVisibleState(boolean forceNotFullyVisible) {
2672 mNotificationStackScroller.setParentNotFullyVisible(forceNotFullyVisible
2673 || getAlpha() != 1.0f
Selim Cinek48ff9b42016-11-09 19:31:51 -08002674 || getVisibility() != VISIBLE);
Selim Cinek07304f5222016-05-19 18:31:36 -07002675 }
2676
Selim Cinek372d1bd2015-08-14 13:19:37 -07002677 /**
2678 * Set whether we are currently launching an affordance. This is currently only set when
2679 * launched via a camera gesture.
2680 */
2681 private void setLaunchingAffordance(boolean launchingAffordance) {
2682 getLeftIcon().setLaunchingAffordance(launchingAffordance);
2683 getRightIcon().setLaunchingAffordance(launchingAffordance);
2684 getCenterIcon().setLaunchingAffordance(launchingAffordance);
2685 }
2686
Zhentao Sun04f97402015-08-26 17:37:30 -07002687 /**
Lucas Dupin193677c2018-06-11 19:16:03 -07002688 * Return true when a bottom affordance is launching an occluded activity with a splash screen.
2689 */
2690 public boolean isLaunchingAffordanceWithPreview() {
2691 return mLaunchingAffordance && mAffordanceHasPreview;
2692 }
2693
2694 /**
Zhentao Sun04f97402015-08-26 17:37:30 -07002695 * Whether the camera application can be launched for the camera launch gesture.
2696 *
2697 * @param keyguardIsShowing whether keyguard is being shown
2698 */
2699 public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
Esteban Talavera40f8b992017-07-14 16:14:07 +01002700 if (!mStatusBar.isCameraAllowedByAdmin()) {
2701 return false;
2702 }
2703
Zhentao Sun04f97402015-08-26 17:37:30 -07002704 ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
2705 String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
2706 ? null : resolveInfo.activityInfo.packageName;
2707 return packageToLaunch != null &&
2708 (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
Adrian Roose31f30e2017-01-25 14:48:15 -08002709 !mAffordanceHelper.isSwipingInProgress();
Zhentao Sun04f97402015-08-26 17:37:30 -07002710 }
2711
2712 /**
2713 * Return true if the applications with the package name is running in foreground.
2714 *
2715 * @param pkgName application package name.
2716 */
2717 private boolean isForegroundApp(String pkgName) {
2718 ActivityManager am = getContext().getSystemService(ActivityManager.class);
2719 List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
2720 return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
Selim Cinek372d1bd2015-08-14 13:19:37 -07002721 }
Selim Cinek53f8e7d2016-03-25 02:28:01 -07002722
2723 public void setGroupManager(NotificationGroupManager groupManager) {
2724 mGroupManager = groupManager;
2725 }
Jason Monk0ceef212016-11-02 14:05:23 -04002726
Selim Cinek24176c32017-03-01 16:50:30 -08002727 public boolean hideStatusBarIconsWhenExpanded() {
Selim Cinek2627d722018-01-19 12:16:49 -08002728 if (mLaunchingNotification) {
2729 return mHideIconsDuringNotificationLaunch;
2730 }
Selim Cinek332c23f2018-03-16 17:37:50 -07002731 if (mHeadsUpAppearanceController != null
2732 && mHeadsUpAppearanceController.shouldBeVisible()) {
2733 return false;
2734 }
Selim Cinek24176c32017-03-01 16:50:30 -08002735 return !isFullWidth() || !mShowIconsWhenExpanded;
Selim Cinek48ff9b42016-11-09 19:31:51 -08002736 }
2737
Jason Monk0ceef212016-11-02 14:05:23 -04002738 private final FragmentListener mFragmentListener = new FragmentListener() {
2739 @Override
2740 public void onFragmentViewCreated(String tag, Fragment fragment) {
2741 mQs = (QS) fragment;
2742 mQs.setPanelView(NotificationPanelView.this);
Jason Monke5b770e2017-03-03 21:49:29 -05002743 mQs.setExpandClickListener(NotificationPanelView.this);
Jason Monk0ceef212016-11-02 14:05:23 -04002744 mQs.setHeaderClickable(mQsExpansionEnabled);
2745 mQs.setKeyguardShowing(mKeyguardShowing);
2746 mQs.setOverscrolling(mStackScrollerOverscrolling);
2747
2748 // recompute internal state when qspanel height changes
2749 mQs.getView().addOnLayoutChangeListener(
2750 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
2751 final int height = bottom - top;
2752 final int oldHeight = oldBottom - oldTop;
2753 if (height != oldHeight) {
2754 onQsHeightChanged();
2755 }
2756 });
2757 mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
2758 updateQsExpansion();
2759 }
2760
2761 @Override
2762 public void onFragmentViewDestroyed(String tag, Fragment fragment) {
2763 // Manual handling of fragment lifecycle is only required because this bridges
2764 // non-fragment and fragment code. Once we are using a fragment for the notification
2765 // panel, mQs will not need to be null cause it will be tied to the same lifecycle.
2766 if (fragment == mQs) {
2767 mQs = null;
2768 }
2769 }
2770 };
Adrian Roosc934c432017-01-13 11:44:56 -08002771
Selim Cinek2c2f0e22017-05-02 20:02:30 -07002772 @Override
2773 public void setTouchDisabled(boolean disabled) {
2774 super.setTouchDisabled(disabled);
2775 if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
Selim Cinekc5fec9a2017-07-05 16:22:53 +02002776 mAffordanceHelper.reset(false /* animate */);
Selim Cinek2c2f0e22017-05-02 20:02:30 -07002777 }
2778 }
2779
Lucas Dupin16cfe452018-02-08 13:14:50 -08002780 public void setDozing(boolean dozing, boolean animate) {
2781 if (dozing == mDozing) return;
2782 mDozing = dozing;
2783
Jason Monk1fd3fc32018-08-14 17:20:09 -04002784 if (mBarState == StatusBarState.KEYGUARD
2785 || mBarState == StatusBarState.SHADE_LOCKED) {
Lucas Dupin16cfe452018-02-08 13:14:50 -08002786 updateDozingVisibilities(animate);
Adrian Roos52414e32017-04-28 09:23:19 -07002787 }
Lucas Dupin16cfe452018-02-08 13:14:50 -08002788
2789 final float darkAmount = dozing ? 1 : 0;
Adrian Roos52414e32017-04-28 09:23:19 -07002790 if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
Adrian Roos51465ea2017-07-27 13:57:35 +02002791 if (animate && mDarkAmountTarget == darkAmount) {
2792 return;
2793 } else {
2794 mDarkAnimator.cancel();
2795 }
Adrian Roos52414e32017-04-28 09:23:19 -07002796 }
Adrian Roos51465ea2017-07-27 13:57:35 +02002797 mDarkAmountTarget = darkAmount;
Adrian Roos52414e32017-04-28 09:23:19 -07002798 if (animate) {
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002799 if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) {
2800 mDarkInterpolator = dozing
2801 ? Interpolators.FAST_OUT_SLOW_IN
2802 : Interpolators.TOUCH_RESPONSE_REVERSE;
2803 }
2804 mNotificationStackScroller.notifyDarkAnimationStart(dozing);
Adrian Roos52414e32017-04-28 09:23:19 -07002805 mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount);
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002806 mDarkAnimator.setInterpolator(Interpolators.LINEAR);
2807 mDarkAnimator.setDuration(mNotificationStackScroller.getDarkAnimationDuration(dozing));
Adrian Roos52414e32017-04-28 09:23:19 -07002808 mDarkAnimator.start();
2809 } else {
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002810 setDarkAmount(darkAmount, darkAmount);
Adrian Roos52414e32017-04-28 09:23:19 -07002811 }
2812 }
2813
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002814 private void setDarkAmount(float linearAmount, float amount) {
2815 mInterpolatedDarkAmount = amount;
2816 mLinearDarkAmount = linearAmount;
2817 mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount);
2818 mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
Adrian Roosc934c432017-01-13 11:44:56 -08002819 positionClockAndNotifications();
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002820 mNotificationStackScroller.setDarkAmount(linearAmount, mInterpolatedDarkAmount);
Adrian Roosc934c432017-01-13 11:44:56 -08002821 }
Selim Cinek24176c32017-03-01 16:50:30 -08002822
yoshiki iguchi4e30e762018-02-06 12:09:23 +09002823 public void setPulsing(boolean pulsing) {
Lucas Dupin56057342018-04-10 11:49:18 -07002824 mPulsing = pulsing;
Lucas Dupin2a6bdfd2018-06-12 17:45:21 -07002825 DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
2826 final boolean animatePulse = !dozeParameters.getDisplayNeedsBlanking()
2827 && dozeParameters.getAlwaysOn();
2828 if (animatePulse) {
Lucas Dupin3d7ccaf2018-04-02 21:19:23 -07002829 mAnimateNextPositionUpdate = true;
2830 }
Lucas Dupin2a6bdfd2018-06-12 17:45:21 -07002831 mNotificationStackScroller.setPulsing(pulsing, animatePulse);
2832 mKeyguardStatusView.setPulsing(pulsing, animatePulse);
Adrian Roosd83e9992017-03-16 15:17:57 -07002833 }
Adrian Roos75fa9642017-04-18 11:34:56 -07002834
2835 public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
2836 if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
2837 mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
2838 mStatusBar.updateKeyguardMaxNotifications();
2839 }
2840 }
Lucas Dupin987f1932017-05-13 21:02:52 -07002841
Lucas Dupin4272f442018-01-13 22:00:35 -08002842 public void dozeTimeTick() {
Lucas Dupin9fedb892018-05-04 17:42:33 -07002843 mKeyguardStatusView.dozeTimeTick();
Lucas Dupin4272f442018-01-13 22:00:35 -08002844 mKeyguardBottomArea.dozeTimeTick();
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002845 if (mInterpolatedDarkAmount > 0) {
Adrian Roos4fc6de82017-06-01 16:09:15 -07002846 positionClockAndNotifications();
2847 }
Lucas Dupin987f1932017-05-13 21:02:52 -07002848 }
2849
2850 public void setStatusAccessibilityImportance(int mode) {
2851 mKeyguardStatusView.setImportantForAccessibility(mode);
2852 }
2853
2854 /**
2855 * TODO: this should be removed.
2856 * It's not correct to pass this view forward because other classes will end up adding
2857 * children to it. Theme will be out of sync.
2858 * @return bottom area view
2859 */
2860 public KeyguardBottomAreaView getKeyguardBottomAreaView() {
2861 return mKeyguardBottomArea;
2862 }
2863
2864 public void setUserSetupComplete(boolean userSetupComplete) {
2865 mUserSetupComplete = userSetupComplete;
2866 mKeyguardBottomArea.setUserSetupComplete(userSetupComplete);
2867 }
2868
2869 public LockIcon getLockIcon() {
2870 return mKeyguardBottomArea.getLockIcon();
2871 }
Selim Cinek2627d722018-01-19 12:16:49 -08002872
2873 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
2874 mExpandOffset = params != null ? params.getTopChange() : 0;
2875 updateQsExpansion();
2876 if (params != null) {
2877 boolean hideIcons = params.getProgress(
2878 ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
2879 if (hideIcons != mHideIconsDuringNotificationLaunch) {
2880 mHideIconsDuringNotificationLaunch = hideIcons;
2881 if (!hideIcons) {
2882 mStatusBar.recomputeDisableFlags(true /* animate */);
2883 }
2884 }
2885 }
2886 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002887
2888 public void addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) {
2889 mTrackingHeadsUpListeners.add(listener);
2890 }
Selim Cinek332c23f2018-03-16 17:37:50 -07002891
Selim Cinek60ffea62018-03-22 13:16:44 -07002892 public void removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) {
2893 mTrackingHeadsUpListeners.remove(listener);
2894 }
2895
2896 public void addVerticalTranslationListener(Runnable verticalTranslationListener) {
2897 mVerticalTranslationListener.add(verticalTranslationListener);
2898 }
2899
2900 public void removeVerticalTranslationListener(Runnable verticalTranslationListener) {
2901 mVerticalTranslationListener.remove(verticalTranslationListener);
Selim Cinek332c23f2018-03-16 17:37:50 -07002902 }
2903
2904 public void setHeadsUpAppearanceController(
2905 HeadsUpAppearanceController headsUpAppearanceController) {
2906 mHeadsUpAppearanceController = headsUpAppearanceController;
2907 }
Lucas Dupin93752552018-03-19 21:32:19 -07002908
2909 /**
2910 * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
2911 * security view of the bouncer.
2912 */
2913 public void onBouncerPreHideAnimation() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002914 setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */,
Lucas Dupin93752552018-03-19 21:32:19 -07002915 false /* goingToFullShade */);
2916 }
Lucas Dupinc510d412018-06-12 13:08:23 -07002917
2918 @Override
2919 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2920 super.dump(fd, pw, args);
2921 if (mKeyguardStatusBar != null) {
2922 mKeyguardStatusBar.dump(fd, pw, args);
2923 }
2924 }
Daniel Sandler08d05e32012-08-08 16:39:54 -04002925}