blob: 467df375e7eb2c1a8d7b95fc9ccc135b7385a4e7 [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 Monk297c04e2018-08-23 17:16:59 -040019import static com.android.systemui.SysUiServiceProvider.getComponent;
Beverly8fdb5332019-02-04 14:29:49 -050020import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
Ned Burns61269442019-05-02 18:27:23 -040021import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
Selim Cinek3d6ae232019-01-04 14:14:33 -080022import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
Selim Cinek2627d722018-01-19 12:16:49 -080023
Jorim Jaggid7daab72014-05-06 22:22:20 +020024import android.animation.Animator;
25import android.animation.AnimatorListenerAdapter;
26import android.animation.ValueAnimator;
Zhentao Sun04f97402015-08-26 17:37:30 -070027import android.app.ActivityManager;
Jason Monk0ceef212016-11-02 14:05:23 -040028import android.app.Fragment;
Jorim Jaggi40aa8812015-09-23 12:59:22 -070029import android.app.StatusBarManager;
Daniel Sandler08d05e32012-08-08 16:39:54 -040030import android.content.Context;
Zhentao Sun04f97402015-08-26 17:37:30 -070031import android.content.pm.ResolveInfo;
Selim Cinek4c6969a2014-05-26 19:22:17 +020032import android.content.res.Configuration;
Anthony Chen04d1ea72017-04-21 14:30:11 -070033import android.content.res.Resources;
Jorim Jaggi58bef332014-11-21 18:10:32 +010034import android.graphics.Canvas;
35import android.graphics.Color;
36import android.graphics.Paint;
Jason Monke59dc402018-08-16 12:05:01 -040037import android.graphics.PointF;
shawnlin4ef7ca52018-05-11 16:44:42 +080038import android.graphics.PorterDuff;
39import android.graphics.PorterDuffXfermode;
Jorim Jaggi613f55f2015-07-16 15:30:10 -070040import android.graphics.Rect;
Evan Lairde1822fd2019-07-10 15:55:45 -040041import android.graphics.Region;
Lucas Dupin4b75b192019-08-29 14:46:29 -070042import android.hardware.biometrics.BiometricSourceType;
Selim Cineke64f52a2017-08-24 14:48:38 -070043import android.os.PowerManager;
Selim Cinek08bd435a2019-07-26 11:37:14 -070044import android.os.SystemClock;
Fabian Kozynski786974f2019-07-25 12:44:06 -040045import android.provider.DeviceConfig;
Fabian Kozynski2865ab02019-10-11 15:03:59 -040046import android.provider.Settings;
Daniel Sandler08d05e32012-08-08 16:39:54 -040047import android.util.AttributeSet;
Lucas Dupin41ff6952018-02-18 19:39:32 -080048import android.util.Log;
Jorim Jaggi3afddce2014-08-14 20:44:43 +020049import android.util.MathUtils;
Lucas Dupin987f1932017-05-13 21:02:52 -070050import android.view.LayoutInflater;
Daniel Sandler040c2e42012-10-17 00:56:33 -040051import android.view.MotionEvent;
Jorim Jaggid7daab72014-05-06 22:22:20 +020052import android.view.VelocityTracker;
Daniel Sandler13522a22012-09-27 14:46:58 -040053import android.view.View;
Jason Monk0ceef212016-11-02 14:05:23 -040054import android.view.ViewGroup;
Selim Cinekb8f09cf2015-03-16 17:09:28 -070055import android.view.WindowInsets;
Phil Weaver428e3972018-01-18 12:50:05 -080056import android.view.accessibility.AccessibilityManager;
John Spurlock7e6809a2014-08-06 16:03:14 -040057import android.widget.FrameLayout;
Lucas Dupin0cd882f2018-01-30 12:19:49 -080058
Lucas Dupin7fc9dc12019-01-03 09:19:43 -080059import com.android.internal.annotations.VisibleForTesting;
Fabian Kozynski786974f2019-07-25 12:44:06 -040060import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
Chris Wren49f06f52015-05-01 16:12:12 -040061import com.android.internal.logging.MetricsLogger;
Chris Wren27a52fa2017-02-01 14:21:43 -050062import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Robert Snoeberger6a0140a2018-12-20 12:46:17 -050063import com.android.keyguard.KeyguardClockSwitch;
Jorim Jaggid09def7512014-09-02 18:36:45 +020064import com.android.keyguard.KeyguardStatusView;
Robert Snoebergerf4976b32019-06-21 15:40:14 -040065import com.android.keyguard.KeyguardUpdateMonitor;
Lucas Dupin4b75b192019-08-29 14:46:29 -070066import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jorim Jaggi613f55f2015-07-16 15:30:10 -070067import com.android.systemui.DejankUtils;
Jason Monk1fd3fc32018-08-14 17:20:09 -040068import com.android.systemui.Dependency;
Winsonc0d70582016-01-29 10:24:39 -080069import com.android.systemui.Interpolators;
Chet Haase4d179dc2012-08-22 07:14:42 -070070import com.android.systemui.R;
Beverlycc4a62f2019-09-26 14:55:28 -040071import com.android.systemui.doze.DozeLog;
Jason Monk0ceef212016-11-02 14:05:23 -040072import com.android.systemui.fragments.FragmentHostManager;
73import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
Dave Mankoff468d4f62019-05-08 14:56:29 -040074import com.android.systemui.plugins.FalsingManager;
Matt Pietal50c8b502019-08-21 13:03:12 -040075import com.android.systemui.plugins.HomeControlsPlugin;
76import com.android.systemui.plugins.PluginListener;
Jason Monk0ceef212016-11-02 14:05:23 -040077import com.android.systemui.plugins.qs.QS;
Beverly8fdb5332019-02-04 14:29:49 -050078import com.android.systemui.plugins.statusbar.StatusBarStateController;
79import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Lucas Dupin7da4f262018-09-20 13:41:46 -070080import com.android.systemui.qs.QSFragment;
Matt Pietal50c8b502019-08-21 13:03:12 -040081import com.android.systemui.shared.plugins.PluginManager;
Jason Monk297c04e2018-08-23 17:16:59 -040082import com.android.systemui.statusbar.CommandQueue;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +020083import com.android.systemui.statusbar.FlingAnimationUtils;
Daniel Sandler151f00d2012-10-02 22:33:08 -040084import com.android.systemui.statusbar.GestureRecorder;
Selim Cinekbaa23272014-07-08 18:01:07 +020085import com.android.systemui.statusbar.KeyguardAffordanceView;
Lucas Dupin987f1932017-05-13 21:02:52 -070086import com.android.systemui.statusbar.KeyguardIndicationController;
Jason Monk297c04e2018-08-23 17:16:59 -040087import com.android.systemui.statusbar.NotificationLockscreenUserManager;
Anthony Chen9e05d462017-04-07 10:10:21 -070088import com.android.systemui.statusbar.NotificationShelf;
Selim Cinek3d6ae232019-01-04 14:14:33 -080089import com.android.systemui.statusbar.PulseExpansionHandler;
Jason Monke59dc402018-08-16 12:05:01 -040090import com.android.systemui.statusbar.RemoteInputController;
Jorim Jaggiecbab362014-04-23 16:13:15 +020091import com.android.systemui.statusbar.StatusBarState;
Lucas Dupind236ee32019-10-08 15:33:59 -070092import com.android.systemui.statusbar.SysuiStatusBarStateController;
Selim Cinek2627d722018-01-19 12:16:49 -080093import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Lucas Dupin60661a62018-04-12 10:50:13 -070094import com.android.systemui.statusbar.notification.AnimatableProperty;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070095import com.android.systemui.statusbar.notification.DynamicPrivacyController;
Jason Monke59dc402018-08-16 12:05:01 -040096import com.android.systemui.statusbar.notification.NotificationEntryManager;
Selim Cinekd5921a82019-01-29 19:04:08 -080097import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
Lucas Dupin60661a62018-04-12 10:50:13 -070098import com.android.systemui.statusbar.notification.PropertyAnimator;
Ned Burnsf81c4c42019-01-07 14:10:43 -050099import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Jason Monke59dc402018-08-16 12:05:01 -0400100import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400101import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
102import com.android.systemui.statusbar.notification.row.ExpandableView;
Rohan Shah20790b82018-07-02 17:21:04 -0700103import com.android.systemui.statusbar.notification.stack.AnimationProperties;
104import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
105import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
Jason Monke59dc402018-08-16 12:05:01 -0400106import com.android.systemui.statusbar.policy.ConfigurationController;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400107import com.android.systemui.statusbar.policy.KeyguardStateController;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400108import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
109import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
Jason Monke59dc402018-08-16 12:05:01 -0400110import com.android.systemui.statusbar.policy.ZenModeController;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400111import com.android.systemui.util.InjectionInflationController;
Matt Pietal5a19cb62019-10-30 12:31:07 -0400112import com.android.systemui.util.Utils;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400113
Lucas Dupinc510d412018-06-12 13:08:23 -0700114import java.io.FileDescriptor;
115import java.io.PrintWriter;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800116import java.util.ArrayList;
Winson Chung9cd21152019-05-28 15:04:08 -0700117import java.util.Collections;
Zhentao Sun04f97402015-08-26 17:37:30 -0700118import java.util.List;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800119import java.util.function.Consumer;
Zhentao Sun04f97402015-08-26 17:37:30 -0700120
Selim Cinekd5921a82019-01-29 19:04:08 -0800121import javax.inject.Inject;
122import javax.inject.Named;
123
Jorim Jaggibe565df2014-04-28 17:51:23 +0200124public class NotificationPanelView extends PanelView implements
Jason Monk8b9d67f2016-03-02 08:59:08 -0500125 ExpandableView.OnHeightChangedListener,
Jorim Jaggi290600a2014-05-30 17:02:20 +0200126 View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700127 KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
Jason Monke59dc402018-08-16 12:05:01 -0400128 OnHeadsUpChangedListener, QS.HeightListener, ZenModeController.Callback,
Selim Cinek3d6ae232019-01-04 14:14:33 -0800129 ConfigurationController.ConfigurationListener, StateListener,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700130 PulseExpansionHandler.ExpansionCallback, DynamicPrivacyController.Listener,
131 NotificationWakeUpCoordinator.WakeUpListener {
Chet Haase4d179dc2012-08-22 07:14:42 -0700132
Jorim Jaggi58bef332014-11-21 18:10:32 +0100133 private static final boolean DEBUG = false;
134
Lucas Dupin014ad092018-12-12 17:53:03 -0800135 /**
Lucas Dupinee63c372018-08-03 11:58:24 -0700136 * Fling expanding QS.
137 */
138 public static final int FLING_EXPAND = 0;
139
140 /**
141 * Fling collapsing QS, potentially stopping when QS becomes QQS.
142 */
143 public static final int FLING_COLLAPSE = 1;
144
145 /**
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500146 * Fling until QS is completely hidden.
Lucas Dupinee63c372018-08-03 11:58:24 -0700147 */
148 public static final int FLING_HIDE = 2;
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400149 private final DozeParameters mDozeParameters;
Lucas Dupinee63c372018-08-03 11:58:24 -0700150
Fabian Kozynski786974f2019-07-25 12:44:06 -0400151 private double mQqsSplitFraction;
152
Selim Cinekf99d0002014-06-13 07:36:01 +0200153 // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
154 // changed.
155 private static final int CAP_HEIGHT = 1456;
156 private static final int FONT_HEIGHT = 2163;
157
Selim Cinek08bd435a2019-07-26 11:37:14 -0700158 /**
159 * Maximum time before which we will expand the panel even for slow motions when getting a
160 * touch passed over from launcher.
161 */
162 private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300;
163
Doris Ling3c00afb2016-07-19 17:04:21 -0700164 static final String COUNTER_PANEL_OPEN = "panel_open";
165 static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
Chris Wren49f06f52015-05-01 16:12:12 -0400166 private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
167
Jorim Jaggi613f55f2015-07-16 15:30:10 -0700168 private static final Rect mDummyDirtyRect = new Rect(0, 0, 1, 1);
Winson Chung9cd21152019-05-28 15:04:08 -0700169 private static final Rect mEmptyRect = new Rect();
Jorim Jaggi613f55f2015-07-16 15:30:10 -0700170
Lucas Dupin60661a62018-04-12 10:50:13 -0700171 private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties()
172 .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700173 private static final AnimatableProperty KEYGUARD_HEADS_UP_SHOWING_AMOUNT
174 = AnimatableProperty.from("KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
175 NotificationPanelView::setKeyguardHeadsUpShowingAmount,
176 NotificationPanelView::getKeyguardHeadsUpShowingAmount,
177 R.id.keyguard_hun_animator_tag,
178 R.id.keyguard_hun_animator_end_tag,
179 R.id.keyguard_hun_animator_start_tag);
180 private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
181 new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Lucas Dupin4b75b192019-08-29 14:46:29 -0700182 @VisibleForTesting
183 final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
184 new KeyguardUpdateMonitorCallback() {
Lucas Dupin7f356e22019-09-12 11:03:39 -0700185
186 @Override
187 public void onBiometricAuthenticated(int userId,
188 BiometricSourceType biometricSourceType) {
189 if (mFirstBypassAttempt && mUpdateMonitor.isUnlockingWithBiometricAllowed()) {
190 mDelayShowingKeyguardStatusBar = true;
191 }
192 }
193
Lucas Dupin4b75b192019-08-29 14:46:29 -0700194 @Override
195 public void onBiometricRunningStateChanged(boolean running,
196 BiometricSourceType biometricSourceType) {
197 boolean keyguardOrShadeLocked = mBarState == StatusBarState.KEYGUARD
198 || mBarState == StatusBarState.SHADE_LOCKED;
Lucas Dupin7f356e22019-09-12 11:03:39 -0700199 if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
200 && !mDelayShowingKeyguardStatusBar) {
Lucas Dupin4b75b192019-08-29 14:46:29 -0700201 mFirstBypassAttempt = false;
202 animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
203 }
204 }
205
206 @Override
207 public void onFinishedGoingToSleep(int why) {
208 mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
Lucas Dupin7f356e22019-09-12 11:03:39 -0700209 mDelayShowingKeyguardStatusBar = false;
210 }
211 };
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400212 private final KeyguardStateController.Callback mKeyguardMonitorCallback =
213 new KeyguardStateController.Callback() {
Lucas Dupin7f356e22019-09-12 11:03:39 -0700214 @Override
215 public void onKeyguardFadingAwayChanged() {
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400216 if (!mKeyguardStateController.isKeyguardFadingAway()) {
Lucas Dupin7f356e22019-09-12 11:03:39 -0700217 mFirstBypassAttempt = false;
218 mDelayShowingKeyguardStatusBar = false;
219 }
Lucas Dupin4b75b192019-08-29 14:46:29 -0700220 }
221 };
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200222
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400223 private final InjectionInflationController mInjectionInflationController;
Selim Cineke64f52a2017-08-24 14:48:38 -0700224 private final PowerManager mPowerManager;
Phil Weaver428e3972018-01-18 12:50:05 -0800225 private final AccessibilityManager mAccessibilityManager;
Selim Cinekd5921a82019-01-29 19:04:08 -0800226 private final NotificationWakeUpCoordinator mWakeUpCoordinator;
Selim Cinek3d6ae232019-01-04 14:14:33 -0800227 private final PulseExpansionHandler mPulseExpansionHandler;
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700228 private final KeyguardBypassController mKeyguardBypassController;
Robert Snoebergerf4976b32019-06-21 15:40:14 -0400229 private final KeyguardUpdateMonitor mUpdateMonitor;
Adrian Roos52414e32017-04-28 09:23:19 -0700230
Lucas Dupin23964c72019-05-21 16:12:45 -0700231 @VisibleForTesting
232 protected KeyguardAffordanceHelper mAffordanceHelper;
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200233 private KeyguardUserSwitcher mKeyguardUserSwitcher;
Lucas Dupinc97d88f2019-01-17 16:34:22 -0800234 @VisibleForTesting
235 protected KeyguardStatusBarView mKeyguardStatusBar;
Lucas Dupind61974d2019-03-29 16:09:26 -0700236 @VisibleForTesting
237 protected ViewGroup mBigClockContainer;
Jason Monk0ceef212016-11-02 14:05:23 -0400238 private QS mQs;
Lucas Dupind61974d2019-03-29 16:09:26 -0700239 @VisibleForTesting
240 protected FrameLayout mQsFrame;
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800241 @VisibleForTesting
242 protected KeyguardStatusView mKeyguardStatusView;
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200243 private View mQsNavbarScrim;
Xiaohui Chen5da71352016-02-22 10:04:41 -0800244 protected NotificationsQuickSettingsContainer mNotificationContainerParent;
Xiaohui Chen9528f432016-02-12 15:03:18 -0800245 protected NotificationStackScrollLayout mNotificationStackScroller;
Matt Pietal8d4a6352019-10-24 11:19:18 -0400246 protected FrameLayout mHomeControlsLayout;
Lucas Dupin60661a62018-04-12 10:50:13 -0700247 private boolean mAnimateNextPositionUpdate;
Chet Haase4d179dc2012-08-22 07:14:42 -0700248
Jorim Jaggid7daab72014-05-06 22:22:20 +0200249 private int mTrackingPointer;
Selim Cinekd5ab6452016-12-08 16:34:00 -0800250 private VelocityTracker mQsVelocityTracker;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200251 private boolean mQsTracking;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200252
253 /**
Jorim Jaggidc96d632014-07-01 18:48:52 +0200254 * If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
255 * the expansion for quick settings.
256 */
257 private boolean mConflictingQsExpansionGesture;
258
259 /**
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200260 * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
261 * intercepted yet.
262 */
263 private boolean mIntercepting;
Selim Cinek4a21a7f2015-05-19 11:00:38 -0700264 private boolean mPanelExpanded;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200265 private boolean mQsExpanded;
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200266 private boolean mQsExpandedWhenExpandingStarted;
John Spurlockbc3a5e92014-05-30 16:20:05 -0400267 private boolean mQsFullyExpanded;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200268 private boolean mKeyguardShowing;
John Spurlockd54da8a2014-08-03 23:23:52 -0400269 private boolean mDozing;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +0100270 private boolean mDozingOnDown;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400271 protected int mBarState;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200272 private float mInitialHeightOnTouch;
273 private float mInitialTouchX;
274 private float mInitialTouchY;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200275 private float mLastTouchX;
276 private float mLastTouchY;
Xiaohui Chen9528f432016-02-12 15:03:18 -0800277 protected float mQsExpansionHeight;
278 protected int mQsMinExpansionHeight;
279 protected int mQsMaxExpansionHeight;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200280 private int mQsPeekHeight;
Jorim Jaggi290600a2014-05-30 17:02:20 +0200281 private boolean mStackScrollerOverscrolling;
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200282 private boolean mQsExpansionFromOverscroll;
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200283 private float mLastOverscroll;
Muyuan Li59690042016-03-23 16:45:16 -0700284 protected boolean mQsExpansionEnabled = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200285 private ValueAnimator mQsExpansionAnimator;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +0200286 private FlingAnimationUtils mFlingAnimationUtils;
Selim Cinek9dbbca82014-05-15 15:23:37 +0200287 private int mStatusBarMinHeight;
Jorim Jaggi457cc352014-06-02 22:47:42 +0200288 private int mNotificationsHeaderCollideDistance;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200289 private int mUnlockMoveDistance;
Jorim Jaggi48bc36a2014-07-25 23:16:04 +0200290 private float mEmptyDragAmount;
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700291 private float mDownX;
292 private float mDownY;
John Spurlock3e04cc82014-05-30 12:34:03 -0400293
Robert Snoeberger69956802019-04-16 16:55:21 -0400294 private final KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200295 new KeyguardClockPositionAlgorithm();
Robert Snoeberger69956802019-04-16 16:55:21 -0400296 private final KeyguardClockPositionAlgorithm.Result mClockPositionResult =
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200297 new KeyguardClockPositionAlgorithm.Result();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200298 private boolean mIsExpanding;
Selim Cinekf99d0002014-06-13 07:36:01 +0200299
Selim Cinek4c6969a2014-05-26 19:22:17 +0200300 private boolean mBlockTouches;
Jason Monk3c68ca22015-01-30 11:30:29 -0500301 // Used for two finger gesture as well as accessibility shortcut to QS.
302 private boolean mQsExpandImmediate;
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200303 private boolean mTwoFingerQsExpandPossible;
Jorim Jaggi56306252014-07-03 00:40:09 +0200304
305 /**
306 * If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
307 * need to take this into account in our panel height calculation.
308 */
Jorim Jaggibd003102014-07-04 00:02:42 +0200309 private boolean mQsAnimatorExpand;
Selim Cinekbaa23272014-07-08 18:01:07 +0200310 private boolean mIsLaunchTransitionFinished;
311 private boolean mIsLaunchTransitionRunning;
312 private Runnable mLaunchAnimationEndRunnable;
313 private boolean mOnlyAffordanceInThisMotion;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200314 private boolean mKeyguardStatusViewAnimating;
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100315 private ValueAnimator mQsSizeChangeAnimator;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200316
Selim Cinek24176c32017-03-01 16:50:30 -0800317 private boolean mShowEmptyShadeView;
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200318
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200319 private boolean mQsScrimEnabled = true;
Selim Cinek90c94652014-08-18 16:46:22 +0200320 private boolean mLastAnnouncementWasQuickSettings;
Selim Cinek19c8c702014-08-25 22:09:19 +0200321 private boolean mQsTouchAboveFalsingThreshold;
322 private int mQsFalsingThreshold;
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200323
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100324 private float mKeyguardStatusBarAnimateAlpha = 1f;
Jorim Jaggi0a818222014-11-10 19:04:34 +0100325 private int mOldLayoutDirection;
Selim Cinek684a4422015-04-15 16:18:39 -0700326 private HeadsUpTouchHelper mHeadsUpTouchHelper;
327 private boolean mIsExpansionFromHeadsUp;
Selim Cinek79d79c42015-05-21 16:14:45 -0700328 private boolean mListenForHeadsUp;
Selim Cinek684a4422015-04-15 16:18:39 -0700329 private int mNavigationBarBottomHeight;
Selim Cinekd2281152015-04-10 14:37:46 -0700330 private boolean mExpandingFromHeadsUp;
Selim Cinek684a4422015-04-15 16:18:39 -0700331 private boolean mCollapsedOnDown;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700332 private int mPositionMinSideMargin;
Selim Cineka981d082016-08-03 14:45:31 -0700333 private int mMaxFadeoutHeight;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700334 private int mLastOrientation = -1;
Selim Cinekbbc580b2015-06-03 14:11:03 +0200335 private boolean mClosingWithAlphaFadeOut;
Selim Cinek0fccc722015-07-29 17:04:36 -0700336 private boolean mHeadsUpAnimatingAway;
Selim Cinek372d1bd2015-08-14 13:19:37 -0700337 private boolean mLaunchingAffordance;
Lucas Dupin193677c2018-06-11 19:16:03 -0700338 private boolean mAffordanceHasPreview;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700339 private FalsingManager mFalsingManager;
Jorim Jaggi40aa8812015-09-23 12:59:22 -0700340 private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700341
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700342 private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
343 @Override
344 public void run() {
Selim Cinekcafa87f2016-10-26 17:00:17 -0700345 setHeadsUpAnimatingAway(false);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700346 notifyBarPanelExpansionChanged();
347 }
348 };
Selim Cinek53f8e7d2016-03-25 02:28:01 -0700349 private NotificationGroupManager mGroupManager;
Selim Cinek24176c32017-03-01 16:50:30 -0800350 private boolean mShowIconsWhenExpanded;
Selim Cinek378053a2016-12-07 15:41:28 -0800351 private int mIndicationBottomPadding;
Adrian Roos75fa9642017-04-18 11:34:56 -0700352 private int mAmbientIndicationBottomPadding;
Selim Cinekfcff4c62016-12-27 14:26:06 +0100353 private boolean mIsFullWidth;
Lucas Dupind61974d2019-03-29 16:09:26 -0700354 private boolean mBlockingExpansionForCurrentTouch;
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200355
Hyunyoung Song43a8cad2019-07-02 13:39:05 -0700356 /**
357 * Following variables maintain state of events when input focus transfer may occur.
358 */
359 private boolean mExpectingSynthesizedDown; // expecting to see synthesized DOWN event
360 private boolean mLastEventSynthesizedDown; // last event was synthesized DOWN event
Sunny Goyalb59e15e2019-06-13 17:02:32 -0700361
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200362 /**
363 * Current dark amount that follows regular interpolation curve of animation.
364 */
365 private float mInterpolatedDarkAmount;
366
367 /**
368 * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the
369 * interpolation curve is different.
370 */
371 private float mLinearDarkAmount;
372
Lucas Dupin56057342018-04-10 11:49:18 -0700373 private boolean mPulsing;
Chris Wren27a52fa2017-02-01 14:21:43 -0500374 private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
Selim Cinek24176c32017-03-01 16:50:30 -0800375 private boolean mNoVisibleNotifications = true;
Lucas Dupin987f1932017-05-13 21:02:52 -0700376 private boolean mUserSetupComplete;
Selim Cinekd7768f42017-11-22 06:43:44 -0800377 private int mQsNotificationTopPadding;
Selim Cinek2627d722018-01-19 12:16:49 -0800378 private float mExpandOffset;
379 private boolean mHideIconsDuringNotificationLaunch = true;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800380 private int mStackScrollerMeasuringPass;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800381 private ArrayList<Consumer<ExpandableNotificationRow>> mTrackingHeadsUpListeners
382 = new ArrayList<>();
Selim Cinek60ffea62018-03-22 13:16:44 -0700383 private ArrayList<Runnable> mVerticalTranslationListener = new ArrayList<>();
Selim Cinek332c23f2018-03-16 17:37:50 -0700384 private HeadsUpAppearanceController mHeadsUpAppearanceController;
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100385
shawnlin4ef7ca52018-05-11 16:44:42 +0800386 private int mPanelAlpha;
387 private int mCurrentPanelAlpha;
388 private final Paint mAlphaPaint = new Paint();
389 private Runnable mPanelAlphaEndAction;
Lucas Dupin5778eb02019-06-05 17:50:48 -0700390 private float mBottomAreaShadeAlpha;
391 private final ValueAnimator mBottomAreaShadeAlphaAnimator;
shawnlin4ef7ca52018-05-11 16:44:42 +0800392 private AnimatorListenerAdapter mAnimatorListenerAdapter = new AnimatorListenerAdapter() {
393 @Override
394 public void onAnimationEnd(Animator animation) {
395 if (mPanelAlphaEndAction != null) {
396 mPanelAlphaEndAction.run();
397 }
398 }
399 };
400 private final AnimatableProperty PANEL_ALPHA = AnimatableProperty.from(
401 "panelAlpha",
402 NotificationPanelView::setPanelAlphaInternal,
403 NotificationPanelView::getCurrentPanelAlpha,
404 R.id.panel_alpha_animator_tag,
405 R.id.panel_alpha_animator_start_tag,
406 R.id.panel_alpha_animator_end_tag);
407 private final AnimationProperties PANEL_ALPHA_OUT_PROPERTIES = new AnimationProperties()
408 .setDuration(150)
409 .setCustomInterpolator(PANEL_ALPHA.getProperty(), Interpolators.ALPHA_OUT);
410 private final AnimationProperties PANEL_ALPHA_IN_PROPERTIES = new AnimationProperties()
411 .setDuration(200)
412 .setAnimationFinishListener(mAnimatorListenerAdapter)
413 .setCustomInterpolator(PANEL_ALPHA.getProperty(), Interpolators.ALPHA_IN);
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400414 private final NotificationEntryManager mEntryManager;
shawnlin4ef7ca52018-05-11 16:44:42 +0800415
Jason Monk297c04e2018-08-23 17:16:59 -0400416 private final CommandQueue mCommandQueue;
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400417 private final NotificationLockscreenUserManager mLockscreenUserManager;
418 private final ShadeController mShadeController;
Charles Chenf3d295c2018-11-30 18:15:21 +0800419 private int mDisplayId;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400420
Robert Snoebergerd717b842019-03-08 13:03:07 -0500421 /**
422 * Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
423 *
424 * onThemeChanged is forced when the theme might not have changed. So, to avoid unncessary
425 * work, check the current id with the cached id.
426 */
427 private int mThemeResId;
Lucas Dupin00ebe132019-04-26 16:17:56 -0700428 private KeyguardIndicationController mKeyguardIndicationController;
Lucas Dupin23964c72019-05-21 16:12:45 -0700429 private Consumer<Boolean> mAffordanceLaunchListener;
Selim Cinek195dfc52019-05-30 19:35:05 -0700430 private int mShelfHeight;
431 private Runnable mOnReinflationListener;
432 private int mDarkIconSize;
Selim Cinekb0fada62019-06-17 19:03:59 -0700433 private int mHeadsUpInset;
Selim Cinekd21232e2019-06-20 14:15:59 -0700434 private boolean mHeadsUpPinnedMode;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700435 private float mKeyguardHeadsUpShowingAmount = 0.0f;
436 private boolean mShowingKeyguardHeadsUp;
Selim Cinek08bd435a2019-07-26 11:37:14 -0700437 private boolean mAllowExpandForSmallExpansion;
438 private Runnable mExpandAfterLayoutRunnable;
Lucas Dupin7f356e22019-09-12 11:03:39 -0700439
440 /**
441 * If face auth with bypass is running for the first time after you turn on the screen.
442 * (From aod or screen off)
443 */
Lucas Dupin4b75b192019-08-29 14:46:29 -0700444 private boolean mFirstBypassAttempt;
Lucas Dupin7f356e22019-09-12 11:03:39 -0700445 /**
446 * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
447 * the keyguard is dismissed to show the status bar.
448 */
449 private boolean mDelayShowingKeyguardStatusBar;
Robert Snoebergerd717b842019-03-08 13:03:07 -0500450
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400451 private PluginManager mPluginManager;
452 private FrameLayout mPluginFrame;
453 private NPVPluginManager mNPVPluginManager;
454
Selim Cinekd5921a82019-01-29 19:04:08 -0800455 @Inject
456 public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400457 InjectionInflationController injectionInflationController,
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400458 NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700459 DynamicPrivacyController dynamicPrivacyController,
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400460 KeyguardBypassController bypassController, FalsingManager falsingManager,
461 PluginManager pluginManager, ShadeController shadeController,
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400462 NotificationLockscreenUserManager notificationLockscreenUserManager,
463 NotificationEntryManager notificationEntryManager,
Lucas Dupind236ee32019-10-08 15:33:59 -0700464 KeyguardStateController keyguardStateController,
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400465 StatusBarStateController statusBarStateController, DozeLog dozeLog,
466 DozeParameters dozeParameters) {
Lucas Dupind236ee32019-10-08 15:33:59 -0700467 super(context, attrs, falsingManager, dozeLog, keyguardStateController,
468 (SysuiStatusBarStateController) statusBarStateController);
Jorim Jaggi58bef332014-11-21 18:10:32 +0100469 setWillNotDraw(!DEBUG);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400470 mInjectionInflationController = injectionInflationController;
Dave Mankoffc195ea82019-06-28 16:33:25 -0400471 mFalsingManager = falsingManager;
Selim Cineke64f52a2017-08-24 14:48:38 -0700472 mPowerManager = context.getSystemService(PowerManager.class);
Selim Cinekd5921a82019-01-29 19:04:08 -0800473 mWakeUpCoordinator = coordinator;
Phil Weaver428e3972018-01-18 12:50:05 -0800474 mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
475 setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
shawnlin4ef7ca52018-05-11 16:44:42 +0800476 mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
477 setPanelAlpha(255, false /* animate */);
Jason Monk297c04e2018-08-23 17:16:59 -0400478 mCommandQueue = getComponent(context, CommandQueue.class);
Charles Chenf3d295c2018-11-30 18:15:21 +0800479 mDisplayId = context.getDisplayId();
Selim Cinek3d6ae232019-01-04 14:14:33 -0800480 mPulseExpansionHandler = pulseExpansionHandler;
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400481 mDozeParameters = dozeParameters;
Selim Cinekb0fada62019-06-17 19:03:59 -0700482 pulseExpansionHandler.setPulseExpandAbortListener(() -> {
483 if (mQs != null) {
484 mQs.animateHeaderSlidingOut();
485 }
486 });
Robert Snoebergerd717b842019-03-08 13:03:07 -0500487 mThemeResId = context.getThemeResId();
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700488 mKeyguardBypassController = bypassController;
Dave Mankoffe2294692019-08-14 11:53:13 -0400489 mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
Lucas Dupin4b75b192019-08-29 14:46:29 -0700490 mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400491 mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700492 dynamicPrivacyController.addListener(this);
Lucas Dupin5778eb02019-06-05 17:50:48 -0700493
494 mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0);
495 mBottomAreaShadeAlphaAnimator.addUpdateListener(animation -> {
496 mBottomAreaShadeAlpha = (float) animation.getAnimatedValue();
497 updateKeyguardBottomAreaAlpha();
498 });
499 mBottomAreaShadeAlphaAnimator.setDuration(160);
500 mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400501 mPluginManager = pluginManager;
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400502 mShadeController = shadeController;
503 mLockscreenUserManager = notificationLockscreenUserManager;
504 mEntryManager = notificationEntryManager;
505
506 setBackgroundColor(Color.TRANSPARENT);
Daniel Sandler13522a22012-09-27 14:46:58 -0400507 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700508
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800509 /**
510 * Returns if there's a custom clock being presented.
511 */
512 public boolean hasCustomClock() {
513 return mKeyguardStatusView.hasCustomClock();
514 }
515
Jason Monke59dc402018-08-16 12:05:01 -0400516 private void setStatusBar(StatusBar bar) {
Daniel Sandler040c2e42012-10-17 00:56:33 -0400517 mStatusBar = bar;
Lucas Dupin987f1932017-05-13 21:02:52 -0700518 mKeyguardBottomArea.setStatusBar(mStatusBar);
Daniel Sandler040c2e42012-10-17 00:56:33 -0400519 }
520
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400521 /**
522 * Call after this view has been fully inflated and had its children attached.
523 */
524 public void onChildrenAttached() {
Dave Mankoff48891862019-10-08 14:23:25 -0400525 loadDimens();
Alan Viverette51efddb2017-04-05 10:00:01 -0400526 mKeyguardStatusBar = findViewById(R.id.keyguard_header);
527 mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
Jason Monkd075b212016-05-25 12:30:51 -0400528
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500529 KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
Robert Snoeberger1e580722019-01-17 15:44:35 -0500530 mBigClockContainer = findViewById(R.id.big_clock_container);
531 keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500532
Matt Pietal50c8b502019-08-21 13:03:12 -0400533 mHomeControlsLayout = findViewById(R.id.home_controls_layout);
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800534 mNotificationContainerParent = findViewById(R.id.notification_container_parent);
535 mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
Jason Monkd075b212016-05-25 12:30:51 -0400536 mNotificationStackScroller.setOnHeightChangedListener(this);
537 mNotificationStackScroller.setOverscrollTopChangedListener(this);
538 mNotificationStackScroller.setOnEmptySpaceClickListener(this);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800539 addTrackingHeadsUpListener(mNotificationStackScroller::setTrackingHeadsUp);
Alan Viverette51efddb2017-04-05 10:00:01 -0400540 mKeyguardBottomArea = findViewById(R.id.keyguard_bottom_area);
Jason Monkd075b212016-05-25 12:30:51 -0400541 mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
Jason Monkd075b212016-05-25 12:30:51 -0400542 mLastOrientation = getResources().getConfiguration().orientation;
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400543 mPluginFrame = findViewById(R.id.plugin_frame);
Fabian Kozynski2865ab02019-10-11 15:03:59 -0400544 if (Settings.System.getInt(
545 mContext.getContentResolver(), "npv_plugin_flag", 0) == 1) {
546 mNPVPluginManager = new NPVPluginManager(mPluginFrame, mPluginManager);
547 }
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400548
Jason Monkd075b212016-05-25 12:30:51 -0400549
Lucas Dupin987f1932017-05-13 21:02:52 -0700550 initBottomArea();
551
Selim Cinekd5921a82019-01-29 19:04:08 -0800552 mWakeUpCoordinator.setStackScroller(mNotificationStackScroller);
Alan Viverette51efddb2017-04-05 10:00:01 -0400553 mQsFrame = findViewById(R.id.qs_frame);
Selim Cinek3d6ae232019-01-04 14:14:33 -0800554 mPulseExpansionHandler.setUp(mNotificationStackScroller, this, mShadeController);
Selim Cinek820ba2d2019-06-18 18:59:09 -0700555 mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
556 @Override
Selim Cinek8ee02b12019-07-22 14:49:18 -0700557 public void onFullyHiddenChanged(boolean isFullyHidden) {
558 updateKeyguardStatusBarForHeadsUp();
559 }
560
561 @Override
Selim Cinek820ba2d2019-06-18 18:59:09 -0700562 public void onPulseExpansionChanged(boolean expandingChanged) {
563 if (mKeyguardBypassController.getBypassEnabled()) {
564 // Position the notifications while dragging down while pulsing
565 requestScrollerTopPaddingUpdate(false /* animate */);
566 updateQSPulseExpansion();
567 }
568 }
569 });
Matt Pietal50c8b502019-08-21 13:03:12 -0400570
Dave Mankoff0cf8dfc2019-09-27 12:46:41 -0400571 mPluginManager.addPluginListener(
Matt Pietal50c8b502019-08-21 13:03:12 -0400572 new PluginListener<HomeControlsPlugin>() {
573
574 @Override
575 public void onPluginConnected(HomeControlsPlugin plugin,
576 Context pluginContext) {
577 plugin.sendParentGroup(mHomeControlsLayout);
578 }
579
580 @Override
581 public void onPluginDisconnected(HomeControlsPlugin plugin) {
582
583 }
584 }, HomeControlsPlugin.class, false);
Jason Monk0ceef212016-11-02 14:05:23 -0400585 }
John Spurlockbceed062014-08-10 18:04:16 -0400586
Jason Monk0ceef212016-11-02 14:05:23 -0400587 @Override
588 protected void onAttachedToWindow() {
589 super.onAttachedToWindow();
590 FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener);
Jason Monkaf08c152018-12-04 11:12:39 -0500591 Dependency.get(StatusBarStateController.class).addCallback(this);
Jason Monke59dc402018-08-16 12:05:01 -0400592 Dependency.get(ZenModeController.class).addCallback(this);
593 Dependency.get(ConfigurationController.class).addCallback(this);
Lucas Dupin4b75b192019-08-29 14:46:29 -0700594 mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
Robert Snoebergerd717b842019-03-08 13:03:07 -0500595 // Theme might have changed between inflating this view and attaching it to the window, so
596 // force a call to onThemeChanged
597 onThemeChanged();
Jason Monk0ceef212016-11-02 14:05:23 -0400598 }
599
600 @Override
601 protected void onDetachedFromWindow() {
602 super.onDetachedFromWindow();
603 FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener);
Jason Monkaf08c152018-12-04 11:12:39 -0500604 Dependency.get(StatusBarStateController.class).removeCallback(this);
Jason Monke59dc402018-08-16 12:05:01 -0400605 Dependency.get(ZenModeController.class).removeCallback(this);
606 Dependency.get(ConfigurationController.class).removeCallback(this);
Lucas Dupin4b75b192019-08-29 14:46:29 -0700607 mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
Jorim Jaggi069cd032014-05-15 03:09:01 +0200608 }
609
610 @Override
611 protected void loadDimens() {
612 super.loadDimens();
Jorim Jaggi1d480692014-05-20 19:41:58 +0200613 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
Selim Cinek9dbbca82014-05-15 15:23:37 +0200614 mStatusBarMinHeight = getResources().getDimensionPixelSize(
615 com.android.internal.R.dimen.status_bar_height);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200616 mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200617 mNotificationsHeaderCollideDistance =
618 getResources().getDimensionPixelSize(R.dimen.header_notifications_collide_distance);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200619 mUnlockMoveDistance = getResources().getDimensionPixelOffset(R.dimen.unlock_move_distance);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200620 mClockPositionAlgorithm.loadDimens(getResources());
Selim Cinek19c8c702014-08-25 22:09:19 +0200621 mQsFalsingThreshold = getResources().getDimensionPixelSize(
622 R.dimen.qs_falsing_threshold);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -0700623 mPositionMinSideMargin = getResources().getDimensionPixelSize(
624 R.dimen.notification_panel_min_side_margin);
Selim Cineka981d082016-08-03 14:45:31 -0700625 mMaxFadeoutHeight = getResources().getDimensionPixelSize(
626 R.dimen.max_notification_fadeout_height);
Selim Cinek378053a2016-12-07 15:41:28 -0800627 mIndicationBottomPadding = getResources().getDimensionPixelSize(
628 R.dimen.keyguard_indication_bottom_padding);
Selim Cinekd7768f42017-11-22 06:43:44 -0800629 mQsNotificationTopPadding = getResources().getDimensionPixelSize(
Selim Cinekb95fd182017-12-21 13:03:32 -0800630 R.dimen.qs_notification_padding);
Selim Cinek195dfc52019-05-30 19:35:05 -0700631 mShelfHeight = getResources().getDimensionPixelSize(R.dimen.notification_shelf_height);
632 mDarkIconSize = getResources().getDimensionPixelSize(
633 R.dimen.status_bar_icon_drawing_size_dark);
Selim Cinekb0fada62019-06-17 19:03:59 -0700634 int statusbarHeight = getResources().getDimensionPixelSize(
635 com.android.internal.R.dimen.status_bar_height);
636 mHeadsUpInset = statusbarHeight + getResources().getDimensionPixelSize(
637 R.dimen.heads_up_status_bar_padding);
Fabian Kozynski786974f2019-07-25 12:44:06 -0400638 mQqsSplitFraction = ((float) getResources().getInteger(R.integer.qqs_split_fraction)) / (
639 getResources().getInteger(R.integer.qqs_split_fraction)
640 + getResources().getInteger(R.integer.qs_split_fraction));
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200641 }
642
Lucas Dupin23964c72019-05-21 16:12:45 -0700643 /**
644 * @see #launchCamera(boolean, int)
645 * @see #setLaunchingAffordance(boolean)
646 */
647 public void setLaunchAffordanceListener(Consumer<Boolean> listener) {
648 mAffordanceLaunchListener = listener;
649 }
650
John Spurlock7e6809a2014-08-06 16:03:14 -0400651 public void updateResources() {
Anthony Chen04d1ea72017-04-21 14:30:11 -0700652 Resources res = getResources();
653 int qsWidth = res.getDimensionPixelSize(R.dimen.qs_panel_width);
John Spurlock7e6809a2014-08-06 16:03:14 -0400654 int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
Jason Monk845b3b92016-03-10 14:38:13 -0500655 FrameLayout.LayoutParams lp =
Jason Monk0ceef212016-11-02 14:05:23 -0400656 (FrameLayout.LayoutParams) mQsFrame.getLayoutParams();
Anthony Chen04d1ea72017-04-21 14:30:11 -0700657 if (lp.width != qsWidth || lp.gravity != panelGravity) {
658 lp.width = qsWidth;
John Spurlock7e6809a2014-08-06 16:03:14 -0400659 lp.gravity = panelGravity;
Jason Monk0ceef212016-11-02 14:05:23 -0400660 mQsFrame.setLayoutParams(lp);
John Spurlock7e6809a2014-08-06 16:03:14 -0400661 }
662
Anthony Chen04d1ea72017-04-21 14:30:11 -0700663 int panelWidth = res.getDimensionPixelSize(R.dimen.notification_panel_width);
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200664 lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
Selim Cinek9e87cba2017-02-17 13:01:01 -0800665 if (lp.width != panelWidth || lp.gravity != panelGravity) {
John Spurlock7e6809a2014-08-06 16:03:14 -0400666 lp.width = panelWidth;
667 lp.gravity = panelGravity;
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200668 mNotificationStackScroller.setLayoutParams(lp);
669 }
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400670 int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings);
Matt Pietald43e1332019-09-25 15:48:05 -0400671 int topMargin = sideMargin;
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400672 lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams();
673 if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin
674 || lp.rightMargin != sideMargin || lp.topMargin != topMargin) {
675 lp.width = qsWidth;
676 lp.gravity = panelGravity;
677 lp.leftMargin = sideMargin;
678 lp.rightMargin = sideMargin;
679 lp.topMargin = topMargin;
680 mPluginFrame.setLayoutParams(lp);
681 }
John Spurlock7e6809a2014-08-06 16:03:14 -0400682 }
683
Jason Monke59dc402018-08-16 12:05:01 -0400684 @Override
685 public void onDensityOrFontScaleChanged() {
686 updateShowEmptyShadeView();
687 }
688
689 @Override
Lucas Dupin8c51ce22017-11-21 13:21:05 -0800690 public void onThemeChanged() {
Robert Snoebergerd717b842019-03-08 13:03:07 -0500691 final int themeResId = getContext().getThemeResId();
692 if (mThemeResId == themeResId) {
693 return;
694 }
695 mThemeResId = themeResId;
696
Robert Snoeberger97822ed2019-04-05 10:37:21 -0400697 reInflateViews();
698 }
699
700 @Override
701 public void onOverlayChanged() {
702 reInflateViews();
703 }
704
705 private void reInflateViews() {
Jason Monke59dc402018-08-16 12:05:01 -0400706 updateShowEmptyShadeView();
707
Lucas Dupin987f1932017-05-13 21:02:52 -0700708 // Re-inflate the status view group.
709 int index = indexOfChild(mKeyguardStatusView);
710 removeView(mKeyguardStatusView);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400711 mKeyguardStatusView = (KeyguardStatusView) mInjectionInflationController
712 .injectable(LayoutInflater.from(mContext)).inflate(
Robert Snoeberger97822ed2019-04-05 10:37:21 -0400713 R.layout.keyguard_status_view,
714 this,
715 false);
Lucas Dupin987f1932017-05-13 21:02:52 -0700716 addView(mKeyguardStatusView, index);
717
Robert Snoebergere90131e2019-01-24 14:07:30 -0500718 // Re-associate the clock container with the keyguard clock switch.
719 mBigClockContainer.removeAllViews();
720 KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
721 keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
722
Lucas Dupin987f1932017-05-13 21:02:52 -0700723 // Update keyguard bottom area
724 index = indexOfChild(mKeyguardBottomArea);
725 removeView(mKeyguardBottomArea);
Lucas Dupincea7dee2018-10-16 12:43:37 -0700726 KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400727 mKeyguardBottomArea = (KeyguardBottomAreaView) mInjectionInflationController
728 .injectable(LayoutInflater.from(mContext)).inflate(
Robert Snoeberger97822ed2019-04-05 10:37:21 -0400729 R.layout.keyguard_bottom_area,
730 this,
731 false);
Lucas Dupincea7dee2018-10-16 12:43:37 -0700732 mKeyguardBottomArea.initFrom(oldBottomArea);
Lucas Dupin987f1932017-05-13 21:02:52 -0700733 addView(mKeyguardBottomArea, index);
734 initBottomArea();
Lucas Dupin00ebe132019-04-26 16:17:56 -0700735 mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
Lucas Dupin1a8b33d2018-11-12 18:18:15 -0800736 onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
737 mStatusBarStateController.getInterpolatedDozeAmount());
Jason Monkbd9745a2017-07-06 16:03:01 -0400738
Lucas Dupin7da4f262018-09-20 13:41:46 -0700739 if (mKeyguardStatusBar != null) {
740 mKeyguardStatusBar.onThemeChanged();
741 }
742
Jason Monk1fd3fc32018-08-14 17:20:09 -0400743 setKeyguardStatusViewVisibility(mBarState, false, false);
744 setKeyguardBottomAreaVisibility(mBarState, false);
Selim Cinek195dfc52019-05-30 19:35:05 -0700745 if (mOnReinflationListener != null) {
746 mOnReinflationListener.run();
747 }
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400748 reinflatePluginContainer();
749 }
750
751 @Override
752 public void onUiModeChanged() {
753 reinflatePluginContainer();
754 }
755
756 private void reinflatePluginContainer() {
757 int index = indexOfChild(mPluginFrame);
758 removeView(mPluginFrame);
759 mPluginFrame = (FrameLayout) mInjectionInflationController
760 .injectable(LayoutInflater.from(mContext)).inflate(
761 R.layout.status_bar_expanded_plugin_frame,
762 this,
763 false);
764 addView(mPluginFrame, index);
765
766 Resources res = getResources();
767 int qsWidth = res.getDimensionPixelSize(R.dimen.qs_panel_width);
768 int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
769 FrameLayout.LayoutParams lp;
770 int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings);
771 int topMargin =
772 res.getDimensionPixelOffset(com.android.internal.R.dimen.quick_qs_total_height);
Matt Pietal5a19cb62019-10-30 12:31:07 -0400773 if (Utils.useQsMediaPlayer(mContext)) {
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400774 topMargin = res.getDimensionPixelOffset(
775 com.android.internal.R.dimen.quick_qs_total_height_with_media);
776 }
Fabian Kozynski3bf518d2019-08-15 15:44:07 -0400777 lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams();
778 if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin
779 || lp.rightMargin != sideMargin || lp.topMargin != topMargin) {
780 lp.width = qsWidth;
781 lp.gravity = panelGravity;
782 lp.leftMargin = sideMargin;
783 lp.rightMargin = sideMargin;
784 lp.topMargin = topMargin;
785 mPluginFrame.setLayoutParams(lp);
786 }
787
Fabian Kozynski2865ab02019-10-11 15:03:59 -0400788 if (mNPVPluginManager != null) mNPVPluginManager.replaceFrameLayout(mPluginFrame);
Lucas Dupin987f1932017-05-13 21:02:52 -0700789 }
790
791 private void initBottomArea() {
Dave Mankoffc195ea82019-06-28 16:33:25 -0400792 mAffordanceHelper = new KeyguardAffordanceHelper(this, getContext(), mFalsingManager);
Lucas Dupin987f1932017-05-13 21:02:52 -0700793 mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
794 mKeyguardBottomArea.setStatusBar(mStatusBar);
795 mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
796 }
797
798 public void setKeyguardIndicationController(KeyguardIndicationController indicationController) {
Lucas Dupin00ebe132019-04-26 16:17:56 -0700799 mKeyguardIndicationController = indicationController;
800 mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
Lucas Dupin987f1932017-05-13 21:02:52 -0700801 }
802
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200803 @Override
804 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700805 DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200806 super.onLayout(changed, left, top, right, bottom);
Selim Cinekfcff4c62016-12-27 14:26:06 +0100807 setIsFullWidth(mNotificationStackScroller.getWidth() == getWidth());
Jorim Jaggid7daab72014-05-06 22:22:20 +0200808
Selim Cinekf99d0002014-06-13 07:36:01 +0200809 // Update Clock Pivot
810 mKeyguardStatusView.setPivotX(getWidth() / 2);
Lucas Dupin987f1932017-05-13 21:02:52 -0700811 mKeyguardStatusView.setPivotY((FONT_HEIGHT - CAP_HEIGHT) / 2048f *
812 mKeyguardStatusView.getClockTextSize());
Selim Cinekf99d0002014-06-13 07:36:01 +0200813
Jorim Jaggid7daab72014-05-06 22:22:20 +0200814 // Calculate quick setting heights.
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100815 int oldMaxHeight = mQsMaxExpansionHeight;
Jason Monk0ceef212016-11-02 14:05:23 -0400816 if (mQs != null) {
817 mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
Fabian Kozynski2865ab02019-10-11 15:03:59 -0400818 if (mNPVPluginManager != null) {
819 mNPVPluginManager.setYOffset(mQsMinExpansionHeight);
820 mQsMinExpansionHeight += mNPVPluginManager.getHeight();
821 }
Jason Monk0ceef212016-11-02 14:05:23 -0400822 mQsMaxExpansionHeight = mQs.getDesiredHeight();
shawnlin8e4e92c2018-04-12 18:47:24 +0800823 mNotificationStackScroller.setMaxTopPadding(
824 mQsMaxExpansionHeight + mQsNotificationTopPadding);
Jason Monk0ceef212016-11-02 14:05:23 -0400825 }
Selim Cinek237a7012014-09-10 18:12:18 +0200826 positionClockAndNotifications();
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100827 if (mQsExpanded && mQsFullyExpanded) {
828 mQsExpansionHeight = mQsMaxExpansionHeight;
829 requestScrollerTopPaddingUpdate(false /* animate */);
830 requestPanelHeightUpdate();
831
832 // Size has changed, start an animation.
833 if (mQsMaxExpansionHeight != oldMaxHeight) {
834 startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
John Spurlockbc3a5e92014-05-30 16:20:05 -0400835 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100836 } else if (!mQsExpanded) {
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200837 setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200838 }
Selim Cinekbc243a92016-09-27 16:35:13 -0700839 updateExpandedHeight(getExpandedHeight());
Jorim Jaggi0bc49172014-11-03 15:52:13 +0100840 updateHeader();
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100841
842 // If we are running a size change animation, the animation takes care of the height of
843 // the container. However, if we are not animating, we always need to make the QS container
844 // the desired height so when closing the QS detail, it stays smaller after the size change
845 // animation is finished but the detail view is still being animated away (this animation
846 // takes longer than the size change animation).
Jason Monk0ceef212016-11-02 14:05:23 -0400847 if (mQsSizeChangeAnimator == null && mQs != null) {
848 mQs.setHeightOverride(mQs.getDesiredHeight());
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100849 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700850 updateMaxHeadsUpTranslation();
Winson Chung9cd21152019-05-28 15:04:08 -0700851 updateGestureExclusionRect();
Selim Cinek08bd435a2019-07-26 11:37:14 -0700852 if (mExpandAfterLayoutRunnable != null) {
853 mExpandAfterLayoutRunnable.run();
854 mExpandAfterLayoutRunnable = null;
855 }
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700856 DejankUtils.stopDetectingBlockingIpcs("NVP#onLayout");
Winson Chung9cd21152019-05-28 15:04:08 -0700857 }
858
859 private void updateGestureExclusionRect() {
860 Rect exclusionRect = calculateGestureExclusionRect();
861 setSystemGestureExclusionRects(exclusionRect.isEmpty()
862 ? Collections.EMPTY_LIST
863 : Collections.singletonList(exclusionRect));
864 }
865
866 private Rect calculateGestureExclusionRect() {
867 Rect exclusionRect = null;
Evan Lairde1822fd2019-07-10 15:55:45 -0400868 Region touchableRegion = mHeadsUpManager.calculateTouchableRegion();
869 if (isFullyCollapsed() && touchableRegion != null) {
Winson Chung9cd21152019-05-28 15:04:08 -0700870 // Note: The heads up manager also calculates the non-pinned touchable region
Evan Lairde1822fd2019-07-10 15:55:45 -0400871 exclusionRect = touchableRegion.getBounds();
Winson Chung9cd21152019-05-28 15:04:08 -0700872 }
873 return exclusionRect != null
874 ? exclusionRect
875 : mEmptyRect;
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200876 }
877
Selim Cinekfcff4c62016-12-27 14:26:06 +0100878 private void setIsFullWidth(boolean isFullWidth) {
879 mIsFullWidth = isFullWidth;
880 mNotificationStackScroller.setIsFullWidth(isFullWidth);
881 }
882
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100883 private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
884 if (mQsSizeChangeAnimator != null) {
885 oldHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
886 mQsSizeChangeAnimator.cancel();
887 }
888 mQsSizeChangeAnimator = ValueAnimator.ofInt(oldHeight, newHeight);
889 mQsSizeChangeAnimator.setDuration(300);
Selim Cinekc18010f2016-01-20 13:41:30 -0800890 mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100891 mQsSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
892 @Override
893 public void onAnimationUpdate(ValueAnimator animation) {
894 requestScrollerTopPaddingUpdate(false /* animate */);
895 requestPanelHeightUpdate();
896 int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
Jason Monk0ceef212016-11-02 14:05:23 -0400897 mQs.setHeightOverride(height);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100898 }
899 });
900 mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
901 @Override
902 public void onAnimationEnd(Animator animation) {
903 mQsSizeChangeAnimator = null;
904 }
905 });
906 mQsSizeChangeAnimator.start();
907 }
908
Jorim Jaggi069cd032014-05-15 03:09:01 +0200909 /**
910 * Positions the clock and notifications dynamically depending on how many notifications are
911 * showing.
912 */
913 private void positionClockAndNotifications() {
Selim Cinekf99d0002014-06-13 07:36:01 +0200914 boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
Lucas Dupin60661a62018-04-12 10:50:13 -0700915 boolean animateClock = animate || mAnimateNextPositionUpdate;
Selim Cinek1408eb52014-06-02 14:45:38 +0200916 int stackScrollerPadding;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400917 if (mBarState != StatusBarState.KEYGUARD) {
Selim Cinekb0fada62019-06-17 19:03:59 -0700918 stackScrollerPadding = getUnlockedStackScrollerPadding();
Jorim Jaggi069cd032014-05-15 03:09:01 +0200919 } else {
Lucas Dupin60661a62018-04-12 10:50:13 -0700920 int totalHeight = getHeight();
921 int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
Robert Snoeberger69956802019-04-16 16:55:21 -0400922 int clockPreferredY = mKeyguardStatusView.getClockPreferredY(totalHeight);
Selim Cinekb0fada62019-06-17 19:03:59 -0700923 boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400924 final boolean hasVisibleNotifications =
925 !bypassEnabled && mNotificationStackScroller.getVisibleNotificationCount() != 0;
926 mKeyguardStatusView.setHasVisibleNotifications(hasVisibleNotifications);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200927 mClockPositionAlgorithm.setup(
Lucas Dupin41ff6952018-02-18 19:39:32 -0800928 mStatusBarMinHeight,
929 totalHeight - bottomPadding,
Lucas Dupin60661a62018-04-12 10:50:13 -0700930 mNotificationStackScroller.getIntrinsicContentHeight(),
931 getExpandedFraction(),
Lucas Dupin41ff6952018-02-18 19:39:32 -0800932 totalHeight,
Selim Cinek195dfc52019-05-30 19:35:05 -0700933 (int) (mKeyguardStatusView.getHeight()
934 - mShelfHeight / 2.0f - mDarkIconSize / 2.0f),
Robert Snoeberger69956802019-04-16 16:55:21 -0400935 clockPreferredY,
Robert Snoeberger168949a2019-04-18 09:39:42 -0400936 hasCustomClock(),
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400937 hasVisibleNotifications,
Jorim Jaggic4cf07a2018-07-05 18:28:12 +0200938 mInterpolatedDarkAmount,
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700939 mEmptyDragAmount,
Selim Cinekb0fada62019-06-17 19:03:59 -0700940 bypassEnabled,
941 getUnlockedStackScrollerPadding());
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200942 mClockPositionAlgorithm.run(mClockPositionResult);
Lucas Dupin60661a62018-04-12 10:50:13 -0700943 PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X,
944 mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
945 PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
946 mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
Lucas Dupinbf6d40c2019-06-04 11:40:42 -0700947 updateNotificationTranslucency();
Lucas Dupin41ff6952018-02-18 19:39:32 -0800948 updateClock();
Selim Cinekdb6d6df2019-05-22 20:39:59 -0700949 stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200950 }
Selim Cinek1408eb52014-06-02 14:45:38 +0200951 mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
Lucas Dupin07ed3df2019-03-26 21:23:59 -0700952 mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800953
954 mStackScrollerMeasuringPass++;
Selim Cinekf99d0002014-06-13 07:36:01 +0200955 requestScrollerTopPaddingUpdate(animate);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800956 mStackScrollerMeasuringPass = 0;
Lucas Dupin60661a62018-04-12 10:50:13 -0700957 mAnimateNextPositionUpdate = false;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200958 }
959
Selim Cinek5f71bee2015-11-18 10:25:23 -0800960 /**
Selim Cinekb0fada62019-06-17 19:03:59 -0700961 * @return the padding of the stackscroller when unlocked
962 */
963 private int getUnlockedStackScrollerPadding() {
964 return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
965 + mQsNotificationTopPadding;
966 }
967
968 /**
Selim Cinek5f71bee2015-11-18 10:25:23 -0800969 * @param maximum the maximum to return at most
970 * @return the maximum keyguard notifications that can fit on the screen
971 */
972 public int computeMaxKeyguardNotifications(int maximum) {
Lucas Dupin41ff6952018-02-18 19:39:32 -0800973 float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
Selim Cinekcacc6042016-01-21 16:16:41 -0800974 int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
975 R.dimen.notification_divider_height));
Anthony Chen9e05d462017-04-07 10:10:21 -0700976 NotificationShelf shelf = mNotificationStackScroller.getNotificationShelf();
977 float shelfSize = shelf.getVisibility() == GONE ? 0
978 : shelf.getIntrinsicHeight() + notificationPadding;
Selim Cinek378053a2016-12-07 15:41:28 -0800979 float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize
Alex Chauff7653d2018-02-01 17:18:08 +0000980 - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
981 - mKeyguardStatusView.getLogoutButtonHeight();
Selim Cinek5f71bee2015-11-18 10:25:23 -0800982 int count = 0;
983 for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
984 ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
985 if (!(child instanceof ExpandableNotificationRow)) {
986 continue;
987 }
Selim Cinekfa760d42016-05-10 15:50:53 -0400988 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Jason Monke59dc402018-08-16 12:05:01 -0400989 boolean suppressedSummary = mGroupManager != null
990 && mGroupManager.isSummaryOfSuppressedGroup(row.getStatusBarNotification());
Selim Cinek53f8e7d2016-03-25 02:28:01 -0700991 if (suppressedSummary) {
992 continue;
993 }
Ned Burns8c1b7632019-07-19 14:26:15 -0400994 if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
Selim Cinekfa760d42016-05-10 15:50:53 -0400995 continue;
996 }
997 if (row.isRemoved()) {
998 continue;
999 }
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07001000 availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */)
1001 + notificationPadding;
Selim Cinek5f71bee2015-11-18 10:25:23 -08001002 if (availableSpace >= 0 && count < maximum) {
1003 count++;
Selim Cinek281c2022016-10-13 19:14:43 -07001004 } else if (availableSpace > -shelfSize) {
1005 // if we are exactly the last view, then we can show us still!
1006 for (int j = i + 1; j < mNotificationStackScroller.getChildCount(); j++) {
1007 if (mNotificationStackScroller.getChildAt(j)
1008 instanceof ExpandableNotificationRow) {
1009 return count;
1010 }
1011 }
1012 count++;
1013 return count;
Selim Cinek5f71bee2015-11-18 10:25:23 -08001014 } else {
1015 return count;
1016 }
1017 }
1018 return count;
1019 }
1020
Lucas Dupin41ff6952018-02-18 19:39:32 -08001021 private void updateClock() {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001022 if (!mKeyguardStatusViewAnimating) {
Lucas Dupin78db0902018-02-24 19:42:06 -08001023 mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001024 }
Jorim Jaggi069cd032014-05-15 03:09:01 +02001025 }
1026
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001027 public void animateToFullShade(long delay) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001028 mNotificationStackScroller.goToFullShade(delay);
Jorim Jaggi98fb09c2014-05-01 22:40:56 +02001029 requestLayout();
Lucas Dupin60661a62018-04-12 10:50:13 -07001030 mAnimateNextPositionUpdate = true;
Daniel Sandler08d05e32012-08-08 16:39:54 -04001031 }
1032
Jorim Jaggid7daab72014-05-06 22:22:20 +02001033 public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
1034 mQsExpansionEnabled = qsExpansionEnabled;
Jason Monk0ceef212016-11-02 14:05:23 -04001035 if (mQs == null) return;
1036 mQs.setHeaderClickable(qsExpansionEnabled);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001037 }
1038
Selim Cinek3c4635c2014-05-29 02:12:47 +02001039 @Override
Lucas Dupinee63c372018-08-03 11:58:24 -07001040 public void resetViews(boolean animate) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001041 mIsLaunchTransitionFinished = false;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001042 mBlockTouches = false;
Selim Cinek372d1bd2015-08-14 13:19:37 -07001043 if (!mLaunchingAffordance) {
Adrian Roose31f30e2017-01-25 14:48:15 -08001044 mAffordanceHelper.reset(false);
Jorim Jaggi40aa8812015-09-23 12:59:22 -07001045 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
Selim Cinek372d1bd2015-08-14 13:19:37 -07001046 }
Eliot Courtney47098cb2017-10-18 17:30:30 +09001047 mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
Mady Mellorc2dbe492017-03-30 13:22:03 -07001048 true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
Lucas Dupinee63c372018-08-03 11:58:24 -07001049 if (animate) {
1050 animateCloseQs(true /* animateAway */);
1051 } else {
1052 closeQs();
1053 }
1054 mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, animate,
1055 !animate /* cancelAnimators */);
Selim Cinekb24e0a92015-06-09 20:17:30 -07001056 mNotificationStackScroller.resetScrollPosition();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001057 }
1058
shawnlin8e4e92c2018-04-12 18:47:24 +08001059 @Override
1060 public void collapse(boolean delayed, float speedUpFactor) {
1061 if (!canPanelBeCollapsed()) {
1062 return;
1063 }
1064
1065 if (mQsExpanded) {
1066 mQsExpandImmediate = true;
1067 mNotificationStackScroller.setShouldShowShelfOnly(true);
1068 }
1069 super.collapse(delayed, speedUpFactor);
1070 }
1071
Jorim Jaggid7daab72014-05-06 22:22:20 +02001072 public void closeQs() {
Selim Cinek831941f2015-06-17 15:09:30 -07001073 cancelQsAnimation();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001074 setQsExpansion(mQsMinExpansionHeight);
1075 }
1076
Lucas Dupinee63c372018-08-03 11:58:24 -07001077 /**
1078 * Animate QS closing by flinging it.
1079 * If QS is expanded, it will collapse into QQS and stop.
1080 *
1081 * @param animateAway Do not stop when QS becomes QQS. Fling until QS isn't visible anymore.
1082 */
1083 public void animateCloseQs(boolean animateAway) {
Jorim Jaggibd003102014-07-04 00:02:42 +02001084 if (mQsExpansionAnimator != null) {
1085 if (!mQsAnimatorExpand) {
1086 return;
1087 }
1088 float height = mQsExpansionHeight;
1089 mQsExpansionAnimator.cancel();
1090 setQsExpansion(height);
1091 }
Lucas Dupinee63c372018-08-03 11:58:24 -07001092 flingSettings(0 /* vel */, animateAway ? FLING_HIDE : FLING_COLLAPSE);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001093 }
1094
Jason Monk3c68ca22015-01-30 11:30:29 -05001095 public void expandWithQs() {
1096 if (mQsExpansionEnabled) {
1097 mQsExpandImmediate = true;
shawnlin8e4e92c2018-04-12 18:47:24 +08001098 mNotificationStackScroller.setShouldShowShelfOnly(true);
Jason Monk3c68ca22015-01-30 11:30:29 -05001099 }
Dave Mankoffc88d6222018-10-25 15:31:20 -04001100 if (isFullyCollapsed()) {
Fabian Kozynskif20a3182018-10-02 16:40:34 -04001101 expand(true /* animate */);
1102 } else {
1103 flingSettings(0 /* velocity */, FLING_EXPAND);
1104 }
Jason Monk3c68ca22015-01-30 11:30:29 -05001105 }
1106
Eugene Susla2de69552018-03-20 13:22:17 -07001107 public void expandWithoutQs() {
1108 if (isQsExpanded()) {
Lucas Dupinee63c372018-08-03 11:58:24 -07001109 flingSettings(0 /* velocity */, FLING_COLLAPSE);
Eugene Susla2de69552018-03-20 13:22:17 -07001110 } else {
1111 expand(true /* animate */);
1112 }
1113 }
1114
Daniel Sandler08d05e32012-08-08 16:39:54 -04001115 @Override
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001116 public void fling(float vel, boolean expand) {
Daniel Sandler151f00d2012-10-02 22:33:08 -04001117 GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
1118 if (gr != null) {
Selim Cinek4c6969a2014-05-26 19:22:17 +02001119 gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
Daniel Sandler151f00d2012-10-02 22:33:08 -04001120 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +02001121 super.fling(vel, expand);
Daniel Sandler08d05e32012-08-08 16:39:54 -04001122 }
Chet Haase4d179dc2012-08-22 07:14:42 -07001123
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -07001124 @Override
Jorim Jaggif3b3bee2015-04-16 14:57:34 -07001125 protected void flingToHeight(float vel, boolean expand, float target,
Selim Cinek9db71052015-04-24 18:54:30 -07001126 float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001127 mHeadsUpTouchHelper.notifyFling(!expand);
Selim Cinek2e4f32b2019-07-01 14:56:03 -07001128 setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
Selim Cinek9db71052015-04-24 18:54:30 -07001129 super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001130 }
1131
1132 @Override
Selim Cinek684a4422015-04-15 16:18:39 -07001133 public boolean onInterceptTouchEvent(MotionEvent event) {
Jason Monk231b0522018-01-04 10:49:55 -05001134 if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
Selim Cinek4c6969a2014-05-26 19:22:17 +02001135 return false;
1136 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001137 initDownStates(event);
Lucas Dupin79f0d172019-05-01 11:46:51 -07001138 // Do not let touches go to shade or QS if the bouncer is visible,
1139 // but still let user swipe down to expand the panel, dismissing the bouncer.
1140 if (mStatusBar.isBouncerShowing()) {
1141 return true;
1142 }
Charles He2eda2422017-09-24 17:55:21 +01001143 if (mBar.panelEnabled() && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
Selim Cinek684a4422015-04-15 16:18:39 -07001144 mIsExpansionFromHeadsUp = true;
Chris Wren49f06f52015-05-01 16:12:12 -04001145 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
1146 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001147 return true;
1148 }
Selim Cinekb8cc6ef2019-06-14 16:37:53 -07001149 if (!shouldQuickSettingsIntercept(mDownX, mDownY, 0)
1150 && mPulseExpansionHandler.onInterceptTouchEvent(event)) {
Selim Cinek3d6ae232019-01-04 14:14:33 -08001151 return true;
1152 }
Anthony Chen3cb3ad92016-12-01 10:58:47 -08001153
Anthony Chen54daefe2017-04-07 17:19:54 -07001154 if (!isFullyCollapsed() && onQsIntercept(event)) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001155 return true;
1156 }
1157 return super.onInterceptTouchEvent(event);
1158 }
1159
1160 private boolean onQsIntercept(MotionEvent event) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001161 int pointerIndex = event.findPointerIndex(mTrackingPointer);
1162 if (pointerIndex < 0) {
1163 pointerIndex = 0;
1164 mTrackingPointer = event.getPointerId(pointerIndex);
John Spurlock73203eb2014-04-15 16:14:46 -04001165 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001166 final float x = event.getX(pointerIndex);
1167 final float y = event.getY(pointerIndex);
1168
1169 switch (event.getActionMasked()) {
1170 case MotionEvent.ACTION_DOWN:
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001171 mIntercepting = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001172 mInitialTouchY = y;
1173 mInitialTouchX = x;
1174 initVelocityTracker();
1175 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +02001176 if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001177 getParent().requestDisallowInterceptTouchEvent(true);
1178 }
Jorim Jaggi54045422014-07-03 18:30:40 +02001179 if (mQsExpansionAnimator != null) {
1180 onQsExpansionStarted();
1181 mInitialHeightOnTouch = mQsExpansionHeight;
1182 mQsTracking = true;
1183 mIntercepting = false;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001184 mNotificationStackScroller.cancelLongPress();
Jorim Jaggi54045422014-07-03 18:30:40 +02001185 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001186 break;
1187 case MotionEvent.ACTION_POINTER_UP:
1188 final int upPointer = event.getPointerId(event.getActionIndex());
1189 if (mTrackingPointer == upPointer) {
1190 // gesture is ongoing, find a new pointer to track
1191 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
1192 mTrackingPointer = event.getPointerId(newIndex);
1193 mInitialTouchX = event.getX(newIndex);
1194 mInitialTouchY = event.getY(newIndex);
1195 }
1196 break;
1197
1198 case MotionEvent.ACTION_MOVE:
1199 final float h = y - mInitialTouchY;
1200 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +02001201 if (mQsTracking) {
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001202
1203 // Already tracking because onOverscrolled was called. We need to update here
1204 // so we don't stop for a frame until the next touch event gets handled in
1205 // onTouchEvent.
1206 setQsExpansion(h + mInitialHeightOnTouch);
1207 trackMovement(event);
1208 mIntercepting = false;
1209 return true;
1210 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001211 if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
Selim Cinek4c6969a2014-05-26 19:22:17 +02001212 && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
Jorim Jaggi58bef332014-11-21 18:10:32 +01001213 mQsTracking = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001214 onQsExpansionStarted();
Jorim Jaggi26aa04c2015-07-29 14:52:22 -07001215 notifyExpandingFinished();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001216 mInitialHeightOnTouch = mQsExpansionHeight;
1217 mInitialTouchY = y;
1218 mInitialTouchX = x;
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001219 mIntercepting = false;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001220 mNotificationStackScroller.cancelLongPress();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001221 return true;
1222 }
1223 break;
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001224
1225 case MotionEvent.ACTION_CANCEL:
1226 case MotionEvent.ACTION_UP:
Jorim Jaggic9a52ab2014-05-12 23:46:19 +02001227 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +02001228 if (mQsTracking) {
Chris Wren49f06f52015-05-01 16:12:12 -04001229 flingQsWithCurrentVelocity(y,
Jorim Jaggiaea80f42014-11-10 22:41:54 +01001230 event.getActionMasked() == MotionEvent.ACTION_CANCEL);
Selim Cinek4c6969a2014-05-26 19:22:17 +02001231 mQsTracking = false;
Jorim Jaggic9a52ab2014-05-12 23:46:19 +02001232 }
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001233 mIntercepting = false;
1234 break;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001235 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001236 return false;
John Spurlock73203eb2014-04-15 16:14:46 -04001237 }
1238
Selim Cinekab1dc952014-10-30 20:20:29 +01001239 @Override
1240 protected boolean isInContentBounds(float x, float y) {
Selim Cinekab1dc952014-10-30 20:20:29 +01001241 float stackScrollerX = mNotificationStackScroller.getX();
Selim Cinek04fb2582015-06-02 19:58:09 +02001242 return !mNotificationStackScroller.isBelowLastNotification(x - stackScrollerX, y)
1243 && stackScrollerX < x && x < stackScrollerX + mNotificationStackScroller.getWidth();
Selim Cinekab1dc952014-10-30 20:20:29 +01001244 }
1245
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001246 private void initDownStates(MotionEvent event) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001247 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1248 mOnlyAffordanceInThisMotion = false;
Selim Cinek19c8c702014-08-25 22:09:19 +02001249 mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001250 mDozingOnDown = isDozing();
Selim Cinekb8cc6ef2019-06-14 16:37:53 -07001251 mDownX = event.getX();
1252 mDownY = event.getY();
Selim Cinek684a4422015-04-15 16:18:39 -07001253 mCollapsedOnDown = isFullyCollapsed();
Selim Cinek79d79c42015-05-21 16:14:45 -07001254 mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
Selim Cinek08bd435a2019-07-26 11:37:14 -07001255 mAllowExpandForSmallExpansion = mExpectingSynthesizedDown;
1256 mTouchSlopExceededBeforeDown = mExpectingSynthesizedDown;
Hyunyoung Song43a8cad2019-07-02 13:39:05 -07001257 if (mExpectingSynthesizedDown) {
1258 mLastEventSynthesizedDown = true;
1259 } else {
1260 // down but not synthesized motion event.
1261 mLastEventSynthesizedDown = false;
1262 }
1263 } else {
1264 // not down event at all.
1265 mLastEventSynthesizedDown = false;
Selim Cinekbaa23272014-07-08 18:01:07 +02001266 }
1267 }
1268
Chris Wren49f06f52015-05-01 16:12:12 -04001269 private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
Selim Cinekd5ab6452016-12-08 16:34:00 -08001270 float vel = getCurrentQSVelocity();
Chris Wren49f06f52015-05-01 16:12:12 -04001271 final boolean expandsQs = flingExpandsQs(vel);
1272 if (expandsQs) {
1273 logQsSwipeDown(y);
1274 }
Lucas Dupinee63c372018-08-03 11:58:24 -07001275 flingSettings(vel, expandsQs && !isCancelMotionEvent ? FLING_EXPAND : FLING_COLLAPSE);
Chris Wren49f06f52015-05-01 16:12:12 -04001276 }
1277
1278 private void logQsSwipeDown(float y) {
Selim Cinekd5ab6452016-12-08 16:34:00 -08001279 float vel = getCurrentQSVelocity();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001280 final int gesture = mBarState == StatusBarState.KEYGUARD
Chris Wren27a52fa2017-02-01 14:21:43 -05001281 ? MetricsEvent.ACTION_LS_QS
1282 : MetricsEvent.ACTION_SHADE_QS_PULL;
1283 mLockscreenGestureLogger.write(gesture,
Chris Wren49f06f52015-05-01 16:12:12 -04001284 (int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
1285 (int) (vel / mStatusBar.getDisplayDensity()));
Jorim Jaggic9a52ab2014-05-12 23:46:19 +02001286 }
1287
Jorim Jaggidc96d632014-07-01 18:48:52 +02001288 private boolean flingExpandsQs(float vel) {
Dave Mankoffc88d6222018-10-25 15:31:20 -04001289 if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) {
Selim Cinek19c8c702014-08-25 22:09:19 +02001290 return false;
1291 }
Jorim Jaggidc96d632014-07-01 18:48:52 +02001292 if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
1293 return getQsExpansionFraction() > 0.5f;
1294 } else {
1295 return vel > 0;
1296 }
1297 }
1298
Blazej Magnowski6dc59b42015-09-22 15:14:20 -07001299 private boolean isFalseTouch() {
Adrian Roos6a70b882016-04-19 17:09:07 -07001300 if (!needsAntiFalsing()) {
Blazej Magnowski6dc59b42015-09-22 15:14:20 -07001301 return false;
1302 }
1303 if (mFalsingManager.isClassiferEnabled()) {
1304 return mFalsingManager.isFalseTouch();
1305 }
1306 return !mQsTouchAboveFalsingThreshold;
Selim Cinek5386fb32014-09-03 16:37:36 +02001307 }
1308
Jorim Jaggidc96d632014-07-01 18:48:52 +02001309 private float getQsExpansionFraction() {
Jorim Jaggi11c071a2014-08-14 19:17:11 +02001310 return Math.min(1f, (mQsExpansionHeight - mQsMinExpansionHeight)
Selim Cinekd7768f42017-11-22 06:43:44 -08001311 / (mQsMaxExpansionHeight - mQsMinExpansionHeight));
Jorim Jaggidc96d632014-07-01 18:48:52 +02001312 }
Jorim Jaggi54045422014-07-03 18:30:40 +02001313
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001314 @Override
Selim Cinek08bd435a2019-07-26 11:37:14 -07001315 protected boolean shouldExpandWhenNotFlinging() {
1316 if (super.shouldExpandWhenNotFlinging()) {
1317 return true;
1318 }
1319 if (mAllowExpandForSmallExpansion) {
1320 // When we get a touch that came over from launcher, the velocity isn't always correct
1321 // Let's err on expanding if the gesture has been reasonably slow
1322 long timeSinceDown = SystemClock.uptimeMillis() - mDownTime;
1323 return timeSinceDown <= MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER;
1324 }
1325 return false;
1326 }
1327
1328 @Override
Selim Cinek48ff9b42016-11-09 19:31:51 -08001329 protected float getOpeningHeight() {
Selim Cinekfcff4c62016-12-27 14:26:06 +01001330 return mNotificationStackScroller.getOpeningHeight();
Selim Cinek48ff9b42016-11-09 19:31:51 -08001331 }
1332
1333 @Override
Daniel Sandler040c2e42012-10-17 00:56:33 -04001334 public boolean onTouchEvent(MotionEvent event) {
Jason Monk0ceef212016-11-02 14:05:23 -04001335 if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
Selim Cinek4c6969a2014-05-26 19:22:17 +02001336 return false;
1337 }
Lucas Dupin79f0d172019-05-01 11:46:51 -07001338
1339 // Do not allow panel expansion if bouncer is scrimmed, otherwise user would be able to
1340 // pull down QS or expand the shade.
1341 if (mStatusBar.isBouncerShowingScrimmed()) {
1342 return false;
1343 }
1344
Lucas Dupind61974d2019-03-29 16:09:26 -07001345 // Make sure the next touch won't the blocked after the current ends.
1346 if (event.getAction() == MotionEvent.ACTION_UP
1347 || event.getAction() == MotionEvent.ACTION_CANCEL) {
1348 mBlockingExpansionForCurrentTouch = false;
1349 }
Hyunyoung Song43a8cad2019-07-02 13:39:05 -07001350 // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
1351 // without any ACTION_MOVE event.
1352 // In such case, simply expand the panel instead of being stuck at the bottom bar.
1353 if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
1354 expand(true /* animate */);
1355 }
1356 initDownStates(event);
Selim Cinekb8cc6ef2019-06-14 16:37:53 -07001357 if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
1358 && mPulseExpansionHandler.onTouchEvent(event)) {
Selim Cinek3d6ae232019-01-04 14:14:33 -08001359 // We're expanding all the other ones shouldn't get this anymore
1360 return true;
1361 }
Selim Cinek79d79c42015-05-21 16:14:45 -07001362 if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
1363 && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
1364 mIsExpansionFromHeadsUp = true;
Selim Cinek79d79c42015-05-21 16:14:45 -07001365 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
1366 }
Adrian Roos8008bd12017-02-22 15:02:09 +01001367 boolean handled = false;
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001368 if ((!mIsExpanding || mHintAnimationRunning)
1369 && !mQsExpanded
Jason Monk1fd3fc32018-08-14 17:20:09 -04001370 && mBarState != StatusBarState.SHADE
Adrian Roos2a318412017-01-25 14:48:26 -08001371 && !mDozing) {
Adrian Roos8008bd12017-02-22 15:02:09 +01001372 handled |= mAffordanceHelper.onTouchEvent(event);
Selim Cinekbaa23272014-07-08 18:01:07 +02001373 }
1374 if (mOnlyAffordanceInThisMotion) {
1375 return true;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001376 }
Adrian Roos8008bd12017-02-22 15:02:09 +01001377 handled |= mHeadsUpTouchHelper.onTouchEvent(event);
Anthony Chen3cb3ad92016-12-01 10:58:47 -08001378
Anthony Chen54daefe2017-04-07 17:19:54 -07001379 if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001380 return true;
1381 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07001382 if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
Chris Wren49f06f52015-05-01 16:12:12 -04001383 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07001384 updateVerticalPanelPosition(event.getX());
Adrian Roos8008bd12017-02-22 15:02:09 +01001385 handled = true;
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07001386 }
Adrian Roos8008bd12017-02-22 15:02:09 +01001387 handled |= super.onTouchEvent(event);
Lucas Dupin1c327432019-01-03 13:37:53 -08001388 return !mDozing || mPulsing || handled;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001389 }
1390
Selim Cinek684a4422015-04-15 16:18:39 -07001391 private boolean handleQsTouch(MotionEvent event) {
Mady Melloraaf32f62015-05-01 17:06:50 -07001392 final int action = event.getActionMasked();
1393 if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
Jason Monk1fd3fc32018-08-14 17:20:09 -04001394 && mBarState != StatusBarState.KEYGUARD && !mQsExpanded
Jorim Jaggi18bd04f2014-08-15 00:03:09 +02001395 && mQsExpansionEnabled) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001396
Jorim Jaggidc96d632014-07-01 18:48:52 +02001397 // Down in the empty area while fully expanded - go to QS.
1398 mQsTracking = true;
1399 mConflictingQsExpansionGesture = true;
1400 onQsExpansionStarted();
1401 mInitialHeightOnTouch = mQsExpansionHeight;
1402 mInitialTouchY = event.getX();
1403 mInitialTouchX = event.getY();
1404 }
Selim Cinek684a4422015-04-15 16:18:39 -07001405 if (!isFullyCollapsed()) {
Jorim Jaggi853b0702014-07-05 04:31:14 +02001406 handleQsDown(event);
1407 }
Jason Monk3c68ca22015-01-30 11:30:29 -05001408 if (!mQsExpandImmediate && mQsTracking) {
Jorim Jaggidc96d632014-07-01 18:48:52 +02001409 onQsTouch(event);
1410 if (!mConflictingQsExpansionGesture) {
1411 return true;
1412 }
1413 }
Mady Melloraaf32f62015-05-01 17:06:50 -07001414 if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
Jorim Jaggidc96d632014-07-01 18:48:52 +02001415 mConflictingQsExpansionGesture = false;
1416 }
Mady Melloraaf32f62015-05-01 17:06:50 -07001417 if (action == MotionEvent.ACTION_DOWN && isFullyCollapsed()
Jorim Jaggi18bd04f2014-08-15 00:03:09 +02001418 && mQsExpansionEnabled) {
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001419 mTwoFingerQsExpandPossible = true;
1420 }
Mady Mellor3a4bc792015-05-27 09:10:22 -07001421 if (mTwoFingerQsExpandPossible && isOpenQsEvent(event)
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001422 && event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
Chris Wren49f06f52015-05-01 16:12:12 -04001423 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1);
Jason Monk3c68ca22015-01-30 11:30:29 -05001424 mQsExpandImmediate = true;
shawnlin8e4e92c2018-04-12 18:47:24 +08001425 mNotificationStackScroller.setShouldShowShelfOnly(true);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001426 requestPanelHeightUpdate();
Jorim Jaggi8599a332014-08-14 21:44:23 +02001427
1428 // Normally, we start listening when the panel is expanded, but here we need to start
1429 // earlier so the state is already up to date when dragging down.
1430 setListening(true);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001431 }
Fabian Kozynskidfa4a362019-08-01 17:12:20 -04001432 if (isQsSplitEnabled() && !mKeyguardShowing) {
1433 if (mQsExpandImmediate) {
1434 mNotificationStackScroller.setVisibility(View.GONE);
1435 mQsFrame.setVisibility(View.VISIBLE);
Matt Pietal50c8b502019-08-21 13:03:12 -04001436 mHomeControlsLayout.setVisibility(View.VISIBLE);
Fabian Kozynskidfa4a362019-08-01 17:12:20 -04001437 } else {
1438 mNotificationStackScroller.setVisibility(View.VISIBLE);
1439 mQsFrame.setVisibility(View.GONE);
Matt Pietal50c8b502019-08-21 13:03:12 -04001440 mHomeControlsLayout.setVisibility(View.GONE);
Fabian Kozynskidfa4a362019-08-01 17:12:20 -04001441 }
1442 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001443 return false;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001444 }
1445
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001446 private boolean isInQsArea(float x, float y) {
Jason Monk0ceef212016-11-02 14:05:23 -04001447 return (x >= mQsFrame.getX()
1448 && x <= mQsFrame.getX() + mQsFrame.getWidth())
Jason Monk85686d62016-03-29 12:34:28 -04001449 && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
Jason Monk0ceef212016-11-02 14:05:23 -04001450 || y <= mQs.getView().getY() + mQs.getView().getHeight());
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001451 }
1452
Fabian Kozynski786974f2019-07-25 12:44:06 -04001453 private boolean isOnQsEndArea(float x) {
1454 if (!isQsSplitEnabled()) return false;
1455 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
1456 return x >= mQsFrame.getX() + mQqsSplitFraction * mQsFrame.getWidth()
1457 && x <= mQsFrame.getX() + mQsFrame.getWidth();
1458 } else {
1459 return x >= mQsFrame.getX()
1460 && x <= mQsFrame.getX() + (1 - mQqsSplitFraction) * mQsFrame.getWidth();
1461 }
1462 }
1463
Mady Mellor3a4bc792015-05-27 09:10:22 -07001464 private boolean isOpenQsEvent(MotionEvent event) {
1465 final int pointerCount = event.getPointerCount();
1466 final int action = event.getActionMasked();
1467
1468 final boolean twoFingerDrag = action == MotionEvent.ACTION_POINTER_DOWN
1469 && pointerCount == 2;
1470
1471 final boolean stylusButtonClickDrag = action == MotionEvent.ACTION_DOWN
1472 && (event.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)
Dave Mankoffc88d6222018-10-25 15:31:20 -04001473 || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
Mady Mellor3a4bc792015-05-27 09:10:22 -07001474
1475 final boolean mouseButtonClickDrag = action == MotionEvent.ACTION_DOWN
1476 && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
Dave Mankoffc88d6222018-10-25 15:31:20 -04001477 || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
Mady Mellor3a4bc792015-05-27 09:10:22 -07001478
Fabian Kozynski786974f2019-07-25 12:44:06 -04001479 final boolean onHeaderRight = isOnQsEndArea(event.getX());
1480
1481 return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag || onHeaderRight;
Mady Mellor3a4bc792015-05-27 09:10:22 -07001482 }
1483
Jorim Jaggi853b0702014-07-05 04:31:14 +02001484 private void handleQsDown(MotionEvent event) {
1485 if (event.getActionMasked() == MotionEvent.ACTION_DOWN
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001486 && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001487 mFalsingManager.onQsDown();
Jorim Jaggi853b0702014-07-05 04:31:14 +02001488 mQsTracking = true;
1489 onQsExpansionStarted();
1490 mInitialHeightOnTouch = mQsExpansionHeight;
1491 mInitialTouchY = event.getX();
1492 mInitialTouchX = event.getY();
Jorim Jaggi8599a332014-08-14 21:44:23 +02001493
1494 // If we interrupt an expansion gesture here, make sure to update the state correctly.
Jorim Jaggi26aa04c2015-07-29 14:52:22 -07001495 notifyExpandingFinished();
Jorim Jaggi853b0702014-07-05 04:31:14 +02001496 }
1497 }
1498
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001499 /**
1500 * Input focus transfer is about to happen.
1501 */
1502 public void startWaitingForOpenPanelGesture() {
1503 if (!isFullyCollapsed()) {
1504 return;
1505 }
Hyunyoung Song43a8cad2019-07-02 13:39:05 -07001506 mExpectingSynthesizedDown = true;
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001507 onTrackingStarted();
Selim Cinekaae9ad62019-07-22 18:36:54 -07001508 updatePanelExpanded();
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001509 }
1510
1511 /**
Hyunyoung Song43a8cad2019-07-02 13:39:05 -07001512 * Called when this view is no longer waiting for input focus transfer.
1513 *
1514 * There are two scenarios behind this function call. First, input focus transfer
1515 * has successfully happened and this view already received synthetic DOWN event.
1516 * (mExpectingSynthesizedDown == false). Do nothing.
1517 *
1518 * Second, before input focus transfer finished, user may have lifted finger
1519 * in previous window and this window never received synthetic DOWN event.
1520 * (mExpectingSynthesizedDown == true).
1521 * In this case, we use the velocity to trigger fling event.
1522 *
1523 * @param velocity unit is in px / millis
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001524 */
Selim Cinek08bd435a2019-07-26 11:37:14 -07001525 public void stopWaitingForOpenPanelGesture(final float velocity) {
Hyunyoung Song43a8cad2019-07-02 13:39:05 -07001526 if (mExpectingSynthesizedDown) {
1527 mExpectingSynthesizedDown = false;
Selim Cinek08bd435a2019-07-26 11:37:14 -07001528 maybeVibrateOnOpening();
1529 Runnable runnable = () -> fling(velocity > 1f ? 1000f * velocity : 0,
1530 true /* expand */);
1531 if (mStatusBar.getStatusBarWindow().getHeight()
1532 != mStatusBar.getStatusBarHeight()) {
1533 // The panel is already expanded to its full size, let's expand directly
1534 runnable.run();
1535 } else {
1536 mExpandAfterLayoutRunnable = runnable;
1537 }
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001538 onTrackingStopped(false);
1539 }
1540 }
1541
Selim Cinek4c6969a2014-05-26 19:22:17 +02001542 @Override
Selim Cinek9db71052015-04-24 18:54:30 -07001543 protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
1544 boolean expands = super.flingExpands(vel, vectorVel, x, y);
Jorim Jaggidc96d632014-07-01 18:48:52 +02001545
1546 // If we are already running a QS expansion, make sure that we keep the panel open.
1547 if (mQsExpansionAnimator != null) {
1548 expands = true;
1549 }
1550 return expands;
1551 }
1552
1553 @Override
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001554 protected boolean shouldGestureWaitForTouchSlop() {
Hyunyoung Song43a8cad2019-07-02 13:39:05 -07001555 if (mExpectingSynthesizedDown) {
1556 mExpectingSynthesizedDown = false;
Sunny Goyalb59e15e2019-06-13 17:02:32 -07001557 return false;
1558 }
1559 return isFullyCollapsed() || mBarState != StatusBarState.SHADE;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001560 }
1561
Selim Cinek9db71052015-04-24 18:54:30 -07001562 @Override
1563 protected boolean shouldGestureIgnoreXTouchSlop(float x, float y) {
Adrian Roose31f30e2017-01-25 14:48:15 -08001564 return !mAffordanceHelper.isOnAffordanceIcon(x, y);
Selim Cinek9db71052015-04-24 18:54:30 -07001565 }
1566
Jorim Jaggidc96d632014-07-01 18:48:52 +02001567 private void onQsTouch(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +02001568 int pointerIndex = event.findPointerIndex(mTrackingPointer);
1569 if (pointerIndex < 0) {
1570 pointerIndex = 0;
1571 mTrackingPointer = event.getPointerId(pointerIndex);
1572 }
1573 final float y = event.getY(pointerIndex);
1574 final float x = event.getX(pointerIndex);
Chris Wren49f06f52015-05-01 16:12:12 -04001575 final float h = y - mInitialTouchY;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001576
1577 switch (event.getActionMasked()) {
1578 case MotionEvent.ACTION_DOWN:
1579 mQsTracking = true;
1580 mInitialTouchY = y;
1581 mInitialTouchX = x;
1582 onQsExpansionStarted();
1583 mInitialHeightOnTouch = mQsExpansionHeight;
1584 initVelocityTracker();
1585 trackMovement(event);
1586 break;
1587
1588 case MotionEvent.ACTION_POINTER_UP:
1589 final int upPointer = event.getPointerId(event.getActionIndex());
1590 if (mTrackingPointer == upPointer) {
1591 // gesture is ongoing, find a new pointer to track
1592 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
1593 final float newY = event.getY(newIndex);
1594 final float newX = event.getX(newIndex);
1595 mTrackingPointer = event.getPointerId(newIndex);
1596 mInitialHeightOnTouch = mQsExpansionHeight;
1597 mInitialTouchY = newY;
1598 mInitialTouchX = newX;
1599 }
1600 break;
1601
1602 case MotionEvent.ACTION_MOVE:
Selim Cinek4c6969a2014-05-26 19:22:17 +02001603 setQsExpansion(h + mInitialHeightOnTouch);
Selim Cinek34cf5c42014-09-26 15:39:00 +02001604 if (h >= getFalsingThreshold()) {
Selim Cinek19c8c702014-08-25 22:09:19 +02001605 mQsTouchAboveFalsingThreshold = true;
1606 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02001607 trackMovement(event);
1608 break;
1609
1610 case MotionEvent.ACTION_UP:
1611 case MotionEvent.ACTION_CANCEL:
1612 mQsTracking = false;
1613 mTrackingPointer = -1;
1614 trackMovement(event);
Selim Cinek84e6de72016-02-22 20:57:43 -08001615 float fraction = getQsExpansionFraction();
1616 if (fraction != 0f || y >= mInitialTouchY) {
1617 flingQsWithCurrentVelocity(y,
1618 event.getActionMasked() == MotionEvent.ACTION_CANCEL);
1619 }
Selim Cinekd5ab6452016-12-08 16:34:00 -08001620 if (mQsVelocityTracker != null) {
1621 mQsVelocityTracker.recycle();
1622 mQsVelocityTracker = null;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001623 }
1624 break;
1625 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001626 }
1627
Selim Cinek34cf5c42014-09-26 15:39:00 +02001628 private int getFalsingThreshold() {
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07001629 float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
Selim Cinek34cf5c42014-09-26 15:39:00 +02001630 return (int) (mQsFalsingThreshold * factor);
1631 }
1632
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001633 @Override
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001634 public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
Selim Cinek831941f2015-06-17 15:09:30 -07001635 cancelQsAnimation();
Jorim Jaggi18bd04f2014-08-15 00:03:09 +02001636 if (!mQsExpansionEnabled) {
1637 amount = 0f;
1638 }
Jorim Jaggi290600a2014-05-30 17:02:20 +02001639 float rounded = amount >= 1f ? amount : 0f;
Jason Monke1be3422016-02-09 10:51:40 -05001640 setOverScrolling(rounded != 0f && isRubberbanded);
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001641 mQsExpansionFromOverscroll = rounded != 0f;
Jorim Jaggi11c071a2014-08-14 19:17:11 +02001642 mLastOverscroll = rounded;
Jorim Jaggi290600a2014-05-30 17:02:20 +02001643 updateQsState();
Jorim Jaggi90e0df22014-07-30 01:10:35 +02001644 setQsExpansion(mQsMinExpansionHeight + rounded);
Jorim Jaggi290600a2014-05-30 17:02:20 +02001645 }
1646
Selim Cinek1408eb52014-06-02 14:45:38 +02001647 @Override
1648 public void flingTopOverscroll(float velocity, boolean open) {
Jorim Jaggib7a33032014-08-20 16:21:36 +02001649 mLastOverscroll = 0f;
Selim Cinekf91de682016-05-11 13:01:02 -04001650 mQsExpansionFromOverscroll = false;
Selim Cinek1408eb52014-06-02 14:45:38 +02001651 setQsExpansion(mQsExpansionHeight);
Lucas Dupinee63c372018-08-03 11:58:24 -07001652 flingSettings(!mQsExpansionEnabled && open ? 0f : velocity,
1653 open && mQsExpansionEnabled ? FLING_EXPAND : FLING_COLLAPSE,
Jorim Jaggi18bd04f2014-08-15 00:03:09 +02001654 new Runnable() {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001655 @Override
1656 public void run() {
1657 mStackScrollerOverscrolling = false;
Jason Monke1be3422016-02-09 10:51:40 -05001658 setOverScrolling(false);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001659 updateQsState();
1660 }
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07001661 }, false /* isClick */);
Selim Cinek1408eb52014-06-02 14:45:38 +02001662 }
1663
Jason Monke1be3422016-02-09 10:51:40 -05001664 private void setOverScrolling(boolean overscrolling) {
1665 mStackScrollerOverscrolling = overscrolling;
Jason Monk0ceef212016-11-02 14:05:23 -04001666 if (mQs == null) return;
1667 mQs.setOverscrolling(overscrolling);
Jason Monke1be3422016-02-09 10:51:40 -05001668 }
1669
Jorim Jaggid7daab72014-05-06 22:22:20 +02001670 private void onQsExpansionStarted() {
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001671 onQsExpansionStarted(0);
1672 }
1673
Muyuan Li0e9f5382016-04-27 15:51:15 -07001674 protected void onQsExpansionStarted(int overscrollAmount) {
Selim Cinek831941f2015-06-17 15:09:30 -07001675 cancelQsAnimation();
1676 cancelHeightAnimator();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001677
1678 // Reset scroll position and apply that position to the expanded height.
Jason Monk16ac3772016-02-10 15:39:21 -05001679 float height = mQsExpansionHeight - overscrollAmount;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001680 setQsExpansion(height);
Jorim Jaggi58bef332014-11-21 18:10:32 +01001681 requestPanelHeightUpdate();
Mady Mellorc2dbe492017-03-30 13:22:03 -07001682 mNotificationStackScroller.checkSnoozeLeavebehind();
Lucas Dupin8f3faac2019-03-12 15:28:49 -07001683
1684 // When expanding QS, let's authenticate the user if possible,
1685 // this will speed up notification actions.
1686 if (height == 0) {
1687 mStatusBar.requestFaceAuth();
1688 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001689 }
1690
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001691 private void setQsExpanded(boolean expanded) {
1692 boolean changed = mQsExpanded != expanded;
1693 if (changed) {
1694 mQsExpanded = expanded;
1695 updateQsState();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001696 requestPanelHeightUpdate();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001697 mFalsingManager.setQsExpanded(expanded);
Jorim Jaggib690f0d2014-07-03 23:25:44 +02001698 mStatusBar.setQsExpanded(expanded);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001699 mNotificationContainerParent.setQsExpanded(expanded);
Selim Cinekb0fada62019-06-17 19:03:59 -07001700 mPulseExpansionHandler.setQsExpanded(expanded);
Selim Cinekae2702d2019-06-19 18:04:05 -07001701 mKeyguardBypassController.setQSExpanded(expanded);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001702 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001703 }
1704
Lucas Dupin1a8b33d2018-11-12 18:18:15 -08001705 @Override
1706 public void onStateChanged(int statusBarState) {
Jason Monk1fd3fc32018-08-14 17:20:09 -04001707 boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
Lucas Dupinc8f16e82019-09-17 18:24:50 -04001708 boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001709 int oldState = mBarState;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001710 boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001711 setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
1712 setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001713
Jason Monk1fd3fc32018-08-14 17:20:09 -04001714 mBarState = statusBarState;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001715 mKeyguardShowing = keyguardShowing;
Fabian Kozynskidfa4a362019-08-01 17:12:20 -04001716 if (mKeyguardShowing && isQsSplitEnabled()) {
1717 mNotificationStackScroller.setVisibility(View.VISIBLE);
1718 mQsFrame.setVisibility(View.VISIBLE);
Matt Pietal50c8b502019-08-21 13:03:12 -04001719 mHomeControlsLayout.setVisibility(View.GONE);
Fabian Kozynskidfa4a362019-08-01 17:12:20 -04001720 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001721
Selim Cinek5f2ca6b2016-10-07 14:45:55 -04001722 if (oldState == StatusBarState.KEYGUARD
1723 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001724 animateKeyguardStatusBarOut();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001725 long delay = mBarState == StatusBarState.SHADE_LOCKED
Lucas Dupinc8f16e82019-09-17 18:24:50 -04001726 ? 0 : mKeyguardStateController.calculateGoingToFullShadeDelay();
Jason Monk0ceef212016-11-02 14:05:23 -04001727 mQs.animateHeaderSlidingIn(delay);
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001728 } else if (oldState == StatusBarState.SHADE_LOCKED
1729 && statusBarState == StatusBarState.KEYGUARD) {
1730 animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
Selim Cinekc7e4cb52019-06-20 15:41:45 -07001731 mNotificationStackScroller.resetScrollPosition();
Fabian Kozynskibaa47b62019-04-26 15:40:43 -04001732 // Only animate header if the header is visible. If not, it will partially animate out
1733 // the top of QS
1734 if (!mQsExpanded) {
1735 mQs.animateHeaderSlidingOut();
1736 }
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001737 } else {
1738 mKeyguardStatusBar.setAlpha(1f);
1739 mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
Fabian Kozynski786974f2019-07-25 12:44:06 -04001740 ((PhoneStatusBarView) mBar).maybeShowDivider(keyguardShowing);
Jason Monk1fd3fc32018-08-14 17:20:09 -04001741 if (keyguardShowing && oldState != mBarState) {
Jason Monk0ceef212016-11-02 14:05:23 -04001742 if (mQs != null) {
1743 mQs.hideImmediately();
1744 }
Selim Cineke70d6532015-04-24 16:46:13 -07001745 }
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001746 }
Selim Cinekc7e4cb52019-06-20 15:41:45 -07001747 updateKeyguardStatusBarForHeadsUp();
Jorim Jaggi0e0942d2015-06-05 14:12:20 -07001748 if (keyguardShowing) {
1749 updateDozingVisibilities(false /* animate */);
1750 }
Selim Cinekb0fada62019-06-17 19:03:59 -07001751 // THe update needs to happen after the headerSlide in above, otherwise the translation
1752 // would reset
1753 updateQSPulseExpansion();
Lucas Dupin5778eb02019-06-05 17:50:48 -07001754 maybeAnimateBottomAreaAlpha();
Lucas Dupinb46d0a22019-01-11 16:57:16 -08001755 resetHorizontalPanelPosition();
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001756 updateQsState();
1757 }
1758
Lucas Dupin5778eb02019-06-05 17:50:48 -07001759 private void maybeAnimateBottomAreaAlpha() {
1760 mBottomAreaShadeAlphaAnimator.cancel();
1761 if (mBarState == StatusBarState.SHADE_LOCKED) {
1762 mBottomAreaShadeAlphaAnimator.start();
1763 } else {
1764 mBottomAreaShadeAlpha = 1f;
1765 }
1766 }
1767
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001768 private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() {
1769 @Override
1770 public void run() {
1771 mKeyguardStatusViewAnimating = false;
Lucas Dupin93752552018-03-19 21:32:19 -07001772 mKeyguardStatusView.setVisibility(View.INVISIBLE);
1773 }
1774 };
1775
1776 private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = new Runnable() {
1777 @Override
1778 public void run() {
1779 mKeyguardStatusViewAnimating = false;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001780 mKeyguardStatusView.setVisibility(View.GONE);
1781 }
1782 };
1783
1784 private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = new Runnable() {
1785 @Override
1786 public void run() {
1787 mKeyguardStatusViewAnimating = false;
1788 }
1789 };
1790
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001791 private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
1792 @Override
1793 public void run() {
1794 mKeyguardStatusBar.setVisibility(View.INVISIBLE);
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001795 mKeyguardStatusBar.setAlpha(1f);
1796 mKeyguardStatusBarAnimateAlpha = 1f;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001797 }
1798 };
1799
1800 private void animateKeyguardStatusBarOut() {
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001801 ValueAnimator anim = ValueAnimator.ofFloat(mKeyguardStatusBar.getAlpha(), 0f);
1802 anim.addUpdateListener(mStatusBarAnimateAlphaListener);
Lucas Dupinc8f16e82019-09-17 18:24:50 -04001803 anim.setStartDelay(mKeyguardStateController.isKeyguardFadingAway()
1804 ? mKeyguardStateController.getKeyguardFadingAwayDelay()
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001805 : 0);
Selim Cinekc075f152019-07-24 15:32:17 -07001806
1807 long duration;
Lucas Dupinc8f16e82019-09-17 18:24:50 -04001808 if (mKeyguardStateController.isKeyguardFadingAway()) {
1809 duration = mKeyguardStateController.getShortenedFadingAwayDuration();
Selim Cinekc075f152019-07-24 15:32:17 -07001810 } else {
1811 duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
1812 }
1813 anim.setDuration(duration);
1814
Selim Cinekc18010f2016-01-20 13:41:30 -08001815 anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001816 anim.addListener(new AnimatorListenerAdapter() {
1817 @Override
1818 public void onAnimationEnd(Animator animation) {
1819 mAnimateKeyguardStatusBarInvisibleEndRunnable.run();
1820 }
1821 });
1822 anim.start();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001823 }
1824
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001825 private final ValueAnimator.AnimatorUpdateListener mStatusBarAnimateAlphaListener =
1826 new ValueAnimator.AnimatorUpdateListener() {
Dave Mankoffc88d6222018-10-25 15:31:20 -04001827 @Override
1828 public void onAnimationUpdate(ValueAnimator animation) {
1829 mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
1830 updateHeaderKeyguardAlpha();
1831 }
1832 };
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001833
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001834 private void animateKeyguardStatusBarIn(long duration) {
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001835 mKeyguardStatusBar.setVisibility(View.VISIBLE);
1836 mKeyguardStatusBar.setAlpha(0f);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001837 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
1838 anim.addUpdateListener(mStatusBarAnimateAlphaListener);
1839 anim.setDuration(duration);
Selim Cinekc18010f2016-01-20 13:41:30 -08001840 anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07001841 anim.start();
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001842 }
1843
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001844 private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = new Runnable() {
1845 @Override
1846 public void run() {
1847 mKeyguardBottomArea.setVisibility(View.GONE);
1848 }
1849 };
1850
Robert Snoeberger80f19a32019-02-13 09:40:11 -05001851 private void setKeyguardBottomAreaVisibility(int statusBarState, boolean goingToFullShade) {
Xiaohui Chen9528f432016-02-12 15:03:18 -08001852 mKeyguardBottomArea.animate().cancel();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001853 if (goingToFullShade) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001854 mKeyguardBottomArea.animate()
1855 .alpha(0f)
Lucas Dupinc8f16e82019-09-17 18:24:50 -04001856 .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay())
1857 .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration())
Selim Cinekc18010f2016-01-20 13:41:30 -08001858 .setInterpolator(Interpolators.ALPHA_OUT)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001859 .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
1860 .start();
1861 } else if (statusBarState == StatusBarState.KEYGUARD
1862 || statusBarState == StatusBarState.SHADE_LOCKED) {
Adrian Roos91ba3072017-02-14 16:50:46 +01001863 mKeyguardBottomArea.setVisibility(View.VISIBLE);
Lucas Dupinf14b34f2019-06-06 10:40:23 -07001864 mKeyguardBottomArea.setAlpha(1f);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001865 } else {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001866 mKeyguardBottomArea.setVisibility(View.GONE);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001867 }
1868 }
1869
1870 private void setKeyguardStatusViewVisibility(int statusBarState, boolean keyguardFadingAway,
1871 boolean goingToFullShade) {
Lucas Dupin93752552018-03-19 21:32:19 -07001872 mKeyguardStatusView.animate().cancel();
1873 mKeyguardStatusViewAnimating = false;
Jason Monk1fd3fc32018-08-14 17:20:09 -04001874 if ((!keyguardFadingAway && mBarState == StatusBarState.KEYGUARD
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001875 && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001876 mKeyguardStatusViewAnimating = true;
1877 mKeyguardStatusView.animate()
1878 .alpha(0f)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001879 .setStartDelay(0)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001880 .setDuration(160)
Selim Cinekc18010f2016-01-20 13:41:30 -08001881 .setInterpolator(Interpolators.ALPHA_OUT)
Lucas Dupin93752552018-03-19 21:32:19 -07001882 .withEndAction(mAnimateKeyguardStatusViewGoneEndRunnable);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001883 if (keyguardFadingAway) {
1884 mKeyguardStatusView.animate()
Lucas Dupinc8f16e82019-09-17 18:24:50 -04001885 .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay())
1886 .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration())
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001887 .start();
1888 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001889 } else if (mBarState == StatusBarState.SHADE_LOCKED
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001890 && statusBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001891 mKeyguardStatusView.setVisibility(View.VISIBLE);
1892 mKeyguardStatusViewAnimating = true;
1893 mKeyguardStatusView.setAlpha(0f);
1894 mKeyguardStatusView.animate()
1895 .alpha(1f)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001896 .setStartDelay(0)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001897 .setDuration(320)
Selim Cinekc18010f2016-01-20 13:41:30 -08001898 .setInterpolator(Interpolators.ALPHA_IN)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001899 .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
1900 } else if (statusBarState == StatusBarState.KEYGUARD) {
Lucas Dupin93752552018-03-19 21:32:19 -07001901 if (keyguardFadingAway) {
1902 mKeyguardStatusViewAnimating = true;
1903 mKeyguardStatusView.animate()
1904 .alpha(0)
1905 .translationYBy(-getHeight() * 0.05f)
1906 .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
1907 .setDuration(125)
1908 .setStartDelay(0)
1909 .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable)
1910 .start();
1911 } else {
1912 mKeyguardStatusView.setVisibility(View.VISIBLE);
1913 mKeyguardStatusView.setAlpha(1f);
1914 }
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001915 } else {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001916 mKeyguardStatusView.setVisibility(View.GONE);
1917 mKeyguardStatusView.setAlpha(1f);
1918 }
1919 }
1920
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001921 private void updateQsState() {
Selim Cinekbc243a92016-09-27 16:35:13 -07001922 mNotificationStackScroller.setQsExpanded(mQsExpanded);
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001923 mNotificationStackScroller.setScrollingEnabled(
Jason Monk1fd3fc32018-08-14 17:20:09 -04001924 mBarState != StatusBarState.KEYGUARD && (!mQsExpanded
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001925 || mQsExpansionFromOverscroll));
Jorim Jaggia2052ea2014-08-05 16:22:30 +02001926 updateEmptyShadeView();
Fabian Kozynski2865ab02019-10-11 15:03:59 -04001927 if (mNPVPluginManager != null) {
1928 mNPVPluginManager.changeVisibility((mBarState != StatusBarState.KEYGUARD)
1929 ? View.VISIBLE
1930 : View.INVISIBLE);
1931 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001932 mQsNavbarScrim.setVisibility(mBarState == StatusBarState.SHADE && mQsExpanded
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001933 && !mStackScrollerOverscrolling && mQsScrimEnabled
Dave Mankoffc88d6222018-10-25 15:31:20 -04001934 ? View.VISIBLE
1935 : View.INVISIBLE);
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001936 if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
Adrian Roos2d1ef302014-10-24 18:42:51 +02001937 mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001938 }
Jason Monk0ceef212016-11-02 14:05:23 -04001939 if (mQs == null) return;
1940 mQs.setExpanded(mQsExpanded);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001941 }
1942
1943 private void setQsExpansion(float height) {
1944 height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
Jason Monkbd28a85b2015-02-10 13:29:02 -05001945 mQsFullyExpanded = height == mQsMaxExpansionHeight && mQsMaxExpansionHeight != 0;
Fabian Kozynskif4b368e2019-08-13 10:34:06 -04001946 if (height > mQsMinExpansionHeight && !mQsExpanded && !mStackScrollerOverscrolling
1947 && !mDozing) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001948 setQsExpanded(true);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001949 } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001950 setQsExpanded(false);
John Spurlock73203eb2014-04-15 16:14:46 -04001951 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001952 mQsExpansionHeight = height;
Jason Monke1be3422016-02-09 10:51:40 -05001953 updateQsExpansion();
Selim Cinek1408eb52014-06-02 14:45:38 +02001954 requestScrollerTopPaddingUpdate(false /* animate */);
Selim Cinekfc222962018-07-20 20:09:23 -07001955 updateHeaderKeyguardAlpha();
Jason Monk1fd3fc32018-08-14 17:20:09 -04001956 if (mBarState == StatusBarState.SHADE_LOCKED
1957 || mBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001958 updateKeyguardBottomAreaAlpha();
Robert Snoeberger80f19a32019-02-13 09:40:11 -05001959 updateBigClockAlpha();
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01001960 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04001961 if (mBarState == StatusBarState.SHADE && mQsExpanded
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001962 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
1963 mQsNavbarScrim.setAlpha(getQsExpansionFraction());
1964 }
Selim Cinek90c94652014-08-18 16:46:22 +02001965
Phil Weaver428e3972018-01-18 12:50:05 -08001966 if (mAccessibilityManager.isEnabled()) {
1967 setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
Selim Cinek90c94652014-08-18 16:46:22 +02001968 }
Phil Weaver428e3972018-01-18 12:50:05 -08001969
Dave Mankoffc88d6222018-10-25 15:31:20 -04001970 if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded
1971 && mFalsingManager.shouldEnforceBouncer()) {
Blazej Magnowski72323322015-07-24 11:49:40 -07001972 mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
Felipe Lemeee5d6302016-04-22 16:11:19 -07001973 false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
Blazej Magnowski72323322015-07-24 11:49:40 -07001974 }
Selim Cineka678b0e2019-07-23 13:12:55 -07001975 for (int i = 0; i < mExpansionListeners.size(); i++) {
1976 mExpansionListeners.get(i).onQsExpansionChanged(mQsMaxExpansionHeight != 0
Lucas Dupin2e838ac2019-04-17 16:50:58 -07001977 ? mQsExpansionHeight / mQsMaxExpansionHeight : 0);
1978 }
Jorim Jaggi58bef332014-11-21 18:10:32 +01001979 if (DEBUG) {
1980 invalidate();
1981 }
Selim Cinek90c94652014-08-18 16:46:22 +02001982 }
1983
Xiaohui Chen9528f432016-02-12 15:03:18 -08001984 protected void updateQsExpansion() {
Jason Monk0ceef212016-11-02 14:05:23 -04001985 if (mQs == null) return;
shawnlin8e4e92c2018-04-12 18:47:24 +08001986 float qsExpansionFraction = getQsExpansionFraction();
1987 mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
Fabian Kozynski3bf518d2019-08-15 15:44:07 -04001988 int heightDiff = mQs.getDesiredHeight() - mQs.getQsMinExpansionHeight();
Fabian Kozynski2865ab02019-10-11 15:03:59 -04001989 if (mNPVPluginManager != null) {
1990 mNPVPluginManager.setExpansion(qsExpansionFraction, getHeaderTranslation(), heightDiff);
1991 }
shawnlin8e4e92c2018-04-12 18:47:24 +08001992 mNotificationStackScroller.setQsExpansionFraction(qsExpansionFraction);
Jason Monke1be3422016-02-09 10:51:40 -05001993 }
1994
Phil Weaver428e3972018-01-18 12:50:05 -08001995 private String determineAccessibilityPaneTitle() {
Jason Monk7a952882016-11-15 15:38:30 -05001996 if (mQs != null && mQs.isCustomizing()) {
Jason Monk39c98e62016-03-16 09:18:35 -04001997 return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
Phil Weaver428e3972018-01-18 12:50:05 -08001998 } else if (mQsExpansionHeight != 0.0f && mQsFullyExpanded) {
1999 // Upon initialisation when we are not layouted yet we don't want to announce that we
2000 // are fully expanded, hence the != 0.0f check.
2001 return getContext().getString(R.string.accessibility_desc_quick_settings);
Jason Monk1fd3fc32018-08-14 17:20:09 -04002002 } else if (mBarState == StatusBarState.KEYGUARD) {
Selim Cinek90c94652014-08-18 16:46:22 +02002003 return getContext().getString(R.string.accessibility_desc_lock_screen);
2004 } else {
2005 return getContext().getString(R.string.accessibility_desc_notification_shade);
2006 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02002007 }
2008
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002009 private float calculateQsTopPadding() {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002010 if (mKeyguardShowing
Jason Monk3c68ca22015-01-30 11:30:29 -05002011 && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002012
2013 // Either QS pushes the notifications down when fully expanded, or QS is fully above the
Lucas Dupin41ff6952018-02-18 19:39:32 -08002014 // notifications (mostly on tablets). maxNotificationPadding denotes the normal top
2015 // padding on Keyguard, maxQsPadding denotes the top padding from the quick settings
2016 // panel. We need to take the maximum and linearly interpolate with the panel expansion
2017 // for a nice motion.
Selim Cinekb0fada62019-06-17 19:03:59 -07002018 int maxNotificationPadding = getKeyguardNotificationStaticPadding();
Lucas Dupin41ff6952018-02-18 19:39:32 -08002019 int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
Jason Monk1fd3fc32018-08-14 17:20:09 -04002020 int max = mBarState == StatusBarState.KEYGUARD
Lucas Dupin41ff6952018-02-18 19:39:32 -08002021 ? Math.max(maxNotificationPadding, maxQsPadding)
2022 : maxQsPadding;
Selim Cinek3d6ae232019-01-04 14:14:33 -08002023 return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
2024 getExpandedFraction());
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01002025 } else if (mQsSizeChangeAnimator != null) {
Selim Cinekb0fada62019-06-17 19:03:59 -07002026 return Math.max((int) mQsSizeChangeAnimator.getAnimatedValue(),
2027 getKeyguardNotificationStaticPadding());
Jason Monk16ac3772016-02-10 15:39:21 -05002028 } else if (mKeyguardShowing) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002029 // We can only do the smoother transition on Keyguard when we also are not collapsing
2030 // from a scrolled quick settings.
Selim Cinekb0fada62019-06-17 19:03:59 -07002031 return MathUtils.lerp((float) getKeyguardNotificationStaticPadding(),
Selim Cinek3d6ae232019-01-04 14:14:33 -08002032 (float) (mQsMaxExpansionHeight + mQsNotificationTopPadding),
2033 getQsExpansionFraction());
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002034 } else {
Selim Cinekb95fd182017-12-21 13:03:32 -08002035 return mQsExpansionHeight + mQsNotificationTopPadding;
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002036 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02002037 }
2038
Selim Cinekb0fada62019-06-17 19:03:59 -07002039 /**
2040 * @return the topPadding of notifications when on keyguard not respecting quick settings
2041 * expansion
2042 */
2043 private int getKeyguardNotificationStaticPadding() {
2044 if (!mKeyguardShowing) {
2045 return 0;
2046 }
2047 if (!mKeyguardBypassController.getBypassEnabled()) {
2048 return mClockPositionResult.stackScrollerPadding;
2049 }
2050 int collapsedPosition = mHeadsUpInset;
2051 if (!mNotificationStackScroller.isPulseExpanding()) {
2052 return collapsedPosition;
2053 } else {
2054 int expandedPosition = mClockPositionResult.stackScrollerPadding;
2055 return (int) MathUtils.lerp(collapsedPosition, expandedPosition,
Selim Cinekc7e4cb52019-06-20 15:41:45 -07002056 mNotificationStackScroller.calculateAppearFractionBypass());
Selim Cinekb0fada62019-06-17 19:03:59 -07002057 }
2058 }
2059
2060
Xiaohui Chen9528f432016-02-12 15:03:18 -08002061 protected void requestScrollerTopPaddingUpdate(boolean animate) {
Selim Cinekdb6d6df2019-05-22 20:39:59 -07002062 mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(), animate);
Selim Cinekb0fada62019-06-17 19:03:59 -07002063 if (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) {
2064 // update the position of the header
2065 updateQsExpansion();
2066 }
2067 }
2068
2069
2070 private void updateQSPulseExpansion() {
2071 if (mQs != null) {
2072 mQs.setShowCollapsedOnKeyguard(mKeyguardShowing
2073 && mKeyguardBypassController.getBypassEnabled()
2074 && mNotificationStackScroller.isPulseExpanding());
2075 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02002076 }
2077
2078 private void trackMovement(MotionEvent event) {
Selim Cinekd5ab6452016-12-08 16:34:00 -08002079 if (mQsVelocityTracker != null) mQsVelocityTracker.addMovement(event);
Jorim Jaggifc1a8242014-05-12 19:30:05 +02002080 mLastTouchX = event.getX();
2081 mLastTouchY = event.getY();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002082 }
2083
2084 private void initVelocityTracker() {
Selim Cinekd5ab6452016-12-08 16:34:00 -08002085 if (mQsVelocityTracker != null) {
2086 mQsVelocityTracker.recycle();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002087 }
Selim Cinekd5ab6452016-12-08 16:34:00 -08002088 mQsVelocityTracker = VelocityTracker.obtain();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002089 }
2090
Selim Cinekd5ab6452016-12-08 16:34:00 -08002091 private float getCurrentQSVelocity() {
2092 if (mQsVelocityTracker == null) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02002093 return 0;
2094 }
Selim Cinekd5ab6452016-12-08 16:34:00 -08002095 mQsVelocityTracker.computeCurrentVelocity(1000);
2096 return mQsVelocityTracker.getYVelocity();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002097 }
2098
Selim Cinek831941f2015-06-17 15:09:30 -07002099 private void cancelQsAnimation() {
Jorim Jaggid7daab72014-05-06 22:22:20 +02002100 if (mQsExpansionAnimator != null) {
2101 mQsExpansionAnimator.cancel();
2102 }
2103 }
Jorim Jaggi475b21d2014-07-01 18:13:24 +02002104
Lucas Dupinee63c372018-08-03 11:58:24 -07002105 /**
2106 * @see #flingSettings(float, int, Runnable, boolean)
2107 */
2108 public void flingSettings(float vel, int type) {
2109 flingSettings(vel, type, null, false /* isClick */);
Jorim Jaggi475b21d2014-07-01 18:13:24 +02002110 }
2111
Lucas Dupinee63c372018-08-03 11:58:24 -07002112 /**
2113 * Animates QS or QQS as if the user had swiped up or down.
2114 *
2115 * @param vel Finger velocity or 0 when not initiated by touch events.
2116 * @param type Either {@link #FLING_EXPAND}, {@link #FLING_COLLAPSE} or {@link #FLING_HIDE}.
2117 * @param onFinishRunnable Runnable to be executed at the end of animation.
2118 * @param isClick If originated by click (different interpolator and duration.)
2119 */
2120 protected void flingSettings(float vel, int type, final Runnable onFinishRunnable,
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07002121 boolean isClick) {
Lucas Dupinee63c372018-08-03 11:58:24 -07002122 float target;
2123 switch (type) {
2124 case FLING_EXPAND:
2125 target = mQsMaxExpansionHeight;
2126 break;
2127 case FLING_COLLAPSE:
2128 target = mQsMinExpansionHeight;
2129 break;
2130 case FLING_HIDE:
2131 default:
2132 target = 0;
2133 }
Jorim Jaggi9cd731a2014-05-22 14:26:06 +02002134 if (target == mQsExpansionHeight) {
Jorim Jaggi475b21d2014-07-01 18:13:24 +02002135 if (onFinishRunnable != null) {
2136 onFinishRunnable.run();
2137 }
Jorim Jaggi9cd731a2014-05-22 14:26:06 +02002138 return;
2139 }
Jorim Jaggi519779e2016-10-12 16:52:14 +02002140
2141 // If we move in the opposite direction, reset velocity and use a different duration.
2142 boolean oppositeDirection = false;
Lucas Dupinee63c372018-08-03 11:58:24 -07002143 boolean expanding = type == FLING_EXPAND;
2144 if (vel > 0 && !expanding || vel < 0 && expanding) {
Selim Cinek5386fb32014-09-03 16:37:36 +02002145 vel = 0;
Jorim Jaggi519779e2016-10-12 16:52:14 +02002146 oppositeDirection = true;
Selim Cinek5386fb32014-09-03 16:37:36 +02002147 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02002148 ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07002149 if (isClick) {
Jorim Jaggiea4a19f2016-02-03 21:31:27 -08002150 animator.setInterpolator(Interpolators.TOUCH_RESPONSE);
Jorim Jaggi46ac19f2015-06-05 17:55:21 -07002151 animator.setDuration(368);
2152 } else {
2153 mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
2154 }
Jorim Jaggi519779e2016-10-12 16:52:14 +02002155 if (oppositeDirection) {
Selim Cinek5386fb32014-09-03 16:37:36 +02002156 animator.setDuration(350);
2157 }
Lucas Dupinee63c372018-08-03 11:58:24 -07002158 animator.addUpdateListener(animation -> {
2159 setQsExpansion((Float) animation.getAnimatedValue());
Jorim Jaggid7daab72014-05-06 22:22:20 +02002160 });
2161 animator.addListener(new AnimatorListenerAdapter() {
2162 @Override
2163 public void onAnimationEnd(Animator animation) {
Mady Mellorc2dbe492017-03-30 13:22:03 -07002164 mNotificationStackScroller.resetCheckSnoozeLeavebehind();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002165 mQsExpansionAnimator = null;
Jorim Jaggi475b21d2014-07-01 18:13:24 +02002166 if (onFinishRunnable != null) {
2167 onFinishRunnable.run();
2168 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02002169 }
2170 });
2171 animator.start();
2172 mQsExpansionAnimator = animator;
Lucas Dupinee63c372018-08-03 11:58:24 -07002173 mQsAnimatorExpand = expanding;
Jorim Jaggid7daab72014-05-06 22:22:20 +02002174 }
2175
2176 /**
2177 * @return Whether we should intercept a gesture to open Quick Settings.
2178 */
Selim Cinek4c6969a2014-05-26 19:22:17 +02002179 private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
Selim Cinek5f1fb462019-07-30 13:57:01 -07002180 if (!mQsExpansionEnabled || mCollapsedOnDown
2181 || (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled())) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02002182 return false;
2183 }
Lucas Dupind61974d2019-03-29 16:09:26 -07002184 View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader();
Jason Monk0ceef212016-11-02 14:05:23 -04002185 final boolean onHeader = x >= mQsFrame.getX()
2186 && x <= mQsFrame.getX() + mQsFrame.getWidth()
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002187 && y >= header.getTop() && y <= header.getBottom();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002188 if (mQsExpanded) {
Jason Monk16ac3772016-02-10 15:39:21 -05002189 return onHeader || (yDiff < 0 && isInQsArea(x, y));
Jorim Jaggid7daab72014-05-06 22:22:20 +02002190 } else {
2191 return onHeader;
2192 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +01002193 }
2194
2195 @Override
2196 protected boolean isScrolledToBottom() {
2197 if (!isInSettings()) {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002198 return mBarState == StatusBarState.KEYGUARD
Jorim Jaggi58bef332014-11-21 18:10:32 +01002199 || mNotificationStackScroller.isScrolledToBottom();
Jorim Jaggie0640dd2014-08-05 23:12:40 +02002200 } else {
Jason Monk16ac3772016-02-10 15:39:21 -05002201 return true;
Chris Wren64161cc2012-12-17 16:49:30 -05002202 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +01002203 }
2204
2205 @Override
2206 protected int getMaxPanelHeight() {
Selim Cinekb0fada62019-06-17 19:03:59 -07002207 if (mKeyguardBypassController.getBypassEnabled() && mBarState == StatusBarState.KEYGUARD) {
2208 return getMaxPanelHeightBypass();
2209 } else {
2210 return getMaxPanelHeightNonBypass();
2211 }
2212 }
2213
2214 private int getMaxPanelHeightNonBypass() {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002215 int min = mStatusBarMinHeight;
Selim Cinekb0fada62019-06-17 19:03:59 -07002216 if (!(mBarState == StatusBarState.KEYGUARD)
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002217 && mNotificationStackScroller.getNotGoneChildCount() == 0) {
Selim Cinek94c2d822016-07-13 18:50:04 -07002218 int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002219 min = Math.max(min, minHeight);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002220 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002221 int maxHeight;
Lucas Dupin3558fb12019-04-11 16:20:51 -07002222 if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted
2223 || mPulsing) {
Jorim Jaggi58bef332014-11-21 18:10:32 +01002224 maxHeight = calculatePanelHeightQsExpanded();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002225 } else {
Lucas Dupin60661a62018-04-12 10:50:13 -07002226 maxHeight = calculatePanelHeightShade();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002227 }
2228 maxHeight = Math.max(maxHeight, min);
Jorim Jaggi1d480692014-05-20 19:41:58 +02002229 return maxHeight;
Selim Cinekb6d85eb2014-03-28 20:21:01 +01002230 }
2231
Selim Cinekb0fada62019-06-17 19:03:59 -07002232 private int getMaxPanelHeightBypass() {
2233 int position = mClockPositionAlgorithm.getExpandedClockPosition()
2234 + mKeyguardStatusView.getHeight();
2235 if (mNotificationStackScroller.getVisibleNotificationCount() != 0) {
2236 position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f;
2237 }
2238 return position;
2239 }
2240
Jim Miller07e03842016-06-22 15:18:13 -07002241 public boolean isInSettings() {
Jorim Jaggid7daab72014-05-06 22:22:20 +02002242 return mQsExpanded;
Selim Cinekb6d85eb2014-03-28 20:21:01 +01002243 }
2244
Jim Miller07e03842016-06-22 15:18:13 -07002245 public boolean isExpanding() {
2246 return mIsExpanding;
2247 }
2248
Selim Cinekb6d85eb2014-03-28 20:21:01 +01002249 @Override
2250 protected void onHeightUpdated(float expandedHeight) {
Jason Monk3c68ca22015-01-30 11:30:29 -05002251 if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
Lucas Dupin41ff6952018-02-18 19:39:32 -08002252 // Updating the clock position will set the top padding which might
2253 // trigger a new panel height and re-position the clock.
2254 // This is a circular dependency and should be avoided, otherwise we'll have
2255 // a stack overflow.
2256 if (mStackScrollerMeasuringPass > 2) {
2257 if (DEBUG) Log.d(TAG, "Unstable notification panel height. Aborting.");
2258 } else {
2259 positionClockAndNotifications();
2260 }
Jorim Jaggi7d16bb12014-05-22 04:24:50 +02002261 }
Jason Monk3c68ca22015-01-30 11:30:29 -05002262 if (mQsExpandImmediate || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002263 && !mQsExpansionFromOverscroll) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002264 float t;
2265 if (mKeyguardShowing) {
Jorim Jaggi54045422014-07-03 18:30:40 +02002266
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002267 // On Keyguard, interpolate the QS expansion linearly to the panel expansion
Selim Cinek48ff9b42016-11-09 19:31:51 -08002268 t = expandedHeight / (getMaxPanelHeight());
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002269 } else {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002270 // In Shade, interpolate linearly such that QS is closed whenever panel height is
2271 // minimum QS expansion + minStackHeight
2272 float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
Selim Cinekd1ad9ab2016-03-01 17:52:20 -08002273 + mNotificationStackScroller.getLayoutMinHeight();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002274 float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
2275 t = (expandedHeight - panelHeightQsCollapsed)
2276 / (panelHeightQsExpanded - panelHeightQsCollapsed);
2277 }
Matt Pietal50c8b502019-08-21 13:03:12 -04002278 float targetHeight = mQsMinExpansionHeight
2279 + t * (mQsMaxExpansionHeight - mQsMinExpansionHeight);
2280 setQsExpansion(targetHeight);
2281 mHomeControlsLayout.setTranslationY(targetHeight);
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002282 }
Selim Cinekbc243a92016-09-27 16:35:13 -07002283 updateExpandedHeight(expandedHeight);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002284 updateHeader();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002285 updateNotificationTranslucency();
Selim Cinek4a21a7f2015-05-19 11:00:38 -07002286 updatePanelExpanded();
Winson Chung9cd21152019-05-28 15:04:08 -07002287 updateGestureExclusionRect();
Jorim Jaggi58bef332014-11-21 18:10:32 +01002288 if (DEBUG) {
2289 invalidate();
2290 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002291 }
2292
Selim Cinek4a21a7f2015-05-19 11:00:38 -07002293 private void updatePanelExpanded() {
Selim Cinekaae9ad62019-07-22 18:36:54 -07002294 boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
Selim Cinek4a21a7f2015-05-19 11:00:38 -07002295 if (mPanelExpanded != isExpanded) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +09002296 mHeadsUpManager.setIsPanelExpanded(isExpanded);
Selim Cinek4a21a7f2015-05-19 11:00:38 -07002297 mStatusBar.setPanelExpanded(isExpanded);
2298 mPanelExpanded = isExpanded;
2299 }
2300 }
2301
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002302 private int calculatePanelHeightShade() {
2303 int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
Lucas Dupin41ff6952018-02-18 19:39:32 -08002304 int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin;
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002305 maxHeight += mNotificationStackScroller.getTopPaddingOverflow();
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002306
Jason Monk1fd3fc32018-08-14 17:20:09 -04002307 if (mBarState == StatusBarState.KEYGUARD) {
Lucas Dupin60661a62018-04-12 10:50:13 -07002308 int minKeyguardPanelBottom = mClockPositionAlgorithm.getExpandedClockPosition()
2309 + mKeyguardStatusView.getHeight()
2310 + mNotificationStackScroller.getIntrinsicContentHeight();
2311 return Math.max(maxHeight, minKeyguardPanelBottom);
2312 } else {
2313 return maxHeight;
2314 }
Lucas Dupin41ff6952018-02-18 19:39:32 -08002315 }
2316
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002317 private int calculatePanelHeightQsExpanded() {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002318 float notificationHeight = mNotificationStackScroller.getHeight()
2319 - mNotificationStackScroller.getEmptyBottomMargin()
2320 - mNotificationStackScroller.getTopPadding();
Jorim Jaggi0cce70c2014-11-04 16:13:41 +01002321
2322 // When only empty shade view is visible in QS collapsed state, simulate that we would have
2323 // it in expanded QS state as well so we don't run into troubles when fading the view in/out
2324 // and expanding/collapsing the whole panel from/to quick settings.
Julia Reynolds34f14962018-05-03 12:40:20 +00002325 if (mNotificationStackScroller.getNotGoneChildCount() == 0
2326 && mShowEmptyShadeView) {
Selim Cinekdb167372016-11-17 15:41:17 -08002327 notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
Jorim Jaggi0cce70c2014-11-04 16:13:41 +01002328 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01002329 int maxQsHeight = mQsMaxExpansionHeight;
2330
Selim Cinekd7768f42017-11-22 06:43:44 -08002331 if (mKeyguardShowing) {
2332 maxQsHeight += mQsNotificationTopPadding;
2333 }
2334
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01002335 // If an animation is changing the size of the QS panel, take the animated value.
2336 if (mQsSizeChangeAnimator != null) {
2337 maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
2338 }
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002339 float totalHeight = Math.max(
Jason Monk1fd3fc32018-08-14 17:20:09 -04002340 maxQsHeight, mBarState == StatusBarState.KEYGUARD
Lucas Dupin41ff6952018-02-18 19:39:32 -08002341 ? mClockPositionResult.stackScrollerPadding : 0)
Selim Cinekbc243a92016-09-27 16:35:13 -07002342 + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002343 if (totalHeight > mNotificationStackScroller.getHeight()) {
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01002344 float fullyCollapsedHeight = maxQsHeight
Selim Cinekd1ad9ab2016-03-01 17:52:20 -08002345 + mNotificationStackScroller.getLayoutMinHeight();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002346 totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
2347 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002348 return (int) totalHeight;
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002349 }
2350
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002351 private void updateNotificationTranslucency() {
Selim Cinekbbc580b2015-06-03 14:11:03 +02002352 float alpha = 1f;
Lucas Dupin60661a62018-04-12 10:50:13 -07002353 if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp &&
2354 !mHeadsUpManager.hasPinnedHeadsUp()) {
Selim Cinekbbc580b2015-06-03 14:11:03 +02002355 alpha = getFadeoutAlpha();
Jorim Jaggi5ad92c52014-07-28 21:07:32 +02002356 }
Selim Cinekd21232e2019-06-20 14:15:59 -07002357 if (mBarState == StatusBarState.KEYGUARD && !mHintAnimationRunning
2358 && !mKeyguardBypassController.getBypassEnabled()) {
Lucas Dupin2e838ac2019-04-17 16:50:58 -07002359 alpha *= mClockPositionResult.clockAlpha;
2360 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002361 mNotificationStackScroller.setAlpha(alpha);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02002362 }
2363
Selim Cinekbbc580b2015-06-03 14:11:03 +02002364 private float getFadeoutAlpha() {
Selim Cinek2e4f32b2019-07-01 14:56:03 -07002365 float alpha;
2366 if (mQsMinExpansionHeight == 0) {
2367 return 1.0f;
2368 }
2369 alpha = getExpandedHeight() / mQsMinExpansionHeight;
Selim Cinekbbc580b2015-06-03 14:11:03 +02002370 alpha = Math.max(0, Math.min(alpha, 1));
2371 alpha = (float) Math.pow(alpha, 0.75);
2372 return alpha;
2373 }
2374
Jorim Jaggi47c85a32014-06-05 17:25:40 +02002375 @Override
2376 protected float getOverExpansionAmount() {
2377 return mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */);
2378 }
2379
2380 @Override
2381 protected float getOverExpansionPixels() {
2382 return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
2383 }
2384
Jorim Jaggi457cc352014-06-02 22:47:42 +02002385 /**
2386 * Hides the header when notifications are colliding with it.
2387 */
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002388 private void updateHeader() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002389 if (mBarState == StatusBarState.KEYGUARD) {
Jason Monke1be3422016-02-09 10:51:40 -05002390 updateHeaderKeyguardAlpha();
Jorim Jaggi457cc352014-06-02 22:47:42 +02002391 }
Jason Monke1be3422016-02-09 10:51:40 -05002392 updateQsExpansion();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002393 }
2394
Xiaohui Chen9528f432016-02-12 15:03:18 -08002395 protected float getHeaderTranslation() {
Selim Cinekb0fada62019-06-17 19:03:59 -07002396 if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
2397 return -mQs.getQsMinExpansionHeight();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002398 }
Selim Cinekc7e4cb52019-06-20 15:41:45 -07002399 float appearAmount = mNotificationStackScroller.calculateAppearFraction(mExpandedHeight);
Selim Cinekb0fada62019-06-17 19:03:59 -07002400 float startHeight = -mQsExpansionHeight;
2401 if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()
2402 && mNotificationStackScroller.isPulseExpanding()) {
2403 if (!mPulseExpansionHandler.isExpanding()
2404 && !mPulseExpansionHandler.getLeavingLockscreen()) {
2405 // If we aborted the expansion we need to make sure the header doesn't reappear
2406 // again after the header has animated away
2407 appearAmount = 0;
2408 } else {
Selim Cinekc7e4cb52019-06-20 15:41:45 -07002409 appearAmount = mNotificationStackScroller.calculateAppearFractionBypass();
Selim Cinekb0fada62019-06-17 19:03:59 -07002410 }
2411 startHeight = -mQs.getQsMinExpansionHeight();
Fabian Kozynski2865ab02019-10-11 15:03:59 -04002412 if (mNPVPluginManager != null) startHeight -= mNPVPluginManager.getHeight();
Selim Cinekb0fada62019-06-17 19:03:59 -07002413 }
2414 float translation = MathUtils.lerp(startHeight, 0,
2415 Math.min(1.0f, appearAmount))
Selim Cinek2627d722018-01-19 12:16:49 -08002416 + mExpandOffset;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002417 return Math.min(0, translation);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002418 }
2419
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002420 /**
2421 * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
2422 * during swiping up
2423 */
2424 private float getKeyguardContentsAlpha() {
2425 float alpha;
Jason Monk1fd3fc32018-08-14 17:20:09 -04002426 if (mBarState == StatusBarState.KEYGUARD) {
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002427
Selim Cinek2e4f32b2019-07-01 14:56:03 -07002428 // When on Keyguard, we hide the header as soon as we expanded close enough to the
2429 // header
2430 alpha = getExpandedHeight()
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002431 /
Jorim Jaggi3afddce2014-08-14 20:44:43 +02002432 (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002433 } else {
2434
2435 // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
2436 // soon as we start translating the stack.
Selim Cinek2e4f32b2019-07-01 14:56:03 -07002437 alpha = getExpandedHeight() / mKeyguardStatusBar.getHeight();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002438 }
Selim Cinek2e4f32b2019-07-01 14:56:03 -07002439 alpha = MathUtils.saturate(alpha);
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002440 alpha = (float) Math.pow(alpha, 0.75);
2441 return alpha;
2442 }
2443
Jorim Jaggie4f1a202015-06-30 13:35:11 -07002444 private void updateHeaderKeyguardAlpha() {
Selim Cinekfc222962018-07-20 20:09:23 -07002445 if (!mKeyguardShowing) {
2446 return;
2447 }
Jorim Jaggi3afddce2014-08-14 20:44:43 +02002448 float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
Lucas Dupin7da4f262018-09-20 13:41:46 -07002449 float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
2450 * mKeyguardStatusBarAnimateAlpha;
Selim Cinekc7e4cb52019-06-20 15:41:45 -07002451 newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount;
Lucas Dupin7da4f262018-09-20 13:41:46 -07002452 mKeyguardStatusBar.setAlpha(newAlpha);
Lucas Dupin7f356e22019-09-12 11:03:39 -07002453 boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace()
2454 || mDelayShowingKeyguardStatusBar;
Lucas Dupin4b75b192019-08-29 14:46:29 -07002455 mKeyguardStatusBar.setVisibility(newAlpha != 0f && !mDozing && !hideForBypass
2456 ? VISIBLE : INVISIBLE);
Jorim Jaggie4f1a202015-06-30 13:35:11 -07002457 }
2458
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002459 private void updateKeyguardBottomAreaAlpha() {
Lucas Dupinbc9aac12018-03-04 20:18:15 -08002460 // There are two possible panel expansion behaviors:
2461 // • User dragging up to unlock: we want to fade out as quick as possible
2462 // (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area.
2463 // • User tapping on lock screen: bouncer won't be visible but panel expansion will
2464 // change due to "unlock hint animation." In this case, fading out the bottom area
2465 // would also hide the message that says "swipe to unlock," we don't want to do that.
2466 float expansionAlpha = MathUtils.map(isUnlockHintRunning()
2467 ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
2468 0f, 1f, getExpandedFraction());
2469 float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
Lucas Dupin5778eb02019-06-05 17:50:48 -07002470 alpha *= mBottomAreaShadeAlpha;
Lucas Dupin407cc582019-03-11 21:04:31 -07002471 mKeyguardBottomArea.setAffordanceAlpha(alpha);
Adrian Roos14410b02015-06-10 13:35:41 -07002472 mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
2473 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
2474 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
Adrian Roos8d4e99f2017-05-25 18:03:58 -07002475 View ambientIndicationContainer = mStatusBar.getAmbientIndicationContainer();
2476 if (ambientIndicationContainer != null) {
2477 ambientIndicationContainer.setAlpha(alpha);
2478 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002479 }
2480
Robert Snoeberger80f19a32019-02-13 09:40:11 -05002481 /**
2482 * Custom clock fades away when user drags up to unlock or pulls down quick settings.
2483 *
2484 * Updates alpha of custom clock to match the alpha of the KeyguardBottomArea. See
2485 * {@link updateKeyguardBottomAreaAlpha}.
2486 */
2487 private void updateBigClockAlpha() {
2488 float expansionAlpha = MathUtils.map(isUnlockHintRunning()
2489 ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f, getExpandedFraction());
2490 float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
2491 mBigClockContainer.setAlpha(alpha);
2492 }
2493
Selim Cinekb6d85eb2014-03-28 20:21:01 +01002494 @Override
Selim Cinek1685e632014-04-08 02:27:49 +02002495 protected void onExpandingStarted() {
2496 super.onExpandingStarted();
2497 mNotificationStackScroller.onExpansionStarted();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002498 mIsExpanding = true;
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002499 mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
Jorim Jaggi56306252014-07-03 00:40:09 +02002500 if (mQsExpanded) {
Jorim Jaggi56306252014-07-03 00:40:09 +02002501 onQsExpansionStarted();
2502 }
Jason Monkb5ece9a2016-04-22 11:40:36 -04002503 // Since there are QS tiles in the header now, we need to make sure we start listening
2504 // immediately so they can be up to date.
Jason Monkf4e019a2016-11-03 09:07:20 -04002505 if (mQs == null) return;
Jason Monk0ceef212016-11-02 14:05:23 -04002506 mQs.setHeaderListening(true);
Selim Cinek1685e632014-04-08 02:27:49 +02002507 }
2508
2509 @Override
2510 protected void onExpandingFinished() {
2511 super.onExpandingFinished();
2512 mNotificationStackScroller.onExpansionStopped();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002513 mHeadsUpManager.onExpandingFinished();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002514 mIsExpanding = false;
Selim Cinek684a4422015-04-15 16:18:39 -07002515 if (isFullyCollapsed()) {
Jorim Jaggi613f55f2015-07-16 15:30:10 -07002516 DejankUtils.postAfterTraversal(new Runnable() {
2517 @Override
2518 public void run() {
2519 setListening(false);
2520 }
2521 });
2522
2523 // Workaround b/22639032: Make sure we invalidate something because else RenderThread
2524 // thinks we are actually drawing a frame put in reality we don't, so RT doesn't go
2525 // ahead with rendering and we jank.
2526 postOnAnimation(new Runnable() {
2527 @Override
2528 public void run() {
2529 getParent().invalidateChild(NotificationPanelView.this, mDummyDirtyRect);
2530 }
2531 });
Jorim Jaggie65e3102014-07-01 22:00:50 +02002532 } else {
Jorim Jaggi4538027d2014-07-30 15:43:13 +02002533 setListening(true);
Jorim Jaggie65e3102014-07-01 22:00:50 +02002534 }
Jason Monk3c68ca22015-01-30 11:30:29 -05002535 mQsExpandImmediate = false;
shawnlin8e4e92c2018-04-12 18:47:24 +08002536 mNotificationStackScroller.setShouldShowShelfOnly(false);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02002537 mTwoFingerQsExpandPossible = false;
Selim Cinek684a4422015-04-15 16:18:39 -07002538 mIsExpansionFromHeadsUp = false;
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002539 notifyListenersTrackingHeadsUp(null);
Selim Cinek684a4422015-04-15 16:18:39 -07002540 mExpandingFromHeadsUp = false;
Selim Cinek3d395c62015-06-16 19:37:37 -07002541 setPanelScrimMinFraction(0.0f);
Jorim Jaggie65e3102014-07-01 22:00:50 +02002542 }
2543
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002544 private void notifyListenersTrackingHeadsUp(ExpandableNotificationRow pickedChild) {
2545 for (int i = 0; i < mTrackingHeadsUpListeners.size(); i++) {
2546 Consumer<ExpandableNotificationRow> listener
2547 = mTrackingHeadsUpListeners.get(i);
2548 listener.accept(pickedChild);
2549 }
2550 }
2551
Jorim Jaggi4538027d2014-07-30 15:43:13 +02002552 private void setListening(boolean listening) {
Jorim Jaggi4538027d2014-07-30 15:43:13 +02002553 mKeyguardStatusBar.setListening(listening);
Jason Monk0ceef212016-11-02 14:05:23 -04002554 if (mQs == null) return;
2555 mQs.setListening(listening);
Fabian Kozynski2865ab02019-10-11 15:03:59 -04002556 if (mNPVPluginManager != null) mNPVPluginManager.setListening(listening);
Jorim Jaggi4538027d2014-07-30 15:43:13 +02002557 }
2558
Jorim Jaggie65e3102014-07-01 22:00:50 +02002559 @Override
Oren Blasberg8d3fea12015-07-10 14:21:44 -07002560 public void expand(boolean animate) {
2561 super.expand(animate);
Jorim Jaggi4538027d2014-07-30 15:43:13 +02002562 setListening(true);
Selim Cinek1685e632014-04-08 02:27:49 +02002563 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002564
2565 @Override
Jorim Jaggi47c85a32014-06-05 17:25:40 +02002566 protected void setOverExpansion(float overExpansion, boolean isPixels) {
Jason Monk3c68ca22015-01-30 11:30:29 -05002567 if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
Jorim Jaggidc96d632014-07-01 18:48:52 +02002568 return;
2569 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04002570 if (mBarState != StatusBarState.KEYGUARD) {
Jorim Jaggi47c85a32014-06-05 17:25:40 +02002571 mNotificationStackScroller.setOnHeightChangedListener(null);
2572 if (isPixels) {
2573 mNotificationStackScroller.setOverScrolledPixels(
2574 overExpansion, true /* onTop */, false /* animate */);
2575 } else {
2576 mNotificationStackScroller.setOverScrollAmount(
2577 overExpansion, true /* onTop */, false /* animate */);
2578 }
2579 mNotificationStackScroller.setOnHeightChangedListener(this);
Selim Cinek1408eb52014-06-02 14:45:38 +02002580 }
Selim Cinek24120a52014-05-26 10:05:42 +02002581 }
2582
2583 @Override
Jorim Jaggi282a6152014-06-02 23:37:53 +02002584 protected void onTrackingStarted() {
Lucas Dupinc8f16e82019-09-17 18:24:50 -04002585 mFalsingManager.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
Jorim Jaggi282a6152014-06-02 23:37:53 +02002586 super.onTrackingStarted();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002587 if (mQsFullyExpanded) {
Jason Monk3c68ca22015-01-30 11:30:29 -05002588 mQsExpandImmediate = true;
shawnlin8e4e92c2018-04-12 18:47:24 +08002589 mNotificationStackScroller.setShouldShowShelfOnly(true);
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01002590 }
Jason Monk1fd3fc32018-08-14 17:20:09 -04002591 if (mBarState == StatusBarState.KEYGUARD
2592 || mBarState == StatusBarState.SHADE_LOCKED) {
Adrian Roose31f30e2017-01-25 14:48:15 -08002593 mAffordanceHelper.animateHideLeftRightIcon();
Jorim Jaggie0640dd2014-08-05 23:12:40 +02002594 }
Jorim Jaggie4b840d2015-06-30 16:19:17 -07002595 mNotificationStackScroller.onPanelTrackingStarted();
Jorim Jaggi282a6152014-06-02 23:37:53 +02002596 }
2597
2598 @Override
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +02002599 protected void onTrackingStopped(boolean expand) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002600 mFalsingManager.onTrackingStopped();
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +02002601 super.onTrackingStopped(expand);
Jorim Jaggi47c85a32014-06-05 17:25:40 +02002602 if (expand) {
2603 mNotificationStackScroller.setOverScrolledPixels(
2604 0.0f, true /* onTop */, true /* animate */);
2605 }
Jorim Jaggie4b840d2015-06-30 16:19:17 -07002606 mNotificationStackScroller.onPanelTrackingStopped();
Jason Monk1fd3fc32018-08-14 17:20:09 -04002607 if (expand && (mBarState == StatusBarState.KEYGUARD
2608 || mBarState == StatusBarState.SHADE_LOCKED)) {
Selim Cinekbaa23272014-07-08 18:01:07 +02002609 if (!mHintAnimationRunning) {
Adrian Roose31f30e2017-01-25 14:48:15 -08002610 mAffordanceHelper.reset(true);
Selim Cinekbaa23272014-07-08 18:01:07 +02002611 }
Jorim Jaggi282a6152014-06-02 23:37:53 +02002612 }
Selim Cinek24120a52014-05-26 10:05:42 +02002613 }
2614
Selim Cinek24120a52014-05-26 10:05:42 +02002615 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002616 public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002617
2618 // Block update if we are in quick settings and just the top padding changed
2619 // (i.e. view == null).
2620 if (view == null && mQsExpanded) {
2621 return;
2622 }
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02002623 if (needsAnimation && mInterpolatedDarkAmount == 0) {
Lucas Dupin60661a62018-04-12 10:50:13 -07002624 mAnimateNextPositionUpdate = true;
2625 }
Selim Cinekbc243a92016-09-27 16:35:13 -07002626 ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
2627 ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow
2628 ? (ExpandableNotificationRow) firstChildNotGone
2629 : null;
2630 if (firstRow != null
2631 && (view == firstRow || (firstRow.getNotificationParent() == firstRow))) {
Lucas Dupin60661a62018-04-12 10:50:13 -07002632 requestScrollerTopPaddingUpdate(false /* animate */);
Selim Cinekbc243a92016-09-27 16:35:13 -07002633 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002634 requestPanelHeightUpdate();
2635 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02002636
2637 @Override
Selim Cineka5e211b2014-08-11 17:35:48 +02002638 public void onReset(ExpandableView view) {
2639 }
2640
Jason Monk8b9d67f2016-03-02 08:59:08 -05002641 public void onQsHeightChanged() {
Jason Monkf4e019a2016-11-03 09:07:20 -04002642 mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0;
Jason Monkf50e8822016-06-01 11:19:26 -04002643 if (mQsExpanded && mQsFullyExpanded) {
Jason Monk8b9d67f2016-03-02 08:59:08 -05002644 mQsExpansionHeight = mQsMaxExpansionHeight;
Selim Cinek1408eb52014-06-02 14:45:38 +02002645 requestScrollerTopPaddingUpdate(false /* animate */);
Jorim Jaggi56306252014-07-03 00:40:09 +02002646 requestPanelHeightUpdate();
Jorim Jaggid7daab72014-05-06 22:22:20 +02002647 }
Phil Weaver428e3972018-01-18 12:50:05 -08002648 if (mAccessibilityManager.isEnabled()) {
2649 setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
2650 }
shawnlin8e4e92c2018-04-12 18:47:24 +08002651 mNotificationStackScroller.setMaxTopPadding(
2652 mQsMaxExpansionHeight + mQsNotificationTopPadding);
Jorim Jaggid7daab72014-05-06 22:22:20 +02002653 }
2654
2655 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +02002656 protected void onConfigurationChanged(Configuration newConfig) {
2657 super.onConfigurationChanged(newConfig);
Adrian Roose31f30e2017-01-25 14:48:15 -08002658 mAffordanceHelper.onConfigurationChanged();
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002659 if (newConfig.orientation != mLastOrientation) {
Lucas Dupinb46d0a22019-01-11 16:57:16 -08002660 resetHorizontalPanelPosition();
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07002661 }
2662 mLastOrientation = newConfig.orientation;
Selim Cinek4c6969a2014-05-26 19:22:17 +02002663 }
2664
2665 @Override
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002666 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Adrian Roos5153d4a2016-03-22 10:01:56 -07002667 mNavigationBarBottomHeight = insets.getStableInsetBottom();
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002668 updateMaxHeadsUpTranslation();
2669 return insets;
2670 }
2671
2672 private void updateMaxHeadsUpTranslation() {
Selim Cinek684a4422015-04-15 16:18:39 -07002673 mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07002674 }
2675
2676 @Override
Jorim Jaggi0a818222014-11-10 19:04:34 +01002677 public void onRtlPropertiesChanged(int layoutDirection) {
2678 if (layoutDirection != mOldLayoutDirection) {
Adrian Roose31f30e2017-01-25 14:48:15 -08002679 mAffordanceHelper.onRtlPropertiesChanged();
Jorim Jaggi0a818222014-11-10 19:04:34 +01002680 mOldLayoutDirection = layoutDirection;
2681 }
2682 }
2683
2684 @Override
Jorim Jaggid7daab72014-05-06 22:22:20 +02002685 public void onClick(View v) {
Amin Shaikh8a3e23c2018-04-17 11:14:32 -04002686 onQsExpansionStarted();
2687 if (mQsExpanded) {
Lucas Dupinee63c372018-08-03 11:58:24 -07002688 flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */,
2689 true /* isClick */);
Amin Shaikh8a3e23c2018-04-17 11:14:32 -04002690 } else if (mQsExpansionEnabled) {
2691 mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0);
Lucas Dupinee63c372018-08-03 11:58:24 -07002692 flingSettings(0 /* vel */, FLING_EXPAND, null /* onFinishRunnable */,
2693 true /* isClick */);
Jorim Jaggid7daab72014-05-06 22:22:20 +02002694 }
2695 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02002696
2697 @Override
Christoph Studerb0183992014-12-22 21:02:26 +01002698 public void onAnimationToSideStarted(boolean rightPage, float translation, float vel) {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002699 boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage;
Selim Cinekbaa23272014-07-08 18:01:07 +02002700 mIsLaunchTransitionRunning = true;
2701 mLaunchAnimationEndRunnable = null;
Christoph Studerb0183992014-12-22 21:02:26 +01002702 float displayDensity = mStatusBar.getDisplayDensity();
2703 int lengthDp = Math.abs((int) (translation / displayDensity));
2704 int velocityDp = Math.abs((int) (vel / displayDensity));
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002705 if (start) {
Chris Wren27a52fa2017-02-01 14:21:43 -05002706 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
Blazej Magnowski72323322015-07-24 11:49:40 -07002707
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002708 mFalsingManager.onLeftAffordanceOn();
2709 if (mFalsingManager.shouldEnforceBouncer()) {
Blazej Magnowski72323322015-07-24 11:49:40 -07002710 mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
2711 @Override
2712 public void run() {
2713 mKeyguardBottomArea.launchLeftAffordance();
2714 }
Felipe Lemeee5d6302016-04-22 16:11:19 -07002715 }, null, true /* dismissShade */, false /* afterKeyguardGone */,
2716 true /* deferred */);
Dave Mankoffc88d6222018-10-25 15:31:20 -04002717 } else {
Blazej Magnowski72323322015-07-24 11:49:40 -07002718 mKeyguardBottomArea.launchLeftAffordance();
2719 }
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002720 } else {
Jorim Jaggi40aa8812015-09-23 12:59:22 -07002721 if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals(
2722 mLastCameraLaunchSource)) {
Chris Wren27a52fa2017-02-01 14:21:43 -05002723 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
Jorim Jaggi40aa8812015-09-23 12:59:22 -07002724 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002725 mFalsingManager.onCameraOn();
2726 if (mFalsingManager.shouldEnforceBouncer()) {
Blazej Magnowski72323322015-07-24 11:49:40 -07002727 mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
2728 @Override
2729 public void run() {
Jorim Jaggifc832e32015-09-25 11:54:05 -07002730 mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
Blazej Magnowski72323322015-07-24 11:49:40 -07002731 }
Felipe Lemeee5d6302016-04-22 16:11:19 -07002732 }, null, true /* dismissShade */, false /* afterKeyguardGone */,
2733 true /* deferred */);
Blazej Magnowski72323322015-07-24 11:49:40 -07002734 }
2735 else {
Jorim Jaggifc832e32015-09-25 11:54:05 -07002736 mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
Blazej Magnowski72323322015-07-24 11:49:40 -07002737 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02002738 }
Jorim Jaggi826730a2014-12-08 21:05:13 +01002739 mStatusBar.startLaunchTransitionTimeout();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002740 mBlockTouches = true;
2741 }
2742
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002743 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002744 public void onAnimationToSideEnded() {
2745 mIsLaunchTransitionRunning = false;
2746 mIsLaunchTransitionFinished = true;
2747 if (mLaunchAnimationEndRunnable != null) {
2748 mLaunchAnimationEndRunnable.run();
2749 mLaunchAnimationEndRunnable = null;
2750 }
Jorim Jaggife762342016-10-13 14:33:27 +02002751 mStatusBar.readyForKeyguardDone();
Selim Cinekbaa23272014-07-08 18:01:07 +02002752 }
2753
2754 @Override
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002755 protected void startUnlockHintAnimation() {
Selim Cineke64f52a2017-08-24 14:48:38 -07002756 if (mPowerManager.isPowerSaveMode()) {
2757 onUnlockHintStarted();
2758 onUnlockHintFinished();
2759 return;
2760 }
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002761 super.startUnlockHintAnimation();
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02002762 }
2763
2764 @Override
Selim Cinek6746c282015-04-21 19:58:31 -07002765 public float getMaxTranslationDistance() {
2766 return (float) Math.hypot(getWidth(), getHeight());
Selim Cinek4c6969a2014-05-26 19:22:17 +02002767 }
2768
2769 @Override
Jorim Jaggid9449862015-05-29 14:49:08 -07002770 public void onSwipingStarted(boolean rightIcon) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002771 mFalsingManager.onAffordanceSwipingStarted(rightIcon);
Jorim Jaggid9449862015-05-29 14:49:08 -07002772 boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon
2773 : rightIcon;
2774 if (camera) {
Jorim Jaggid9449862015-05-29 14:49:08 -07002775 mKeyguardBottomArea.bindCameraPrewarmService();
Jorim Jaggia86790b2015-04-02 16:32:29 -07002776 }
Selim Cinekbaa23272014-07-08 18:01:07 +02002777 requestDisallowInterceptTouchEvent(true);
2778 mOnlyAffordanceInThisMotion = true;
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002779 mQsTracking = false;
Selim Cinek4c6969a2014-05-26 19:22:17 +02002780 }
2781
2782 @Override
Jorim Jaggia86790b2015-04-02 16:32:29 -07002783 public void onSwipingAborted() {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002784 mFalsingManager.onAffordanceSwipingAborted();
Jorim Jaggid9449862015-05-29 14:49:08 -07002785 mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
Jorim Jaggia86790b2015-04-02 16:32:29 -07002786 }
2787
2788 @Override
Selim Cinek6746c282015-04-21 19:58:31 -07002789 public void onIconClicked(boolean rightIcon) {
2790 if (mHintAnimationRunning) {
2791 return;
2792 }
2793 mHintAnimationRunning = true;
Adrian Roose31f30e2017-01-25 14:48:15 -08002794 mAffordanceHelper.startHintAnimation(rightIcon, new Runnable() {
Selim Cinek6746c282015-04-21 19:58:31 -07002795 @Override
2796 public void run() {
2797 mHintAnimationRunning = false;
2798 mStatusBar.onHintFinished();
2799 }
2800 });
2801 rightIcon = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon : rightIcon;
2802 if (rightIcon) {
2803 mStatusBar.onCameraHintStarted();
2804 } else {
Selim Cineke70d6532015-04-24 16:46:13 -07002805 if (mKeyguardBottomArea.isLeftVoiceAssist()) {
2806 mStatusBar.onVoiceAssistHintStarted();
2807 } else {
2808 mStatusBar.onPhoneHintStarted();
2809 }
Selim Cinek6746c282015-04-21 19:58:31 -07002810 }
2811 }
2812
2813 @Override
Selim Cinekec29d342017-05-05 18:31:49 -07002814 protected void onUnlockHintFinished() {
2815 super.onUnlockHintFinished();
2816 mNotificationStackScroller.setUnlockHintRunning(false);
2817 }
2818
2819 @Override
2820 protected void onUnlockHintStarted() {
2821 super.onUnlockHintStarted();
2822 mNotificationStackScroller.setUnlockHintRunning(true);
2823 }
2824
2825 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002826 public KeyguardAffordanceView getLeftIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002827 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002828 ? mKeyguardBottomArea.getRightView()
2829 : mKeyguardBottomArea.getLeftView();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002830 }
2831
2832 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02002833 public KeyguardAffordanceView getRightIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02002834 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002835 ? mKeyguardBottomArea.getLeftView()
2836 : mKeyguardBottomArea.getRightView();
Selim Cinek4c6969a2014-05-26 19:22:17 +02002837 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002838
2839 @Override
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02002840 public View getLeftPreview() {
2841 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002842 ? mKeyguardBottomArea.getRightPreview()
2843 : mKeyguardBottomArea.getLeftPreview();
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02002844 }
2845
2846 @Override
2847 public View getRightPreview() {
2848 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cineke70d6532015-04-24 16:46:13 -07002849 ? mKeyguardBottomArea.getLeftPreview()
2850 : mKeyguardBottomArea.getRightPreview();
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02002851 }
2852
2853 @Override
Selim Cinek34cf5c42014-09-26 15:39:00 +02002854 public float getAffordanceFalsingFactor() {
Jorim Jaggi50ff3af2015-08-12 18:35:42 -07002855 return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
Selim Cinek34cf5c42014-09-26 15:39:00 +02002856 }
2857
2858 @Override
Adrian Roos6a70b882016-04-19 17:09:07 -07002859 public boolean needsAntiFalsing() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002860 return mBarState == StatusBarState.KEYGUARD;
Adrian Roos6a70b882016-04-19 17:09:07 -07002861 }
2862
2863 @Override
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002864 protected float getPeekHeight() {
2865 if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
2866 return mNotificationStackScroller.getPeekHeight();
2867 } else {
Selim Cinek94c2d822016-07-13 18:50:04 -07002868 return mQsMinExpansionHeight;
Jorim Jaggi2580a9762014-06-25 03:08:25 +02002869 }
2870 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002871
2872 @Override
Selim Cinek2411f762016-12-28 17:05:08 +01002873 protected boolean shouldUseDismissingAnimation() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002874 return mBarState != StatusBarState.SHADE
Lucas Dupinc8f16e82019-09-17 18:24:50 -04002875 && (mKeyguardStateController.canDismissLockScreen() || !isTracking());
Selim Cinek2411f762016-12-28 17:05:08 +01002876 }
2877
2878 @Override
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002879 protected boolean fullyExpandedClearAllVisible() {
Julia Reynoldsed1c9af2018-03-21 15:21:09 -04002880 return mNotificationStackScroller.isFooterViewNotGone()
Jason Monk3c68ca22015-01-30 11:30:29 -05002881 && mNotificationStackScroller.isScrolledToBottom() && !mQsExpandImmediate;
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002882 }
2883
2884 @Override
2885 protected boolean isClearAllVisible() {
Selim Cinek38475442018-05-18 11:11:46 -07002886 return mNotificationStackScroller.isFooterViewContentVisible();
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002887 }
2888
2889 @Override
2890 protected int getClearAllHeight() {
Julia Reynoldsed1c9af2018-03-21 15:21:09 -04002891 return mNotificationStackScroller.getFooterViewHeight();
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02002892 }
2893
2894 @Override
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002895 protected boolean isTrackingBlocked() {
Lucas Dupind61974d2019-03-29 16:09:26 -07002896 return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
Jorim Jaggi30c305c2014-07-01 23:34:41 +02002897 }
Jorim Jaggi54045422014-07-03 18:30:40 +02002898
Jorim Jaggibd003102014-07-04 00:02:42 +02002899 public boolean isQsExpanded() {
2900 return mQsExpanded;
2901 }
Jorim Jaggi853b0702014-07-05 04:31:14 +02002902
John Spurlockf7ae4422014-08-01 12:45:18 -04002903 public boolean isQsDetailShowing() {
Jason Monk0ceef212016-11-02 14:05:23 -04002904 return mQs.isShowingDetail();
John Spurlockf7ae4422014-08-01 12:45:18 -04002905 }
2906
2907 public void closeQsDetail() {
Jason Monk0ceef212016-11-02 14:05:23 -04002908 mQs.closeDetail();
John Spurlockf7ae4422014-08-01 12:45:18 -04002909 }
2910
Jorim Jaggi853b0702014-07-05 04:31:14 +02002911 @Override
2912 public boolean shouldDelayChildPressedState() {
2913 return true;
2914 }
Selim Cinekbaa23272014-07-08 18:01:07 +02002915
2916 public boolean isLaunchTransitionFinished() {
2917 return mIsLaunchTransitionFinished;
2918 }
2919
2920 public boolean isLaunchTransitionRunning() {
2921 return mIsLaunchTransitionRunning;
2922 }
2923
2924 public void setLaunchTransitionEndRunnable(Runnable r) {
2925 mLaunchAnimationEndRunnable = r;
2926 }
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02002927
2928 public void setEmptyDragAmount(float amount) {
Lucas Dupin55c6e802018-09-27 18:07:36 -07002929 mEmptyDragAmount = amount * 0.2f;
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02002930 positionClockAndNotifications();
2931 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02002932
Jorim Jaggi0e0942d2015-06-05 14:12:20 -07002933 private void updateDozingVisibilities(boolean animate) {
Lucas Dupin7da4f262018-09-20 13:41:46 -07002934 mKeyguardBottomArea.setDozing(mDozing, animate);
Lucas Dupin07ed3df2019-03-26 21:23:59 -07002935 if (!mDozing && animate) {
2936 animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
2937 }
John Spurlockd54da8a2014-08-03 23:23:52 -04002938 }
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002939
Jorim Jaggid7912d22014-09-30 17:38:19 +02002940 @Override
John Spurlockcf5d3c92014-09-21 17:55:01 -04002941 public boolean isDozing() {
2942 return mDozing;
2943 }
2944
Selim Cinek24176c32017-03-01 16:50:30 -08002945 public void showEmptyShadeView(boolean emptyShadeViewVisible) {
2946 mShowEmptyShadeView = emptyShadeViewVisible;
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002947 updateEmptyShadeView();
2948 }
2949
2950 private void updateEmptyShadeView() {
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002951 // Hide "No notifications" in QS.
Selim Cinek24176c32017-03-01 16:50:30 -08002952 mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
Jorim Jaggia2052ea2014-08-05 16:22:30 +02002953 }
Jorim Jaggidd5b8862014-08-05 21:04:39 +02002954
2955 public void setQsScrimEnabled(boolean qsScrimEnabled) {
2956 boolean changed = mQsScrimEnabled != qsScrimEnabled;
2957 mQsScrimEnabled = qsScrimEnabled;
2958 if (changed) {
2959 updateQsState();
2960 }
2961 }
John Spurlock7e6809a2014-08-06 16:03:14 -04002962
Jorim Jaggibf1899e2014-08-07 02:04:18 +02002963 public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
2964 mKeyguardUserSwitcher = keyguardUserSwitcher;
2965 }
2966
Jorim Jaggi93739112015-08-13 15:53:14 -07002967 public void onScreenTurningOn() {
Lucas Dupin9fedb892018-05-04 17:42:33 -07002968 mKeyguardStatusView.dozeTimeTick();
Jorim Jaggid09def7512014-09-02 18:36:45 +02002969 }
Selim Cinek3a9c10a2014-10-28 14:21:10 +01002970
2971 @Override
2972 public void onEmptySpaceClicked(float x, float y) {
2973 onEmptySpaceClick(x);
2974 }
Jorim Jaggi58bef332014-11-21 18:10:32 +01002975
Jim Miller07e03842016-06-22 15:18:13 -07002976 @Override
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002977 protected boolean onMiddleClicked() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04002978 switch (mBarState) {
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002979 case StatusBarState.KEYGUARD:
2980 if (!mDozingOnDown) {
Lucas Dupin6e383882019-06-25 09:46:59 -07002981 if (mKeyguardBypassController.getBypassEnabled()) {
2982 mUpdateMonitor.requestFaceAuth();
2983 } else {
2984 mLockscreenGestureLogger.write(
2985 MetricsEvent.ACTION_LS_HINT,
2986 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
2987 startUnlockHintAnimation();
2988 }
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002989 }
2990 return true;
2991 case StatusBarState.SHADE_LOCKED:
2992 if (!mQsExpanded) {
Jason Monk297c04e2018-08-23 17:16:59 -04002993 mShadeController.goToKeyguard();
Jorim Jaggi1cf6e102015-01-20 16:45:05 +01002994 }
2995 return true;
2996 case StatusBarState.SHADE:
2997
2998 // This gets called in the middle of the touch handling, where the state is still
2999 // that we are tracking the panel. Collapse the panel after this is done.
3000 post(mPostCollapseRunnable);
3001 return false;
3002 default:
3003 return true;
3004 }
3005 }
3006
Jorim Jaggi58bef332014-11-21 18:10:32 +01003007 @Override
shawnlin4ef7ca52018-05-11 16:44:42 +08003008 protected void dispatchDraw(Canvas canvas) {
3009 super.dispatchDraw(canvas);
3010 if (mCurrentPanelAlpha != 255) {
3011 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
3012 }
3013 }
3014
3015 public float getCurrentPanelAlpha() {
3016 return mCurrentPanelAlpha;
3017 }
3018
3019 public boolean setPanelAlpha(int alpha, boolean animate) {
3020 if (mPanelAlpha != alpha) {
3021 mPanelAlpha = alpha;
3022 PropertyAnimator.setProperty(this, PANEL_ALPHA, alpha,
3023 alpha == 255 ? PANEL_ALPHA_IN_PROPERTIES : PANEL_ALPHA_OUT_PROPERTIES, animate);
3024 return true;
3025 }
3026 return false;
3027 }
3028
3029 public void setPanelAlphaInternal(float alpha) {
3030 mCurrentPanelAlpha = (int) alpha;
3031 mAlphaPaint.setARGB(mCurrentPanelAlpha, 255, 255, 255);
3032 invalidate();
3033 }
3034
3035 public void setPanelAlphaEndAction(Runnable r) {
3036 mPanelAlphaEndAction = r;
3037 }
3038
3039 @Override
Lucas Dupin41ff6952018-02-18 19:39:32 -08003040 protected void onDraw(Canvas canvas) {
3041 super.onDraw(canvas);
3042
Jorim Jaggi58bef332014-11-21 18:10:32 +01003043 if (DEBUG) {
3044 Paint p = new Paint();
3045 p.setColor(Color.RED);
3046 p.setStrokeWidth(2);
3047 p.setStyle(Paint.Style.STROKE);
3048 canvas.drawLine(0, getMaxPanelHeight(), getWidth(), getMaxPanelHeight(), p);
3049 p.setColor(Color.BLUE);
3050 canvas.drawLine(0, getExpandedHeight(), getWidth(), getExpandedHeight(), p);
3051 p.setColor(Color.GREEN);
3052 canvas.drawLine(0, calculatePanelHeightQsExpanded(), getWidth(),
3053 calculatePanelHeightQsExpanded(), p);
3054 p.setColor(Color.YELLOW);
3055 canvas.drawLine(0, calculatePanelHeightShade(), getWidth(),
3056 calculatePanelHeightShade(), p);
3057 p.setColor(Color.MAGENTA);
3058 canvas.drawLine(0, calculateQsTopPadding(), getWidth(),
3059 calculateQsTopPadding(), p);
3060 p.setColor(Color.CYAN);
Lucas Dupin60661a62018-04-12 10:50:13 -07003061 canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, getWidth(),
Jorim Jaggi58bef332014-11-21 18:10:32 +01003062 mNotificationStackScroller.getTopPadding(), p);
Lucas Dupin60661a62018-04-12 10:50:13 -07003063 p.setColor(Color.GRAY);
3064 canvas.drawLine(0, mClockPositionResult.clockY, getWidth(),
3065 mClockPositionResult.clockY, p);
Jorim Jaggi58bef332014-11-21 18:10:32 +01003066 }
3067 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003068
3069 @Override
John Spurlockb349af572015-04-29 12:24:19 -04003070 public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07003071 mNotificationStackScroller.setInHeadsUpPinnedMode(inPinnedMode);
Selim Cinek684a4422015-04-15 16:18:39 -07003072 if (inPinnedMode) {
3073 mHeadsUpExistenceChangedRunnable.run();
3074 updateNotificationTranslucency();
3075 } else {
Selim Cinekcafa87f2016-10-26 17:00:17 -07003076 setHeadsUpAnimatingAway(true);
Selim Cinek684a4422015-04-15 16:18:39 -07003077 mNotificationStackScroller.runAfterAnimationFinished(
3078 mHeadsUpExistenceChangedRunnable);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003079 }
Winson Chung9cd21152019-05-28 15:04:08 -07003080 updateGestureExclusionRect();
Selim Cinekd21232e2019-06-20 14:15:59 -07003081 mHeadsUpPinnedMode = inPinnedMode;
3082 updateHeadsUpVisibility();
Selim Cinekc7e4cb52019-06-20 15:41:45 -07003083 updateKeyguardStatusBarForHeadsUp();
3084 }
3085
3086 private void updateKeyguardStatusBarForHeadsUp() {
3087 boolean showingKeyguardHeadsUp = mKeyguardShowing
3088 && mHeadsUpAppearanceController.shouldBeVisible();
3089 if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
3090 mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
3091 if (mKeyguardShowing) {
3092 PropertyAnimator.setProperty(this, KEYGUARD_HEADS_UP_SHOWING_AMOUNT,
3093 showingKeyguardHeadsUp ? 1.0f : 0.0f, KEYGUARD_HUN_PROPERTIES,
3094 true /* animate */);
3095 } else {
3096 PropertyAnimator.applyImmediately(this, KEYGUARD_HEADS_UP_SHOWING_AMOUNT, 0.0f);
3097 }
3098 }
3099 }
3100
3101 private void setKeyguardHeadsUpShowingAmount(float amount) {
3102 mKeyguardHeadsUpShowingAmount = amount;
3103 updateHeaderKeyguardAlpha();
3104 }
3105
3106 private float getKeyguardHeadsUpShowingAmount() {
3107 return mKeyguardHeadsUpShowingAmount;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003108 }
3109
Selim Cinekcafa87f2016-10-26 17:00:17 -07003110 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
3111 mHeadsUpAnimatingAway = headsUpAnimatingAway;
3112 mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinekd21232e2019-06-20 14:15:59 -07003113 updateHeadsUpVisibility();
3114 }
3115
3116 private void updateHeadsUpVisibility() {
3117 ((PhoneStatusBarView) mBar).setHeadsUpVisible(mHeadsUpAnimatingAway || mHeadsUpPinnedMode);
Selim Cinekcafa87f2016-10-26 17:00:17 -07003118 }
3119
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003120 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -05003121 public void onHeadsUpPinned(NotificationEntry entry) {
Selim Cinekd21232e2019-06-20 14:15:59 -07003122 if (!isOnKeyguard()) {
3123 mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(),
3124 true);
3125 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07003126 }
3127
3128 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -05003129 public void onHeadsUpUnPinned(NotificationEntry entry) {
Selim Cineka303a642018-03-08 21:24:55 -08003130
3131 // When we're unpinning the notification via active edge they remain heads-upped,
3132 // we need to make sure that an animation happens in this case, otherwise the notification
3133 // will stick to the top without any interaction.
Selim Cinekd21232e2019-06-20 14:15:59 -07003134 if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) {
Evan Laird94492852018-10-25 13:43:01 -04003135 mNotificationStackScroller.generateHeadsUpAnimation(
3136 entry.getHeadsUpAnimationView(), false);
3137 entry.setHeadsUpIsVisible();
Selim Cineka303a642018-03-08 21:24:55 -08003138 }
Selim Cinek684a4422015-04-15 16:18:39 -07003139 }
3140
3141 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -05003142 public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
Evan Laird94492852018-10-25 13:43:01 -04003143 mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003144 }
3145
Selim Cineka59ecc32015-04-07 10:51:49 -07003146 @Override
yoshiki iguchi4e30e762018-02-06 12:09:23 +09003147 public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003148 super.setHeadsUpManager(headsUpManager);
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -04003149 mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager,
3150 mNotificationStackScroller.getHeadsUpCallback(), this);
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003151 }
3152
Selim Cinekaa9db1f2018-02-27 17:35:47 -08003153 public void setTrackedHeadsUp(ExpandableNotificationRow pickedChild) {
3154 if (pickedChild != null) {
3155 notifyListenersTrackingHeadsUp(pickedChild);
Selim Cinekd2281152015-04-10 14:37:46 -07003156 mExpandingFromHeadsUp = true;
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003157 }
Selim Cinek684a4422015-04-15 16:18:39 -07003158 // otherwise we update the state when the expansion is finished
Selim Cinekb8f09cf2015-03-16 17:09:28 -07003159 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003160
3161 @Override
3162 protected void onClosingFinished() {
3163 super.onClosingFinished();
Lucas Dupinb46d0a22019-01-11 16:57:16 -08003164 resetHorizontalPanelPosition();
Selim Cinekbbc580b2015-06-03 14:11:03 +02003165 setClosingWithAlphaFadeout(false);
3166 }
3167
3168 private void setClosingWithAlphaFadeout(boolean closing) {
3169 mClosingWithAlphaFadeOut = closing;
3170 mNotificationStackScroller.forceNoOverlappingRendering(closing);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003171 }
3172
3173 /**
3174 * Updates the vertical position of the panel so it is positioned closer to the touch
3175 * responsible for opening the panel.
3176 *
3177 * @param x the x-coordinate the touch event
3178 */
Xiaohui Chen9528f432016-02-12 15:03:18 -08003179 protected void updateVerticalPanelPosition(float x) {
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003180 if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
Lucas Dupinb46d0a22019-01-11 16:57:16 -08003181 resetHorizontalPanelPosition();
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003182 return;
3183 }
3184 float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2;
3185 float rightMost = getWidth() - mPositionMinSideMargin
3186 - mNotificationStackScroller.getWidth() / 2;
3187 if (Math.abs(x - getWidth() / 2) < mNotificationStackScroller.getWidth() / 4) {
3188 x = getWidth() / 2;
3189 }
3190 x = Math.min(rightMost, Math.max(leftMost, x));
Lucas Dupinb46d0a22019-01-11 16:57:16 -08003191 float center =
3192 mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2;
3193 setHorizontalPanelTranslation(x - center);
Dave Mankoffc88d6222018-10-25 15:31:20 -04003194 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003195
Lucas Dupinb46d0a22019-01-11 16:57:16 -08003196 private void resetHorizontalPanelPosition() {
3197 setHorizontalPanelTranslation(0f);
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003198 }
3199
Lucas Dupinb46d0a22019-01-11 16:57:16 -08003200 protected void setHorizontalPanelTranslation(float translation) {
Selim Cinekc7e4cb52019-06-20 15:41:45 -07003201 mNotificationStackScroller.setTranslationX(translation);
Jason Monk0ceef212016-11-02 14:05:23 -04003202 mQsFrame.setTranslationX(translation);
Selim Cinek60ffea62018-03-22 13:16:44 -07003203 int size = mVerticalTranslationListener.size();
3204 for (int i = 0; i < size; i++) {
3205 mVerticalTranslationListener.get(i).run();
Selim Cinek332c23f2018-03-16 17:37:50 -07003206 }
Jorim Jaggi6d4a27f2015-04-20 16:01:53 -07003207 }
Xiyuan Xiab3a6f1e2015-04-28 16:17:18 -07003208
Selim Cinekbc243a92016-09-27 16:35:13 -07003209 protected void updateExpandedHeight(float expandedHeight) {
Selim Cinekd5ab6452016-12-08 16:34:00 -08003210 if (mTracking) {
3211 mNotificationStackScroller.setExpandingVelocity(getCurrentExpandVelocity());
3212 }
Selim Cinekb0fada62019-06-17 19:03:59 -07003213 if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
3214 // The expandedHeight is always the full panel Height when bypassing
3215 expandedHeight = getMaxPanelHeightNonBypass();
3216 }
Selim Cinekbc243a92016-09-27 16:35:13 -07003217 mNotificationStackScroller.setExpandedHeight(expandedHeight);
Xiyuan Xiab3a6f1e2015-04-28 16:17:18 -07003218 updateKeyguardBottomAreaAlpha();
Robert Snoeberger80f19a32019-02-13 09:40:11 -05003219 updateBigClockAlpha();
Selim Cinek24176c32017-03-01 16:50:30 -08003220 updateStatusBarIcons();
Selim Cinekfcff4c62016-12-27 14:26:06 +01003221 }
3222
3223 /**
3224 * @return whether the notifications are displayed full width and don't have any margins on
3225 * the side.
3226 */
3227 public boolean isFullWidth() {
3228 return mIsFullWidth;
Selim Cinek48ff9b42016-11-09 19:31:51 -08003229 }
3230
Selim Cinek24176c32017-03-01 16:50:30 -08003231 private void updateStatusBarIcons() {
felkachangca4eee82018-06-29 15:34:28 +08003232 boolean showIconsWhenExpanded = (isPanelVisibleBecauseOfHeadsUp() || isFullWidth())
3233 && getExpandedHeight() < getOpeningHeight();
Selim Cinek24176c32017-03-01 16:50:30 -08003234 if (showIconsWhenExpanded && mNoVisibleNotifications && isOnKeyguard()) {
3235 showIconsWhenExpanded = false;
3236 }
3237 if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
3238 mShowIconsWhenExpanded = showIconsWhenExpanded;
Charles Chenf3d295c2018-11-30 18:15:21 +08003239 mCommandQueue.recomputeDisableFlags(mDisplayId, false);
Selim Cinek48ff9b42016-11-09 19:31:51 -08003240 }
Xiyuan Xiab3a6f1e2015-04-28 16:17:18 -07003241 }
Selim Cinek3d395c62015-06-16 19:37:37 -07003242
Selim Cinek24176c32017-03-01 16:50:30 -08003243 private boolean isOnKeyguard() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04003244 return mBarState == StatusBarState.KEYGUARD;
Selim Cinek24176c32017-03-01 16:50:30 -08003245 }
3246
Selim Cinek3d395c62015-06-16 19:37:37 -07003247 public void setPanelScrimMinFraction(float minFraction) {
3248 mBar.panelScrimMinFractionChanged(minFraction);
3249 }
Chris Wren16895942015-06-23 11:22:20 -04003250
Xiaohui Chen9528f432016-02-12 15:03:18 -08003251 public void clearNotificationEffects() {
Chris Wren16895942015-06-23 11:22:20 -04003252 mStatusBar.clearNotificationEffects();
3253 }
Selim Cinek0fccc722015-07-29 17:04:36 -07003254
Jim Miller07e03842016-06-22 15:18:13 -07003255 @Override
Selim Cinek0fccc722015-07-29 17:04:36 -07003256 protected boolean isPanelVisibleBecauseOfHeadsUp() {
Selim Cinekd21232e2019-06-20 14:15:59 -07003257 return (mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway)
3258 && mBarState == StatusBarState.SHADE;
Selim Cinek0fccc722015-07-29 17:04:36 -07003259 }
Jorim Jaggi90978852015-08-18 19:55:53 -07003260
3261 @Override
3262 public boolean hasOverlappingRendering() {
3263 return !mDozing;
3264 }
Selim Cinek372d1bd2015-08-14 13:19:37 -07003265
Jorim Jaggi40aa8812015-09-23 12:59:22 -07003266 public void launchCamera(boolean animate, int source) {
3267 if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
3268 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
3269 } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
3270 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
Jonathan Solnita4138162017-05-10 21:06:04 -07003271 } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER) {
3272 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER;
Jorim Jaggi40aa8812015-09-23 12:59:22 -07003273 } else {
3274
3275 // Default.
3276 mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
3277 }
3278
Selim Cinek372d1bd2015-08-14 13:19:37 -07003279 // If we are launching it when we are occluded already we don't want it to animate,
3280 // nor setting these flags, since the occluded state doesn't change anymore, hence it's
3281 // never reset.
3282 if (!isFullyCollapsed()) {
Selim Cinek372d1bd2015-08-14 13:19:37 -07003283 setLaunchingAffordance(true);
3284 } else {
3285 animate = false;
3286 }
Lucas Dupin193677c2018-06-11 19:16:03 -07003287 mAffordanceHasPreview = mKeyguardBottomArea.getRightPreview() != null;
Adrian Roose31f30e2017-01-25 14:48:15 -08003288 mAffordanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
Selim Cinek372d1bd2015-08-14 13:19:37 -07003289 }
3290
3291 public void onAffordanceLaunchEnded() {
Selim Cinek372d1bd2015-08-14 13:19:37 -07003292 setLaunchingAffordance(false);
3293 }
3294
3295 /**
3296 * Set whether we are currently launching an affordance. This is currently only set when
3297 * launched via a camera gesture.
3298 */
3299 private void setLaunchingAffordance(boolean launchingAffordance) {
Selim Cinekec177752019-06-19 18:13:51 -07003300 mLaunchingAffordance = launchingAffordance;
Selim Cinek372d1bd2015-08-14 13:19:37 -07003301 getLeftIcon().setLaunchingAffordance(launchingAffordance);
3302 getRightIcon().setLaunchingAffordance(launchingAffordance);
Selim Cinekec177752019-06-19 18:13:51 -07003303 mKeyguardBypassController.setLaunchingAffordance(launchingAffordance);
Lucas Dupin23964c72019-05-21 16:12:45 -07003304 if (mAffordanceLaunchListener != null) {
3305 mAffordanceLaunchListener.accept(launchingAffordance);
3306 }
Selim Cinek372d1bd2015-08-14 13:19:37 -07003307 }
3308
Zhentao Sun04f97402015-08-26 17:37:30 -07003309 /**
Lucas Dupin193677c2018-06-11 19:16:03 -07003310 * Return true when a bottom affordance is launching an occluded activity with a splash screen.
3311 */
3312 public boolean isLaunchingAffordanceWithPreview() {
3313 return mLaunchingAffordance && mAffordanceHasPreview;
3314 }
3315
3316 /**
Zhentao Sun04f97402015-08-26 17:37:30 -07003317 * Whether the camera application can be launched for the camera launch gesture.
Zhentao Sun04f97402015-08-26 17:37:30 -07003318 */
Lucas Dupinb928a872019-07-31 13:33:01 -07003319 public boolean canCameraGestureBeLaunched() {
Esteban Talavera40f8b992017-07-14 16:14:07 +01003320 if (!mStatusBar.isCameraAllowedByAdmin()) {
3321 return false;
3322 }
3323
Zhentao Sun04f97402015-08-26 17:37:30 -07003324 ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
3325 String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
3326 ? null : resolveInfo.activityInfo.packageName;
3327 return packageToLaunch != null &&
Lucas Dupinb928a872019-07-31 13:33:01 -07003328 (mBarState != StatusBarState.SHADE || !isForegroundApp(packageToLaunch))
Dave Mankoffc88d6222018-10-25 15:31:20 -04003329 && !mAffordanceHelper.isSwipingInProgress();
Zhentao Sun04f97402015-08-26 17:37:30 -07003330 }
3331
3332 /**
3333 * Return true if the applications with the package name is running in foreground.
3334 *
3335 * @param pkgName application package name.
3336 */
3337 private boolean isForegroundApp(String pkgName) {
3338 ActivityManager am = getContext().getSystemService(ActivityManager.class);
3339 List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
3340 return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
Selim Cinek372d1bd2015-08-14 13:19:37 -07003341 }
Selim Cinek53f8e7d2016-03-25 02:28:01 -07003342
Jason Monke59dc402018-08-16 12:05:01 -04003343 private void setGroupManager(NotificationGroupManager groupManager) {
Selim Cinek53f8e7d2016-03-25 02:28:01 -07003344 mGroupManager = groupManager;
3345 }
Jason Monk0ceef212016-11-02 14:05:23 -04003346
Selim Cinek24176c32017-03-01 16:50:30 -08003347 public boolean hideStatusBarIconsWhenExpanded() {
Selim Cinek2627d722018-01-19 12:16:49 -08003348 if (mLaunchingNotification) {
3349 return mHideIconsDuringNotificationLaunch;
3350 }
Selim Cinek332c23f2018-03-16 17:37:50 -07003351 if (mHeadsUpAppearanceController != null
3352 && mHeadsUpAppearanceController.shouldBeVisible()) {
3353 return false;
3354 }
Selim Cinek24176c32017-03-01 16:50:30 -08003355 return !isFullWidth() || !mShowIconsWhenExpanded;
Selim Cinek48ff9b42016-11-09 19:31:51 -08003356 }
3357
Jason Monk0ceef212016-11-02 14:05:23 -04003358 private final FragmentListener mFragmentListener = new FragmentListener() {
3359 @Override
3360 public void onFragmentViewCreated(String tag, Fragment fragment) {
3361 mQs = (QS) fragment;
3362 mQs.setPanelView(NotificationPanelView.this);
Jason Monke5b770e2017-03-03 21:49:29 -05003363 mQs.setExpandClickListener(NotificationPanelView.this);
Jason Monk0ceef212016-11-02 14:05:23 -04003364 mQs.setHeaderClickable(mQsExpansionEnabled);
Selim Cinekb0fada62019-06-17 19:03:59 -07003365 updateQSPulseExpansion();
Jason Monk0ceef212016-11-02 14:05:23 -04003366 mQs.setOverscrolling(mStackScrollerOverscrolling);
3367
3368 // recompute internal state when qspanel height changes
3369 mQs.getView().addOnLayoutChangeListener(
3370 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
3371 final int height = bottom - top;
3372 final int oldHeight = oldBottom - oldTop;
3373 if (height != oldHeight) {
3374 onQsHeightChanged();
3375 }
3376 });
3377 mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
Lucas Dupin7da4f262018-09-20 13:41:46 -07003378 if (mQs instanceof QSFragment) {
3379 mKeyguardStatusBar.setQSPanel(((QSFragment) mQs).getQsPanel());
3380 }
Jason Monk0ceef212016-11-02 14:05:23 -04003381 updateQsExpansion();
3382 }
3383
3384 @Override
3385 public void onFragmentViewDestroyed(String tag, Fragment fragment) {
3386 // Manual handling of fragment lifecycle is only required because this bridges
3387 // non-fragment and fragment code. Once we are using a fragment for the notification
3388 // panel, mQs will not need to be null cause it will be tied to the same lifecycle.
3389 if (fragment == mQs) {
3390 mQs = null;
3391 }
3392 }
3393 };
Adrian Roosc934c432017-01-13 11:44:56 -08003394
Selim Cinek2c2f0e22017-05-02 20:02:30 -07003395 @Override
Jason Monke59dc402018-08-16 12:05:01 -04003396 public void setTouchAndAnimationDisabled(boolean disabled) {
3397 super.setTouchAndAnimationDisabled(disabled);
Selim Cinek2c2f0e22017-05-02 20:02:30 -07003398 if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
Selim Cinekc5fec9a2017-07-05 16:22:53 +02003399 mAffordanceHelper.reset(false /* animate */);
Selim Cinek2c2f0e22017-05-02 20:02:30 -07003400 }
Jason Monke59dc402018-08-16 12:05:01 -04003401 mNotificationStackScroller.setAnimationsEnabled(!disabled);
Selim Cinek2c2f0e22017-05-02 20:02:30 -07003402 }
3403
Lucas Dupinc7804042018-12-21 12:26:33 -08003404 /**
3405 * Sets the dozing state.
3406 *
3407 * @param dozing {@code true} when dozing.
3408 * @param animate if transition should be animated.
3409 * @param wakeUpTouchLocation touch event location - if woken up by SLPI sensor.
3410 */
3411 public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation) {
Lucas Dupin16cfe452018-02-08 13:14:50 -08003412 if (dozing == mDozing) return;
3413 mDozing = dozing;
Selim Cinekc1d9ab22019-05-21 18:08:30 -07003414 mNotificationStackScroller.setDozing(mDozing, animate, wakeUpTouchLocation);
Lucas Dupin07ed3df2019-03-26 21:23:59 -07003415 mKeyguardBottomArea.setDozing(mDozing, animate);
Lucas Dupin16cfe452018-02-08 13:14:50 -08003416
Lucas Dupin5778eb02019-06-05 17:50:48 -07003417 if (dozing) {
3418 mBottomAreaShadeAlphaAnimator.cancel();
3419 }
3420
Jason Monk1fd3fc32018-08-14 17:20:09 -04003421 if (mBarState == StatusBarState.KEYGUARD
3422 || mBarState == StatusBarState.SHADE_LOCKED) {
Lucas Dupin16cfe452018-02-08 13:14:50 -08003423 updateDozingVisibilities(animate);
Adrian Roos52414e32017-04-28 09:23:19 -07003424 }
Lucas Dupin16cfe452018-02-08 13:14:50 -08003425
Selim Cinekc1d9ab22019-05-21 18:08:30 -07003426 final float dozeAmount = dozing ? 1 : 0;
3427 mStatusBarStateController.setDozeAmount(dozeAmount, animate);
Adrian Roos52414e32017-04-28 09:23:19 -07003428 }
3429
Lucas Dupin1a8b33d2018-11-12 18:18:15 -08003430 @Override
3431 public void onDozeAmountChanged(float linearAmount, float amount) {
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02003432 mInterpolatedDarkAmount = amount;
3433 mLinearDarkAmount = linearAmount;
3434 mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount);
3435 mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
Adrian Roosc934c432017-01-13 11:44:56 -08003436 positionClockAndNotifications();
3437 }
Selim Cinek24176c32017-03-01 16:50:30 -08003438
yoshiki iguchi4e30e762018-02-06 12:09:23 +09003439 public void setPulsing(boolean pulsing) {
Lucas Dupin56057342018-04-10 11:49:18 -07003440 mPulsing = pulsing;
Dave Mankoff2aff6c32019-10-14 17:40:37 -04003441 final boolean animatePulse = !mDozeParameters.getDisplayNeedsBlanking()
3442 && mDozeParameters.getAlwaysOn();
Lucas Dupin2a6bdfd2018-06-12 17:45:21 -07003443 if (animatePulse) {
Lucas Dupin3d7ccaf2018-04-02 21:19:23 -07003444 mAnimateNextPositionUpdate = true;
3445 }
Lucas Dupine132e022019-01-03 10:07:03 -08003446 // Do not animate the clock when waking up from a pulse.
3447 // The height callback will take care of pushing the clock to the right position.
3448 if (!mPulsing && !mDozing) {
3449 mAnimateNextPositionUpdate = false;
3450 }
Lucas Dupin2a6bdfd2018-06-12 17:45:21 -07003451 mNotificationStackScroller.setPulsing(pulsing, animatePulse);
Lucas Dupin00be88f2019-01-03 17:50:52 -08003452 mKeyguardStatusView.setPulsing(pulsing);
Adrian Roosd83e9992017-03-16 15:17:57 -07003453 }
Adrian Roos75fa9642017-04-18 11:34:56 -07003454
3455 public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
3456 if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
3457 mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
3458 mStatusBar.updateKeyguardMaxNotifications();
3459 }
3460 }
Lucas Dupin987f1932017-05-13 21:02:52 -07003461
Lucas Dupin4272f442018-01-13 22:00:35 -08003462 public void dozeTimeTick() {
Lucas Dupin07ed3df2019-03-26 21:23:59 -07003463 mKeyguardBottomArea.dozeTimeTick();
Lucas Dupin9fedb892018-05-04 17:42:33 -07003464 mKeyguardStatusView.dozeTimeTick();
Jorim Jaggic4cf07a2018-07-05 18:28:12 +02003465 if (mInterpolatedDarkAmount > 0) {
Adrian Roos4fc6de82017-06-01 16:09:15 -07003466 positionClockAndNotifications();
3467 }
Lucas Dupin987f1932017-05-13 21:02:52 -07003468 }
3469
3470 public void setStatusAccessibilityImportance(int mode) {
Dave Mankoffc88d6222018-10-25 15:31:20 -04003471 mKeyguardStatusView.setImportantForAccessibility(mode);
Lucas Dupin987f1932017-05-13 21:02:52 -07003472 }
3473
3474 /**
3475 * TODO: this should be removed.
3476 * It's not correct to pass this view forward because other classes will end up adding
3477 * children to it. Theme will be out of sync.
Dave Mankoffc88d6222018-10-25 15:31:20 -04003478 *
Lucas Dupin987f1932017-05-13 21:02:52 -07003479 * @return bottom area view
3480 */
3481 public KeyguardBottomAreaView getKeyguardBottomAreaView() {
3482 return mKeyguardBottomArea;
3483 }
3484
3485 public void setUserSetupComplete(boolean userSetupComplete) {
3486 mUserSetupComplete = userSetupComplete;
3487 mKeyguardBottomArea.setUserSetupComplete(userSetupComplete);
3488 }
3489
Selim Cinek2627d722018-01-19 12:16:49 -08003490 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
3491 mExpandOffset = params != null ? params.getTopChange() : 0;
3492 updateQsExpansion();
3493 if (params != null) {
3494 boolean hideIcons = params.getProgress(
3495 ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
3496 if (hideIcons != mHideIconsDuringNotificationLaunch) {
3497 mHideIconsDuringNotificationLaunch = hideIcons;
3498 if (!hideIcons) {
Charles Chenf3d295c2018-11-30 18:15:21 +08003499 mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
Selim Cinek2627d722018-01-19 12:16:49 -08003500 }
3501 }
3502 }
3503 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -08003504
3505 public void addTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) {
3506 mTrackingHeadsUpListeners.add(listener);
3507 }
Selim Cinek332c23f2018-03-16 17:37:50 -07003508
Selim Cinek60ffea62018-03-22 13:16:44 -07003509 public void removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) {
3510 mTrackingHeadsUpListeners.remove(listener);
3511 }
3512
3513 public void addVerticalTranslationListener(Runnable verticalTranslationListener) {
3514 mVerticalTranslationListener.add(verticalTranslationListener);
3515 }
3516
3517 public void removeVerticalTranslationListener(Runnable verticalTranslationListener) {
3518 mVerticalTranslationListener.remove(verticalTranslationListener);
Selim Cinek332c23f2018-03-16 17:37:50 -07003519 }
3520
3521 public void setHeadsUpAppearanceController(
3522 HeadsUpAppearanceController headsUpAppearanceController) {
3523 mHeadsUpAppearanceController = headsUpAppearanceController;
3524 }
Lucas Dupin93752552018-03-19 21:32:19 -07003525
3526 /**
3527 * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
3528 * security view of the bouncer.
3529 */
3530 public void onBouncerPreHideAnimation() {
Jason Monk1fd3fc32018-08-14 17:20:09 -04003531 setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */,
Lucas Dupin93752552018-03-19 21:32:19 -07003532 false /* goingToFullShade */);
3533 }
Lucas Dupinc510d412018-06-12 13:08:23 -07003534
Lucas Dupind61974d2019-03-29 16:09:26 -07003535 /**
3536 * Do not let the user drag the shade up and down for the current touch session.
3537 * This is necessary to avoid shade expansion while/after the bouncer is dismissed.
3538 */
3539 public void blockExpansionForCurrentTouch() {
3540 mBlockingExpansionForCurrentTouch = mTracking;
3541 }
3542
Lucas Dupinc510d412018-06-12 13:08:23 -07003543 @Override
3544 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3545 super.dump(fd, pw, args);
Winson Chung9cd21152019-05-28 15:04:08 -07003546 pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect());
Lucas Dupinc510d412018-06-12 13:08:23 -07003547 if (mKeyguardStatusBar != null) {
3548 mKeyguardStatusBar.dump(fd, pw, args);
3549 }
Lucas Dupin43499522019-03-04 16:45:58 -08003550 if (mKeyguardStatusView != null) {
3551 mKeyguardStatusView.dump(fd, pw, args);
3552 }
Lucas Dupinc510d412018-06-12 13:08:23 -07003553 }
Jason Monke59dc402018-08-16 12:05:01 -04003554
3555 public boolean hasActiveClearableNotifications() {
Ned Burns61269442019-05-02 18:27:23 -04003556 return mNotificationStackScroller.hasActiveClearableNotifications(ROWS_ALL);
Jason Monke59dc402018-08-16 12:05:01 -04003557 }
3558
3559 @Override
3560 public void onZenChanged(int zen) {
3561 updateShowEmptyShadeView();
3562 }
3563
3564 private void updateShowEmptyShadeView() {
3565 boolean showEmptyShadeView =
3566 mBarState != StatusBarState.KEYGUARD &&
3567 mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
3568 showEmptyShadeView(showEmptyShadeView);
3569 }
3570
3571 public RemoteInputController.Delegate createRemoteInputDelegate() {
3572 return mNotificationStackScroller.createDelegate();
3573 }
3574
3575 public void updateNotificationViews() {
Gus Prevase2d6f042018-10-17 15:25:30 -04003576 mNotificationStackScroller.updateSectionBoundaries();
Jason Monke59dc402018-08-16 12:05:01 -04003577 mNotificationStackScroller.updateSpeedBumpIndex();
3578 mNotificationStackScroller.updateFooter();
3579 updateShowEmptyShadeView();
Jason Monk297c04e2018-08-23 17:16:59 -04003580 mNotificationStackScroller.updateIconAreaViews();
Jason Monke59dc402018-08-16 12:05:01 -04003581 }
3582
3583 public void onUpdateRowStates() {
3584 mNotificationStackScroller.onUpdateRowStates();
3585 }
3586
3587 public boolean hasPulsingNotifications() {
3588 return mNotificationStackScroller.hasPulsingNotifications();
3589 }
3590
Jason Monke59dc402018-08-16 12:05:01 -04003591 public ActivatableNotificationView getActivatedChild() {
3592 return mNotificationStackScroller.getActivatedChild();
3593 }
3594
3595 public void setActivatedChild(ActivatableNotificationView o) {
3596 mNotificationStackScroller.setActivatedChild(o);
3597 }
3598
Jason Monke59dc402018-08-16 12:05:01 -04003599 public void runAfterAnimationFinished(Runnable r) {
3600 mNotificationStackScroller.runAfterAnimationFinished(r);
3601 }
3602
3603 public void setScrollingEnabled(boolean b) {
3604 mNotificationStackScroller.setScrollingEnabled(b);
3605 }
3606
3607 public void initDependencies(StatusBar statusBar, NotificationGroupManager groupManager,
3608 NotificationShelf notificationShelf,
3609 HeadsUpManagerPhone headsUpManager,
3610 NotificationIconAreaController notificationIconAreaController,
3611 ScrimController scrimController) {
3612 setStatusBar(statusBar);
3613 setGroupManager(mGroupManager);
3614 mNotificationStackScroller.setNotificationPanel(this);
3615 mNotificationStackScroller.setIconAreaController(notificationIconAreaController);
3616 mNotificationStackScroller.setStatusBar(statusBar);
3617 mNotificationStackScroller.setGroupManager(groupManager);
Jason Monke59dc402018-08-16 12:05:01 -04003618 mNotificationStackScroller.setShelf(notificationShelf);
3619 mNotificationStackScroller.setScrimController(scrimController);
3620 updateShowEmptyShadeView();
3621 }
Lucas Dupin55c6e802018-09-27 18:07:36 -07003622
Jason Monk297c04e2018-08-23 17:16:59 -04003623 public void showTransientIndication(int id) {
Lucas Dupin00ebe132019-04-26 16:17:56 -07003624 mKeyguardIndicationController.showTransientIndication(id);
Jason Monk297c04e2018-08-23 17:16:59 -04003625 }
Lucas Dupin407cc582019-03-11 21:04:31 -07003626
Selim Cinek6f0a62a2019-04-09 18:40:12 -07003627 @Override
3628 public void onDynamicPrivacyChanged() {
Lucas Dupine1651c52019-05-23 12:57:29 -07003629 // Do not request animation when pulsing or waking up, otherwise the clock wiill be out
3630 // of sync with the notification panel.
3631 if (mLinearDarkAmount != 0) {
3632 return;
3633 }
Selim Cinek6f0a62a2019-04-09 18:40:12 -07003634 mAnimateNextPositionUpdate = true;
3635 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -07003636
Selim Cinek195dfc52019-05-30 19:35:05 -07003637 public void setOnReinflationListener(Runnable onReinflationListener) {
3638 mOnReinflationListener = onReinflationListener;
3639 }
3640
Fabian Kozynski786974f2019-07-25 12:44:06 -04003641 public static boolean isQsSplitEnabled() {
3642 return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
3643 SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false);
3644 }
Daniel Sandler08d05e32012-08-08 16:39:54 -04003645}