diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java index bd2209b0d2920..0424382a1b88a 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java @@ -52,13 +52,6 @@ public interface QS extends FragmentBase { void setListening(boolean listening); boolean isShowingDetail(); void closeDetail(); - - /** - * Set that we're currently pulse expanding - * - * @param pulseExpanding if we're currently expanding during pulsing - */ - default void setPulseExpanding(boolean pulseExpanding) {} void animateHeaderSlidingOut(); void setQsExpansion(float qsExpansionFraction, float headerTranslation); void setHeaderListening(boolean listening); diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index f9dcd390cd510..f3b8b0bfaf36f 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -55,7 +55,7 @@ android:clipChildren="false" android:clipToPadding="false" android:focusable="true" - android:paddingBottom="10dp" + android:paddingBottom="24dp" android:importantForAccessibility="yes" /> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 7984f3a980e71..34f8503ac1dde 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1456,7 +1456,7 @@ 24dp - 16dp + 32dp 28dp 20dp diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 0a1e9d04fab00..04f692dcc1e63 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.util.InjectionInflationController; @@ -69,6 +70,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private final Rect mQsBounds = new Rect(); private final StatusBarStateController mStatusBarStateController; private final FalsingManager mFalsingManager; + private final KeyguardBypassController mBypassController; private boolean mQsExpanded; private boolean mHeaderAnimating; private boolean mStackScrollerOverscrolling; @@ -135,6 +137,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca StatusBarStateController statusBarStateController, CommandQueue commandQueue, QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost, @Named(QUICK_QS_PANEL) MediaHost qqsMediaHost, + KeyguardBypassController keyguardBypassController, QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags, FalsingManager falsingManager) { mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler; @@ -148,6 +151,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mHost = qsTileHost; mFeatureFlags = featureFlags; mFalsingManager = falsingManager; + mBypassController = keyguardBypassController; mStatusBarStateController = statusBarStateController; } @@ -380,16 +384,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca return mStatusBarStateController.getState() == StatusBarState.KEYGUARD; } - @Override - public void setPulseExpanding(boolean pulseExpanding) { - if (pulseExpanding != mPulseExpanding) { - mPulseExpanding = pulseExpanding; - updateShowCollapsedOnKeyguard(); - } - } - private void updateShowCollapsedOnKeyguard() { - boolean showCollapsed = mPulseExpanding || mTransitioningToFullShade; + boolean showCollapsed = mBypassController.getBypassEnabled() || mTransitioningToFullShade; if (showCollapsed != mShowCollapsedOnKeyguard) { mShowCollapsedOnKeyguard = showCollapsed; updateQsState(); @@ -719,5 +715,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca public void onStateChanged(int newState) { mState = newState; setKeyguardShowing(newState == StatusBarState.KEYGUARD); + updateShowCollapsedOnKeyguard(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 7c7f566589199..425bdc24fe1b1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -56,6 +56,8 @@ public class QSPanel extends LinearLayout implements Tunable { private static final String TAG = "QSPanel"; protected final Context mContext; + private final int mMediaTopMargin; + private final int mMediaTotalBottomMargin; /** * The index where the content starts that needs to be moved between parents @@ -99,13 +101,14 @@ public class QSPanel extends LinearLayout implements Tunable { protected LinearLayout mHorizontalContentContainer; protected QSTileLayout mTileLayout; - private int mMediaTotalBottomMargin; public QSPanel(Context context, AttributeSet attrs) { super(context, attrs); mUsingMediaPlayer = useQsMediaPlayer(context); mMediaTotalBottomMargin = getResources().getDimensionPixelSize( R.dimen.quick_settings_bottom_margin_media); + mMediaTopMargin = getResources().getDimensionPixelSize( + R.dimen.qs_tile_margin_vertical); mContext = context; setOrientation(VERTICAL); @@ -328,7 +331,7 @@ public class QSPanel extends LinearLayout implements Tunable { private void updateHorizontalLinearLayoutMargins() { if (mHorizontalLinearLayout != null && !displayMediaMarginsOnMedia()) { LayoutParams lp = (LayoutParams) mHorizontalLinearLayout.getLayoutParams(); - lp.bottomMargin = mMediaTotalBottomMargin - getPaddingBottom(); + lp.bottomMargin = Math.max(mMediaTotalBottomMargin - getPaddingBottom(), 0); mHorizontalLinearLayout.setLayoutParams(lp); } } @@ -343,6 +346,13 @@ public class QSPanel extends LinearLayout implements Tunable { return true; } + /** + * @return true if the media view needs margin on the top to separate it from the qs tiles + */ + protected boolean mediaNeedsTopMargin() { + return false; + } + private boolean needsDynamicRowsAndColumns() { return true; } @@ -411,7 +421,9 @@ public class QSPanel extends LinearLayout implements Tunable { // necessary if the view isn't horizontal, since otherwise the padding is // carried in the parent of this view (to ensure correct vertical alignment) layoutParams.bottomMargin = !horizontal || displayMediaMarginsOnMedia() - ? mMediaTotalBottomMargin - getPaddingBottom() : 0; + ? Math.max(mMediaTotalBottomMargin - getPaddingBottom(), 0) : 0; + layoutParams.topMargin = mediaNeedsTopMargin() && !horizontal + ? mMediaTopMargin : 0; } } @@ -674,6 +686,7 @@ public class QSPanel extends LinearLayout implements Tunable { mTileLayout.setMaxColumns(horizontal ? 2 : 4); } updateMargins(mediaHostView); + mHorizontalLinearLayout.setVisibility(horizontal ? View.VISIBLE : View.GONE); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 4cd4048f72868..985943bc8b054 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -72,6 +72,11 @@ public class QuickQSPanel extends QSPanel { return false; } + @Override + protected boolean mediaNeedsTopMargin() { + return true; + } + @Override protected void updatePadding() { // QS Panel is setting a top padding by default, which we don't need. @@ -180,7 +185,6 @@ public class QuickQSPanel extends QSPanel { LayoutParams.WRAP_CONTENT); setLayoutParams(lp); setMaxColumns(4); - mLastRowPadding = true; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 2b96a34967f49..1a890a7ad07bb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -31,7 +31,6 @@ public class TileLayout extends ViewGroup implements QSTileLayout { protected int mCellMarginVertical; protected int mSidePadding; protected int mRows = 1; - protected boolean mLastRowPadding = false; protected final ArrayList mRecords = new ArrayList<>(); protected boolean mListening; @@ -168,9 +167,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout { } int height = (mCellHeight + mCellMarginVertical) * mRows; - if (!mLastRowPadding) { - height -= mCellMarginVertical; - } + height -= mCellMarginVertical; if (height < 0) height = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 6f4a73ec4516d..6fa06a76dc5ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -65,6 +65,7 @@ class LockscreenShadeTransitionController @Inject constructor( configurationController: ConfigurationController, falsingManager: FalsingManager ) { + private var pulseHeight: Float = 0f private var useSplitShade: Boolean = false private lateinit var nsslController: NotificationStackScrollLayoutController lateinit var notificationPanelController: NotificationPanelViewController @@ -87,6 +88,12 @@ class LockscreenShadeTransitionController @Inject constructor( @VisibleForTesting internal var dragDownAnimator: ValueAnimator? = null + /** + * The current pulse height animator if any + */ + @VisibleForTesting + internal var pulseHeightAnimator: ValueAnimator? = null + /** * Distance that the full shade transition takes in order for scrim to fully transition to * the shade (in alpha) @@ -109,6 +116,12 @@ class LockscreenShadeTransitionController @Inject constructor( */ private var nextHideKeyguardNeedsNoAnimation = false + /** + * The distance until we're showing the notifications when pulsing + */ + val distanceUntilShowingPulsingNotifications + get() = scrimTransitionDistance + /** * The udfpsKeyguardViewController if it exists. */ @@ -286,22 +299,26 @@ class LockscreenShadeTransitionController @Inject constructor( nsslController.setTransitionToFullShadeAmount(field) notificationPanelController.setTransitionToFullShadeAmount(field, false /* animate */, 0 /* delay */) - val scrimProgress = MathUtils.saturate(field / scrimTransitionDistance) - scrimController.setTransitionToFullShadeProgress(scrimProgress) // TODO: appear qs also in split shade val qsAmount = if (useSplitShade) 0f else field qS.setTransitionToFullShadeAmount(qsAmount, false /* animate */) // TODO: appear media also in split shade val mediaAmount = if (useSplitShade) 0f else field mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount) - // Fade out all content only visible on the lockscreen - notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress) - depthController.transitionToFullShadeProgress = scrimProgress - udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress) + transitionToShadeAmountCommon(field) } } } + private fun transitionToShadeAmountCommon(dragDownAmount: Float) { + val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance) + scrimController.setTransitionToFullShadeProgress(scrimProgress) + // Fade out all content only visible on the lockscreen + notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress) + depthController.transitionToFullShadeProgress = scrimProgress + udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress) + } + private fun setDragDownAmountAnimated( target: Float, delay: Long = 0, @@ -453,15 +470,19 @@ class LockscreenShadeTransitionController @Inject constructor( /** * Notify this handler that the keyguard was just dismissed and that a animation to * the full shade should happen. + * + * @param delay the delay to do the animation with + * @param previousState which state were we in when we hid the keyguard? */ - fun onHideKeyguard(delay: Long) { + fun onHideKeyguard(delay: Long, previousState: Int) { if (animationHandlerOnKeyguardDismiss != null) { animationHandlerOnKeyguardDismiss!!.invoke(delay) animationHandlerOnKeyguardDismiss = null } else { if (nextHideKeyguardNeedsNoAnimation) { nextHideKeyguardNeedsNoAnimation = false - } else { + } else if (previousState != StatusBarState.SHADE_LOCKED) { + // No animation necessary if we already were in the shade locked! performDefaultGoToFullShadeAnimation(delay) } } @@ -479,6 +500,53 @@ class LockscreenShadeTransitionController @Inject constructor( notificationPanelController.animateToFullShade(delay) animateAppear(delay) } + + // + // PULSE EXPANSION + // + + /** + * Set the height how tall notifications are pulsing. This is only set whenever we are expanding + * from a pulse and determines how much the notifications are expanded. + */ + fun setPulseHeight(height: Float, animate: Boolean = false) { + if (animate) { + val pulseHeightAnimator = ValueAnimator.ofFloat(pulseHeight, height) + pulseHeightAnimator.interpolator = Interpolators.FAST_OUT_SLOW_IN + pulseHeightAnimator.duration = SPRING_BACK_ANIMATION_LENGTH_MS + pulseHeightAnimator.addUpdateListener { animation: ValueAnimator -> + setPulseHeight(animation.animatedValue as Float) + } + pulseHeightAnimator.start() + this.pulseHeightAnimator = pulseHeightAnimator + } else { + pulseHeight = height + val overflow = nsslController.setPulseHeight(height) + notificationPanelController.setOverStrechAmount(overflow) + val transitionHeight = if (keyguardBypassController.bypassEnabled) height else 0.0f + transitionToShadeAmountCommon(transitionHeight) + } + } + + /** + * Finish the pulse animation when the touch interaction finishes + * @param cancelled was the interaction cancelled and this is a reset? + */ + fun finishPulseAnimation(cancelled: Boolean) { + if (cancelled) { + setPulseHeight(0f, animate = true) + } else { + notificationPanelController.onPulseExpansionFinished() + setPulseHeight(0f, animate = false) + } + } + + /** + * Notify this class that a pulse expansion is starting + */ + fun onPulseExpansionStarted() { + pulseHeightAnimator?.cancel() + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index b34bfad499f87..761a20326200b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -19,8 +19,8 @@ package com.android.systemui.statusbar import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ObjectAnimator -import android.animation.ValueAnimator import android.content.Context +import android.content.res.Configuration import android.os.PowerManager import android.os.PowerManager.WAKE_REASON_GESTURE import android.os.SystemClock @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationRoundnessMa import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.policy.ConfigurationController import javax.inject.Inject import kotlin.math.max @@ -56,18 +57,17 @@ constructor( private val bypassController: KeyguardBypassController, private val headsUpManager: HeadsUpManagerPhone, private val roundnessManager: NotificationRoundnessManager, + private val configurationController: ConfigurationController, private val statusBarStateController: StatusBarStateController, private val falsingManager: FalsingManager, private val lockscreenShadeTransitionController: LockscreenShadeTransitionController, private val falsingCollector: FalsingCollector ) : Gefingerpoken { companion object { - private val RUBBERBAND_FACTOR_STATIC = 0.25f private val SPRING_BACK_ANIMATION_LENGTH_MS = 375 } private val mPowerManager: PowerManager? - private val mMinDragDistance: Int private var mInitialTouchX: Float = 0.0f private var mInitialTouchY: Float = 0.0f var isExpanding: Boolean = false @@ -81,6 +81,7 @@ constructor( topEntry?.let { roundnessManager.setTrackingHeadsUp(it.row) } + lockscreenShadeTransitionController.onPulseExpansionStarted() } else { roundnessManager.setTrackingHeadsUp(null) if (!leavingLockscreen) { @@ -93,8 +94,8 @@ constructor( } var leavingLockscreen: Boolean = false private set - private val mTouchSlop: Float - private lateinit var overStretchHandler: OverStretchHandler + private var touchSlop = 0f + private var minDragDistance = 0 private lateinit var stackScrollerController: NotificationStackScrollLayoutController private val mTemp2 = IntArray(2) private var mDraggedFarEnough: Boolean = false @@ -102,9 +103,7 @@ constructor( private var mPulsing: Boolean = false var isWakingToShadeLocked: Boolean = false private set - private var overStretchAmount: Float = 0.0f - private var mWakeUpHeight: Float = 0.0f - private var mReachedWakeUpHeight: Boolean = false + private var velocityTracker: VelocityTracker? = null private val isFalseTouch: Boolean @@ -114,12 +113,21 @@ constructor( var bouncerShowing: Boolean = false init { - mMinDragDistance = context.resources.getDimensionPixelSize( - R.dimen.keyguard_drag_down_min_distance) - mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat() + initResources(context) + configurationController.addCallback(object : ConfigurationController.ConfigurationListener { + override fun onConfigChanged(newConfig: Configuration?) { + initResources(context) + } + }) mPowerManager = context.getSystemService(PowerManager::class.java) } + private fun initResources(context: Context) { + minDragDistance = context.resources.getDimensionPixelSize( + R.dimen.keyguard_drag_down_min_distance) + touchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat() + } + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { return canHandleMotionEvent() && startExpansion(event) } @@ -148,14 +156,12 @@ constructor( MotionEvent.ACTION_MOVE -> { val h = y - mInitialTouchY - if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) { + if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) { falsingCollector.onStartExpandingFromPulse() isExpanding = true captureStartingChild(mInitialTouchX, mInitialTouchY) mInitialTouchY = y mInitialTouchX = x - mWakeUpHeight = wakeUpCoordinator.getWakeUpHeight() - mReachedWakeUpHeight = false return true } } @@ -216,7 +222,6 @@ constructor( } private fun finishExpansion() { - resetClock() val startingChild = mStartingChild if (mStartingChild != null) { setUserLocked(mStartingChild!!, false) @@ -230,6 +235,7 @@ constructor( } lockscreenShadeTransitionController.goToLockedShade(startingChild, needsQSAnimation = false) + lockscreenShadeTransitionController.finishPulseAnimation(cancelled = false) leavingLockscreen = true isExpanding = false if (mStartingChild is ExpandableNotificationRow) { @@ -240,24 +246,19 @@ constructor( private fun updateExpansionHeight(height: Float) { var expansionHeight = max(height, 0.0f) - if (!mReachedWakeUpHeight && height > mWakeUpHeight) { - mReachedWakeUpHeight = true - } if (mStartingChild != null) { val child = mStartingChild!! val newHeight = Math.min((child.collapsedHeight + expansionHeight).toInt(), child.maxContentHeight) child.actualHeight = newHeight - expansionHeight = max(newHeight.toFloat(), expansionHeight) } else { - val target = if (mReachedWakeUpHeight) mWakeUpHeight else 0.0f - wakeUpCoordinator.setNotificationsVisibleForExpansion(height > target, - true /* animate */, - true /* increaseSpeed */) - expansionHeight = max(mWakeUpHeight, expansionHeight) + wakeUpCoordinator.setNotificationsVisibleForExpansion( + height + > lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications, + true /* animate */, + true /* increaseSpeed */) } - val dragDownAmount = wakeUpCoordinator.setPulseHeight(expansionHeight) - setOverStretchAmount(dragDownAmount) + lockscreenShadeTransitionController.setPulseHeight(expansionHeight, animate = false) } private fun captureStartingChild(x: Float, y: Float) { @@ -269,11 +270,6 @@ constructor( } } - private fun setOverStretchAmount(amount: Float) { - overStretchAmount = amount - overStretchHandler.setOverStretchAmount(amount) - } - private fun reset(child: ExpandableView) { if (child.actualHeight == child.collapsedHeight) { setUserLocked(child, false) @@ -297,25 +293,14 @@ constructor( } } - private fun resetClock() { - val anim = ValueAnimator.ofFloat(overStretchAmount, 0f) - anim.interpolator = Interpolators.FAST_OUT_SLOW_IN - anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong() - anim.addUpdateListener { - animation -> setOverStretchAmount(animation.animatedValue as Float) - } - anim.start() - } - private fun cancelExpansion() { isExpanding = false falsingCollector.onExpansionFromPulseStopped() if (mStartingChild != null) { reset(mStartingChild!!) mStartingChild = null - } else { - resetClock() } + lockscreenShadeTransitionController.finishPulseAnimation(cancelled = true) wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */, true /* animate */, false /* increaseSpeed */) @@ -333,11 +318,7 @@ constructor( } else null } - fun setUp( - stackScrollerController: NotificationStackScrollLayoutController, - overStrechHandler: OverStretchHandler - ) { - this.overStretchHandler = overStrechHandler + fun setUp(stackScrollerController: NotificationStackScrollLayoutController) { this.stackScrollerController = stackScrollerController } @@ -348,12 +329,4 @@ constructor( fun onStartedWakingUp() { isWakingToShadeLocked = false } - - interface OverStretchHandler { - - /** - * Set the overstretch amount in pixels This will be rubberbanded later - */ - fun setOverStretchAmount(amount: Float) - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index b0a7767accfc1..a2c9ffc6bdc4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -374,10 +374,6 @@ class NotificationWakeUpCoordinator @Inject constructor( } } - fun getWakeUpHeight(): Float { - return mStackScrollerController.wakeUpHeight - } - private fun updateHideAmount() { val linearAmount = min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount) val amount = min(1.0f - mVisibilityAmount, mDozeAmount) @@ -395,16 +391,6 @@ class NotificationWakeUpCoordinator @Inject constructor( } } - /** - * Set the height how tall notifications are pulsing. This is only set whenever we are expanding - * from a pulse and determines how much the notifications are expanded. - */ - fun setPulseHeight(height: Float): Float { - val overflow = mStackScrollerController.setPulseHeight(height) - // no overflow for the bypass experience - return if (bypassController.bypassEnabled) 0.0f else overflow - } - override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) { var animate = shouldAnimateVisibility() if (!isHeadsUp) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 4ad72027b046b..289c32f17b31e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -5138,12 +5138,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * @return the overflow how much the height is further than he lowest notification */ public float setPulseHeight(float height) { + float overflow; mAmbientState.setPulseHeight(height); if (mKeyguardBypassEnabledProvider.getBypassEnabled()) { notifyAppearChangedListeners(); + overflow = Math.max(0, height - getIntrinsicPadding()); + } else { + overflow = Math.max(0, height + - mAmbientState.getInnerHeight(true /* ignorePulseHeight */)); } requestChildrenUpdate(); - return Math.max(0, height - mAmbientState.getInnerHeight(true /* ignorePulseHeight */)); + return overflow; } public float getPulseHeight() { @@ -5203,12 +5208,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public float calculateAppearFractionBypass() { float pulseHeight = getPulseHeight(); - float wakeUpHeight = getWakeUpHeight(); - float dragDownAmount = pulseHeight - wakeUpHeight; - // The total distance required to fully reveal the header float totalDistance = getIntrinsicPadding(); - return MathUtils.smoothStep(0, totalDistance, dragDownAmount); + return MathUtils.smoothStep(0, totalDistance, pulseHeight); } public void setController( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 09afedb6de59c..9e4adce47e0c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -885,10 +885,6 @@ public class NotificationStackScrollLayoutController { mView.setDozeAmount(amount); } - public float getWakeUpHeight() { - return mView.getWakeUpHeight(); - } - public int getSpeedBumpIndex() { return mView.getSpeedBumpIndex(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index d0507e1e136ca..b36dc56ffdf95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -274,7 +274,9 @@ public class StackScrollAlgorithm { // expanded. Consider updating these states in updateContentView instead so that we don't // have to recalculate in every frame. float currentY = -ambientState.getScrollY(); - if (!ambientState.isOnKeyguard()) { + if (!ambientState.isOnKeyguard() + || (ambientState.isBypassEnabled() && ambientState.isPulseExpanding())) { + // add top padding at the start as long as we're not on the lock screen currentY += mNotificationScrimPadding; } state.firstViewInShelf = null; @@ -324,7 +326,8 @@ public class StackScrollAlgorithm { */ private void updatePositionsForState(StackScrollAlgorithmState algorithmState, AmbientState ambientState) { - if (!ambientState.isOnKeyguard()) { + if (!ambientState.isOnKeyguard() + || (ambientState.isBypassEnabled() && ambientState.isPulseExpanding())) { algorithmState.mCurrentYPosition += mNotificationScrimPadding; algorithmState.mCurrentExpandedYPosition += mNotificationScrimPadding; } @@ -355,7 +358,9 @@ public class StackScrollAlgorithm { && algorithmState.firstViewInShelf != null; final float shelfHeight = showingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f; - final float scrimPadding = ambientState.isOnKeyguard() ? 0 : mNotificationScrimPadding; + final float scrimPadding = ambientState.isOnKeyguard() + && (!ambientState.isBypassEnabled() || !ambientState.isPulseExpanding()) + ? 0 : mNotificationScrimPadding; final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding; final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index ad4213d212a0b..f77c0520cdb1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -211,7 +211,7 @@ public class KeyguardClockPositionAlgorithm { private int getStackScrollerPadding(int clockYPosition) { if (mBypassEnabled) { - return mUnlockedStackScrollerPadding; + return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount); } else if (mIsSplitShade) { return clockYPosition; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index cfe95e06fb61f..6516abd143edf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -165,14 +165,14 @@ public class NotificationIconAreaController implements * Called by the Keyguard*ViewController whose view contains the aod icons. */ public void setupAodIcons(@NonNull NotificationIconContainer aodIcons) { - boolean changed = mAodIcons != null; + boolean changed = mAodIcons != null && aodIcons != mAodIcons; if (changed) { mAodIcons.setAnimationsEnabled(false); mAodIcons.removeAllViews(); } mAodIcons = aodIcons; mAodIcons.setOnLockScreen(true); - updateAodIconsVisibility(false /* animate */); + updateAodIconsVisibility(false /* animate */, changed); updateAnimations(); if (changed) { updateAodNotificationIcons(); @@ -587,7 +587,7 @@ public class NotificationIconAreaController implements @Override public void onStateChanged(int newState) { - updateAodIconsVisibility(false /* animate */); + updateAodIconsVisibility(false /* animate */, false /* force */); updateAnimations(); } @@ -663,18 +663,18 @@ public class NotificationIconAreaController implements // since otherwise the unhide animation overlaps animate &= fullyHidden; } - updateAodIconsVisibility(animate); + updateAodIconsVisibility(animate, false /* force */); updateAodNotificationIcons(); } @Override public void onPulseExpansionChanged(boolean expandingChanged) { if (expandingChanged) { - updateAodIconsVisibility(true /* animate */); + updateAodIconsVisibility(true /* animate */, false /* force */); } } - private void updateAodIconsVisibility(boolean animate) { + private void updateAodIconsVisibility(boolean animate, boolean forceUpdate) { if (mAodIcons == null) { return; } @@ -688,10 +688,11 @@ public class NotificationIconAreaController implements && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) { visible = false; } - if (visible && mWakeUpCoordinator.isPulseExpanding()) { + if (visible && mWakeUpCoordinator.isPulseExpanding() + && !mBypassController.getBypassEnabled()) { visible = false; } - if (mAodIconsVisible != visible) { + if (mAodIconsVisible != visible || forceUpdate) { mAodIconsVisible = visible; mAodIcons.animate().cancel(); if (animate) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 11e6b7d920f8a..12e85beba0c67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -608,6 +608,11 @@ public class NotificationPanelViewController extends PanelViewController { * Is the current animator resetting the qs translation. */ private boolean mIsQsTranslationResetAnimator; + + /** + * Is the current animator resetting the pulse expansion after a drag down + */ + private boolean mIsPulseExpansionResetAnimator; private final Rect mKeyguardStatusAreaClipBounds = new Rect(); private final Region mQsInterceptRegion = new Region(); @@ -884,14 +889,7 @@ public class NotificationPanelViewController extends PanelViewController { mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController); mQsFrame = mView.findViewById(R.id.qs_frame); - mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController, - amount -> { - float progress = amount / mView.getHeight(); - float overstretch = Interpolators.getOvershootInterpolation(progress, - (float) mMaxOverscrollAmountForPulse / mView.getHeight(), - 0.2f); - setOverStrechAmount(overstretch); - }); + mPulseExpansionHandler.setUp(mNotificationStackScrollLayoutController); mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() { @Override public void onFullyHiddenChanged(boolean isFullyHidden) { @@ -903,7 +901,6 @@ public class NotificationPanelViewController extends PanelViewController { if (mKeyguardBypassController.getBypassEnabled()) { // Position the notifications while dragging down while pulsing requestScrollerTopPaddingUpdate(false /* animate */); - updateQSPulseExpansion(); } } }); @@ -941,8 +938,6 @@ public class NotificationPanelViewController extends PanelViewController { R.dimen.notification_panel_min_side_margin); mIndicationBottomPadding = mResources.getDimensionPixelSize( R.dimen.keyguard_indication_bottom_padding); - mQsNotificationTopPadding = mResources.getDimensionPixelSize( - R.dimen.qs_notification_padding); mShelfHeight = mResources.getDimensionPixelSize(R.dimen.notification_shelf_height); mDarkIconSize = mResources.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark); int statusbarHeight = mResources.getDimensionPixelSize( @@ -1341,8 +1336,7 @@ public class NotificationPanelViewController extends PanelViewController { * @return the padding of the stackscroller when unlocked */ private int getUnlockedStackScrollerPadding() { - return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight - + mQsNotificationTopPadding; + return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight; } /** @@ -2239,7 +2233,7 @@ public class NotificationPanelViewController extends PanelViewController { } } - protected void updateQsExpansion() { + private void updateQsExpansion() { if (mQs == null) return; float qsExpansionFraction = computeQsExpansionFraction(); mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation()); @@ -2298,9 +2292,20 @@ public class NotificationPanelViewController extends PanelViewController { top = mTransitionToFullShadeQSPosition; } else { final float notificationTop = getQSEdgePosition(); - top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop) - : notificationTop); + if (isOnKeyguard()) { + if (mKeyguardBypassController.getBypassEnabled()) { + // When bypassing on the keyguard, let's use the panel bottom. + // this should go away once we unify the stackY position and don't have + // to do this min anymore below. + top = qsPanelBottomY; + } else { + top = (int) Math.min(qsPanelBottomY, notificationTop); + } + } else { + top = (int) notificationTop; + } } + top += mOverStretchAmount; bottom = getView().getBottom(); // notification bounds should take full screen width regardless of insets left = 0; @@ -2353,6 +2358,7 @@ public class NotificationPanelViewController extends PanelViewController { public void onAnimationEnd(Animator animation) { mQsClippingAnimation = null; mIsQsTranslationResetAnimator = false; + mIsPulseExpansionResetAnimator = false; } }); mQsClippingAnimation.start(); @@ -2378,9 +2384,17 @@ public class NotificationPanelViewController extends PanelViewController { } if (mQs != null) { float qsTranslation = 0; - if (mTransitioningToFullShadeProgress > 0.0f || (mQsClippingAnimation != null - && mIsQsTranslationResetAnimator)) { - qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT; + boolean pulseExpanding = mPulseExpansionHandler.isExpanding(); + if (mTransitioningToFullShadeProgress > 0.0f || pulseExpanding + || (mQsClippingAnimation != null + && (mIsQsTranslationResetAnimator || mIsPulseExpansionResetAnimator))) { + if (pulseExpanding || mIsPulseExpansionResetAnimator) { + // qsTranslation should only be positive during pulse expansion because it's + // already translating in from the top + qsTranslation = Math.max(0, (top - mQs.getHeader().getHeight()) / 2.0f); + } else { + qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT; + } } mQsTranslationForFullShadeTransition = qsTranslation; updateQsFrameTranslation(); @@ -2447,7 +2461,7 @@ public class NotificationPanelViewController extends PanelViewController { private float calculateNotificationsTopPadding() { if (mShouldUseSplitNotificationShade && !mKeyguardShowing) { - return mSplitShadeNotificationsTopPadding + mQsNotificationTopPadding; + return mSplitShadeNotificationsTopPadding; } if (mKeyguardShowing && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) { @@ -2458,7 +2472,7 @@ public class NotificationPanelViewController extends PanelViewController { // panel. We need to take the maximum and linearly interpolate with the panel expansion // for a nice motion. int maxNotificationPadding = getKeyguardNotificationStaticPadding(); - int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding; + int maxQsPadding = mQsMaxExpansionHeight; int max = mBarState == KEYGUARD ? Math.max( maxNotificationPadding, maxQsPadding) : maxQsPadding; return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max, @@ -2471,10 +2485,10 @@ public class NotificationPanelViewController extends PanelViewController { // We can only do the smoother transition on Keyguard when we also are not collapsing // from a scrolled quick settings. return MathUtils.lerp((float) getKeyguardNotificationStaticPadding(), - (float) (mQsMaxExpansionHeight + mQsNotificationTopPadding), + (float) (mQsMaxExpansionHeight), computeQsExpansionFraction()); } else { - return mQsExpansionHeight + mQsNotificationTopPadding; + return mQsExpansionHeight; } } @@ -2509,14 +2523,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - private void updateQSPulseExpansion() { - if (mQs != null) { - mQs.setPulseExpanding( - mKeyguardShowing && mKeyguardBypassController.getBypassEnabled() - && mNotificationStackScrollLayoutController.isPulseExpanding()); - } - } - /** * Set the amount of pixels we have currently dragged down if we're transitioning to the full * shade. 0.0f means we're not transitioning yet. @@ -2567,6 +2573,15 @@ public class NotificationPanelViewController extends PanelViewController { updateQsExpansion(); } + /** + * Notify the panel that the pulse expansion has finished and that we're going to the full + * shade + */ + public void onPulseExpansionFinished() { + animateNextNotificationBounds(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE, 0); + mIsPulseExpansionResetAnimator = true; + } + /** * Set the alpha of the keyguard elements which only show on the lockscreen, but not in * shade locked / shade. This is used when dragging down to the full shade. @@ -2860,10 +2875,6 @@ public class NotificationPanelViewController extends PanelViewController { } int maxQsHeight = mQsMaxExpansionHeight; - if (mKeyguardShowing) { - maxQsHeight += mQsNotificationTopPadding; - } - // If an animation is changing the size of the QS panel, take the animated value. if (mQsSizeChangeAnimator != null) { maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue(); @@ -2928,19 +2939,7 @@ public class NotificationPanelViewController extends PanelViewController { startHeight = -mQsExpansionHeight * QS_PARALLAX_AMOUNT; } if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) { - if (mNotificationStackScrollLayoutController.isPulseExpanding()) { - if (!mPulseExpansionHandler.isExpanding() - && !mPulseExpansionHandler.getLeavingLockscreen()) { - // If we aborted the expansion we need to make sure the header doesn't reappear - // again after the header has animated away - appearAmount = 0; - } else { - appearAmount = mNotificationStackScrollLayoutController - .calculateAppearFractionBypass(); - } - } else { - appearAmount = 0.0f; - } + appearAmount = mNotificationStackScrollLayoutController.calculateAppearFractionBypass(); startHeight = -mQs.getQsMinExpansionHeight(); } float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount)); @@ -3543,7 +3542,6 @@ public class NotificationPanelViewController extends PanelViewController { mQs.setPanelView(mHeightListener); mQs.setExpandClickListener(mOnClickListener); mQs.setHeaderClickable(isQsExpansionEnabled()); - updateQSPulseExpansion(); mQs.setOverscrolling(mStackScrollerOverscrolling); mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade); @@ -4304,8 +4302,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mAccessibilityManager.isEnabled()) { mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); } - mNotificationStackScrollLayoutController.setMaxTopPadding( - mQsMaxExpansionHeight + mQsNotificationTopPadding); + mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight); } } @@ -4423,7 +4420,6 @@ public class NotificationPanelViewController extends PanelViewController { updateMaxDisplayedNotifications(false); // The update needs to happen after the headerSlide in above, otherwise the translation // would reset - updateQSPulseExpansion(); maybeAnimateBottomAreaAlpha(); resetHorizontalPanelPosition(); updateQsState(); @@ -4458,7 +4454,9 @@ public class NotificationPanelViewController extends PanelViewController { * Sets the overstretch amount in raw pixels when dragging down. */ public void setOverStrechAmount(float amount) { - mOverStretchAmount = amount; + float progress = amount / mView.getHeight(); + float overstretch = Interpolators.getOvershootInterpolation(progress); + mOverStretchAmount = overstretch * mMaxOverscrollAmountForPulse; positionClockAndNotifications(true /* forceUpdate */); } @@ -4512,8 +4510,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mQs != null) { updateQSMinHeight(); mQsMaxExpansionHeight = mQs.getDesiredHeight(); - mNotificationStackScrollLayoutController.setMaxTopPadding( - mQsMaxExpansionHeight + mQsNotificationTopPadding); + mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight); } positionClockAndNotifications(); if (mQsExpanded && mQsFullyExpanded) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 35c14b28757e6..8f73520c94092 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3616,6 +3616,7 @@ public class StatusBar extends SystemUI implements DemoMode, mIsKeyguard = false; Trace.beginSection("StatusBar#hideKeyguard"); boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide(); + int previousState = mStatusBarStateController.getState(); if (!(mStatusBarStateController.setState(StatusBarState.SHADE, force))) { //TODO: StatusBarStateController should probably know about hiding the keyguard and // notify listeners. @@ -3628,7 +3629,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController.setLeaveOpenOnKeyguardHide(false); } long delay = mKeyguardStateController.calculateGoingToFullShadeDelay(); - mLockscreenShadeTransitionController.onHideKeyguard(delay); + mLockscreenShadeTransitionController.onHideKeyguard(delay, previousState); // Disable layout transitions in navbar for this transition because the load is just // too heavy for the CPU and GPU on any device. diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index c40977b31e731..c1a7bc5f8bf59 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -55,6 +55,7 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.Clock; @@ -92,6 +93,8 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { @Mock private MediaHost mQQSMediaHost; @Mock + private KeyguardBypassController mBypassController; + @Mock private FeatureFlags mFeatureFlags; @Mock private FalsingManager mFalsingManager; @@ -184,6 +187,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { new QSDetailDisplayer(), mQSMediaHost, mQQSMediaHost, + mBypassController, mQsComponentFactory, mFeatureFlags, mFalsingManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 76fc4d44b96b5..d7661be217527 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -372,16 +372,17 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardBypassController, mDozeParameters, mUnlockedScreenOffAnimationController); + mConfigurationController = new ConfigurationControllerImpl(mContext); PulseExpansionHandler expansionHandler = new PulseExpansionHandler( mContext, coordinator, mKeyguardBypassController, mHeadsUpManager, mock(NotificationRoundnessManager.class), + mConfigurationController, mStatusBarStateController, mFalsingManager, mLockscreenShadeTransitionController, new FalsingCollectorFake()); - mConfigurationController = new ConfigurationControllerImpl(mContext); when(mKeyguardStatusViewComponentFactory.build(any())) .thenReturn(mKeyguardStatusViewComponent); when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())