diff options
14 files changed, 915 insertions, 345 deletions
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 57193e7060f9..436145ec0692 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 @@ -16,6 +16,8 @@ package com.android.systemui.plugins.qs; import android.view.View; +import androidx.annotation.FloatRange; + import com.android.systemui.plugins.FragmentBase; import com.android.systemui.plugins.annotations.DependsOn; import com.android.systemui.plugins.annotations.ProvidesInterface; @@ -107,10 +109,24 @@ public interface QS extends FragmentBase { void setInSplitShade(boolean shouldTranslate); /** - * 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. + * Sets the progress of the transition to full shade on the lockscreen. + * + * @param isTransitioningToFullShade + * whether the transition to full shade is in progress. This might be {@code true}, even + * though {@code qsTransitionFraction} is still 0. + * The reason for that is that on some device configurations, the QS transition has a + * start delay compared to the overall transition. + * + * @param qsTransitionFraction + * the fraction of the QS transition progress, from 0 to 1. + * + * @param qsSquishinessFraction + * the fraction of the QS "squish" transition progress, from 0 to 1. */ - default void setTransitionToFullShadeAmount(float pxAmount, float progress) {} + default void setTransitionToFullShadeProgress( + boolean isTransitioningToFullShade, + @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction, + @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {} /** * A rounded corner clipping that makes QS feel as if it were behind everything. @@ -140,6 +156,12 @@ public interface QS extends FragmentBase { default void setOverScrollAmount(int overScrollAmount) {} /** + * Sets whether the notification panel is using the full width of the screen. Typically true on + * small screens and false on large screens. + */ + void setIsNotificationPanelFullWidth(boolean isFullWidth); + + /** * Callback for when QSPanel container is scrolled */ @ProvidesInterface(version = ScrollListener.VERSION) diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index d638c9d5742e..f4d482406fa0 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -49,54 +49,29 @@ <dimen name="status_view_margin_horizontal">8dp</dimen> - <!-- Distance that the full shade transition takes in order to complete by tapping on a button - like "expand". --> + <!-- Lockscreen shade transition values --> <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen> - - <!-- Distance that the full shade transition takes in order to complete. --> <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen> - - <!-- Distance that the full shade transition takes in order for media to fully transition to - the shade --> - <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen> - - <!-- Distance that the full shade transition takes in order for scrim to fully transition to - the shade (in alpha) --> + <!-- Media transition distance = qs delay + qs distance --> + <dimen name="lockscreen_shade_media_transition_distance">129.28dp</dimen> <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen> - <!-- The notifications scrim transition should start when the other scrims' transition is at 95%. --> <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen> - <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims' - transition. --> + transition. --> <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen> - - <!-- Distance that the full shade transition takes in order for the keyguard content on - NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) --> <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen> - - <!-- Distance that the full shade transition takes in order for the notification shell to fully - expand. --> <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> - - <!-- Distance that the full shade transition takes in order for the Quick Settings to fully - fade and expand. --> - <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> - - <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully - change. - On split-shade, there should be no depth effect, so setting the value to 0. --> + <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_notifications_scrim_transition_distance</dimen> + <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_notifications_scrim_transition_delay</dimen> + <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen> + <!-- On split-shade, the QS squish transition should start from half height. --> + <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item> + <!-- On split-shade, there should be no depth effect, so setting the value to 0. --> <dimen name="lockscreen_shade_depth_controller_transition_distance">0dp</dimen> - - <!-- Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully - fade. --> <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> - - <!-- Used for StatusBar to know that a transition is in progress. At the moment it only checks - whether the progress is > 0, therefore this value is not very important. --> <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> - <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen> <!-- Roughly the same distance as media on LS to media on QS. We will translate by this value diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 008299bd9b1c..a587e5a806ca 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -73,4 +73,24 @@ <dimen name="large_dialog_width">472dp</dimen> <dimen name="large_screen_shade_header_height">42dp</dimen> + + <!-- Lockscreen shade transition values --> + <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen> + <dimen name="lockscreen_shade_full_transition_distance">80dp</dimen> + <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen> + <dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_notifications_scrim_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen> + <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen> + <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen> + <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen> + <!-- On large screen portrait, the QS squish transition should start from half height. --> + <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item> + <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen> + </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a19145ddba6b..d85c999bd387 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1223,6 +1223,17 @@ fade and expand. --> <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> + <!-- Distance delay for the QS transition to start during the lockscreen shade expansion. --> + <dimen name="lockscreen_shade_qs_transition_delay">0dp</dimen> + + <!-- Distance that it takes to complete the QS "squish" transition during the lockscreen shade + expansion. --> + <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen> + + <!-- The fraction at which the QS "squish" transition should start during the lockscreen shade + expansion. 0 is fully collapsed, 1 is fully expanded. --> + <item type="dimen" format="float" name="lockscreen_shade_qs_squish_start_fraction">0</item> + <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully change. --> <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index b31e4720fef6..072c32f693d9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -34,6 +34,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import androidx.annotation.FloatRange; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; @@ -166,6 +167,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca // visible; private boolean mQsVisible; + /** + * Whether the notification panel uses the full width of the screen. + * + * Usually {@code true} on small screens, and {@code false} on large screens. + */ + private boolean mIsNotificationPanelFullWidth; + @Inject public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler, QSTileHost qsTileHost, @@ -571,15 +579,17 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } @Override - public void setTransitionToFullShadeAmount(float pxAmount, float progress) { - boolean isTransitioningToFullShade = pxAmount > 0; + public void setTransitionToFullShadeProgress( + boolean isTransitioningToFullShade, + @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction, + @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) { if (isTransitioningToFullShade != mTransitioningToFullShade) { mTransitioningToFullShade = isTransitioningToFullShade; updateShowCollapsedOnKeyguard(); } - mFullShadeProgress = progress; + mFullShadeProgress = qsTransitionFraction; setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation, - isTransitioningToFullShade ? progress : mSquishinessFraction); + isTransitioningToFullShade ? qsSquishinessFraction : mSquishinessFraction); } @Override @@ -598,12 +608,16 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } @Override + public void setIsNotificationPanelFullWidth(boolean isFullWidth) { + mIsNotificationPanelFullWidth = isFullWidth; + } + + @Override public void setQsExpansion(float expansion, float panelExpansionFraction, float proposedTranslation, float squishinessFraction) { float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation; - float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD - ? mFullShadeProgress : panelExpansionFraction; - setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1); + float alphaProgress = calculateAlphaProgress(panelExpansionFraction); + setAlphaAnimationProgress(alphaProgress); mContainer.setExpansion(expansion); final float translationScaleY = (mInSplitShade ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); @@ -684,10 +698,43 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } else if (progress > 0 && view.getVisibility() != View.VISIBLE) { view.setVisibility((View.VISIBLE)); } - float alpha = mQSPanelController.isBouncerInTransit() - ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress) - : ShadeInterpolation.getContentAlpha(progress); - view.setAlpha(alpha); + view.setAlpha(interpolateAlphaAnimationProgress(progress)); + } + + private float calculateAlphaProgress(float panelExpansionFraction) { + if (mIsNotificationPanelFullWidth) { + // Small screens. QS alpha is not animated. + return 1; + } + if (mInSplitShade) { + // Large screens in landscape. + if (mTransitioningToFullShade || isKeyguardState()) { + // Always use "mFullShadeProgress" on keyguard, because + // "panelExpansionFractions" is always 1 on keyguard split shade. + return mFullShadeProgress; + } else { + return panelExpansionFraction; + } + } + // Large screens in portrait. + if (mTransitioningToFullShade) { + // Only use this value during the standard lock screen shade expansion. During the + // "quick" expansion from top, this value is 0. + return mFullShadeProgress; + } else { + return panelExpansionFraction; + } + } + + private float interpolateAlphaAnimationProgress(float progress) { + if (mQSPanelController.isBouncerInTransit()) { + return BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress); + } + if (isKeyguardState()) { + // Alpha progress should be linear on lockscreen shade expansion. + return progress; + } + return ShadeInterpolation.getContentAlpha(progress); } private void updateQsBounds() { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index d5ba07ad95aa..c385e58b487c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -1341,6 +1341,9 @@ public final class NotificationPanelViewController extends PanelViewController { mIsFullWidth = isFullWidth; mScrimController.setClipsQsScrim(isFullWidth); mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth); + if (mQs != null) { + mQs.setIsNotificationPanelFullWidth(isFullWidth); + } } private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) { @@ -2450,8 +2453,8 @@ public final class NotificationPanelViewController extends PanelViewController { final float squishiness; if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) { squishiness = 1; - } else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) { - squishiness = mLockscreenShadeTransitionController.getQSDragProgress(); + } else if (mTransitioningToFullShadeProgress > 0.0f) { + squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction(); } else { squishiness = mNotificationStackScrollLayoutController .getNotificationSquishinessFraction(); @@ -3739,6 +3742,7 @@ public final class NotificationPanelViewController extends PanelViewController { mQs.setHeaderClickable(isQsExpansionEnabled()); mQs.setOverscrolling(mStackScrollerOverscrolling); mQs.setInSplitShade(mSplitShadeEnabled); + mQs.setIsNotificationPanelFullWidth(mIsFullWidth); // recompute internal state when qspanel height changes mQs.getView().addOnLayoutChangeListener( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt new file mode 100644 index 000000000000..62c225ba0b4e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar + +import android.content.Context +import android.util.IndentingPrintWriter +import android.util.MathUtils +import androidx.annotation.FloatRange +import androidx.annotation.Px +import com.android.systemui.R +import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.qs.QS +import com.android.systemui.statusbar.policy.ConfigurationController +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlin.math.max + +/** Responsible for the QS components during the lockscreen shade transition. */ +class LockscreenShadeQsTransitionController +@AssistedInject +constructor( + context: Context, + configurationController: ConfigurationController, + dumpManager: DumpManager, + @Assisted private val qsProvider: () -> QS, +) : AbstractLockscreenShadeTransitionController(context, configurationController, dumpManager) { + + private val qs: QS + get() = qsProvider() + + /** + * The progress fraction of the QS transition during lockscreen shade expansion. + * + * Note that this value might be 0 for some time when the expansion is already in progress, + * since there is a transition start delay for QS on some device configurations. For this + * reason, don't use this value to check whether the shade expansion is in progress. + */ + @FloatRange(from = 0.0, to = 1.0) + var qsTransitionFraction = 0f + private set + + /** + * The fraction of the QS "squish" transition progress during lockscreen shade expansion. + * + * Note that in some device configurations (large screens) this value can start at a value + * greater than 0. For this reason don't use this value to check whether the QS transition has + * started or not. + */ + @FloatRange(from = 0.0, to = 1.0) + var qsSquishTransitionFraction = 0f + private set + + /** + * The drag down amount, in pixels __for the QS transition__, also taking into account the + * [qsTransitionStartDelay]. + * + * Since it takes into account the start delay, it is __not__ the same as the raw drag down + * amount from the shade expansion. + */ + @Px private var qsDragDownAmount = 0f + + /** + * Distance it takes for the QS transition to complete during the lockscreen shade expansion. + */ + @Px private var qsTransitionDistance = 0 + + /** Distance delay for the QS transition to start during the lockscreen shade expansion. */ + @Px private var qsTransitionStartDelay = 0 + + /** + * Distance that it takes to complete the QS "squish" transition during the lockscreen shade + * expansion. + */ + @Px private var qsSquishTransitionDistance = 0 + + /** + * Whether the transition to full shade is in progress. Might be `true` even though + * [qsTransitionFraction] is still 0, due to [qsTransitionStartDelay]. + */ + private var isTransitioningToFullShade = false + + /** + * The fraction at which the QS "squish" transition should start during the lockscreen shade + * expansion. + * + * 0 is fully collapsed, 1 is fully expanded. + */ + @FloatRange(from = 0.0, to = 1.0) private var qsSquishStartFraction = 0f + + override fun updateResources() { + qsTransitionDistance = + context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance) + qsTransitionStartDelay = + context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_delay) + qsSquishTransitionDistance = + context.resources.getDimensionPixelSize( + R.dimen.lockscreen_shade_qs_squish_transition_distance + ) + qsSquishStartFraction = + context.resources.getFloat(R.dimen.lockscreen_shade_qs_squish_start_fraction) + + qsSquishTransitionFraction = max(qsSquishTransitionFraction, qsSquishStartFraction) + } + + override fun onDragDownAmountChanged(dragDownAmount: Float) { + qsDragDownAmount = dragDownAmount - qsTransitionStartDelay + qsTransitionFraction = MathUtils.saturate(qsDragDownAmount / qsTransitionDistance) + qsSquishTransitionFraction = + MathUtils.lerp( + /* start= */ qsSquishStartFraction, + /* stop= */ 1f, + /* amount= */ MathUtils.saturate(qsDragDownAmount / qsSquishTransitionDistance) + ) + isTransitioningToFullShade = dragDownAmount > 0.0f + qs.setTransitionToFullShadeProgress( + isTransitioningToFullShade, + qsTransitionFraction, + qsSquishTransitionFraction + ) + } + + override fun dump(pw: IndentingPrintWriter) { + pw.println( + """ + Resources: + qsTransitionDistance: $qsTransitionDistance + qsTransitionStartDelay: $qsTransitionStartDelay + qsSquishTransitionDistance: $qsSquishTransitionDistance + qsSquishStartFraction: $qsSquishStartFraction + State: + dragDownAmount: $dragDownAmount + qsDragDownAmount: $qsDragDownAmount + qsDragFraction: $qsTransitionFraction + qsSquishFraction: $qsSquishTransitionFraction + isTransitioningToFullShade: $isTransitioningToFullShade + """.trimIndent() + ) + } + + @AssistedFactory + fun interface Factory { + fun create(qsProvider: () -> QS): LockscreenShadeQsTransitionController + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 74d8f1beaec1..1ad7ee778202 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -12,6 +12,7 @@ import android.util.MathUtils import android.view.MotionEvent import android.view.View import android.view.ViewConfiguration +import androidx.annotation.FloatRange import androidx.annotation.VisibleForTesting import com.android.systemui.Dumpable import com.android.systemui.ExpandHelper @@ -69,7 +70,8 @@ class LockscreenShadeTransitionController @Inject constructor( wakefulnessLifecycle: WakefulnessLifecycle, configurationController: ConfigurationController, falsingManager: FalsingManager, - dumpManager: DumpManager + dumpManager: DumpManager, + qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory, ) : Dumpable { private var pulseHeight: Float = 0f @get:VisibleForTesting @@ -121,12 +123,6 @@ class LockscreenShadeTransitionController @Inject constructor( private var notificationShelfTransitionDistance = 0 /** - * Distance that the full shade transition takes in order for the Quick Settings to fully fade - * and expand. - */ - private var qsTransitionDistance = 0 - - /** * Distance that the full shade transition takes in order for depth of the wallpaper to fully * change. */ @@ -189,6 +185,18 @@ class LockscreenShadeTransitionController @Inject constructor( keyguardTransitionControllerFactory.create(notificationPanelController) } + private val qsTransitionController = qsTransitionControllerFactory.create { qS } + + /** See [LockscreenShadeQsTransitionController.qsTransitionFraction].*/ + @get:FloatRange(from = 0.0, to = 1.0) + val qSDragProgress: Float + get() = qsTransitionController.qsTransitionFraction + + /** See [LockscreenShadeQsTransitionController.qsSquishTransitionFraction].*/ + @get:FloatRange(from = 0.0, to = 1.0) + val qsSquishTransitionFraction: Float + get() = qsTransitionController.qsSquishTransitionFraction + /** * [LockScreenShadeOverScroller] property that delegates to either * [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller]. @@ -243,8 +251,6 @@ class LockscreenShadeTransitionController @Inject constructor( R.dimen.lockscreen_shade_transition_by_tap_distance) notificationShelfTransitionDistance = context.resources.getDimensionPixelSize( R.dimen.lockscreen_shade_notif_shelf_transition_distance) - qsTransitionDistance = context.resources.getDimensionPixelSize( - R.dimen.lockscreen_shade_qs_transition_distance) depthControllerTransitionDistance = context.resources.getDimensionPixelSize( R.dimen.lockscreen_shade_depth_controller_transition_distance) udfpsTransitionDistance = context.resources.getDimensionPixelSize( @@ -412,8 +418,7 @@ class LockscreenShadeTransitionController @Inject constructor( MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance) nsslController.setTransitionToFullShadeAmount(fractionToShade) - qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance) - qS.setTransitionToFullShadeAmount(field, qSDragProgress) + qsTransitionController.dragDownAmount = value notificationPanelController.setTransitionToFullShadeAmount(field, false /* animate */, 0 /* delay */) @@ -427,12 +432,6 @@ class LockscreenShadeTransitionController @Inject constructor( } } - /** - * The drag progress of the quick settings drag down amount - */ - var qSDragProgress = 0f - private set - private fun transitionToShadeAmountCommon(dragDownAmount: Float) { if (depthControllerTransitionDistance == 0) { // split shade depthController.transitionToFullShadeProgress = 0f @@ -705,7 +704,6 @@ class LockscreenShadeTransitionController @Inject constructor( it.println("pulseHeight: $pulseHeight") it.println("useSplitShade: $useSplitShade") it.println("dragDownAmount: $dragDownAmount") - it.println("qSDragProgress: $qSDragProgress") it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled") it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded") it.println("isWakingToShadeLocked: $isWakingToShadeLocked") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index cb0a1480c233..4d1c3617ac1a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -259,11 +259,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private boolean mKeyguardOccluded; @Inject - public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters, - AlarmManager alarmManager, KeyguardStateController keyguardStateController, - DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler, - KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager, - ConfigurationController configurationController, @Main Executor mainExecutor, + public ScrimController( + LightBarController lightBarController, + DozeParameters dozeParameters, + AlarmManager alarmManager, + KeyguardStateController keyguardStateController, + DelayedWakeLock.Builder delayedWakeLockBuilder, + Handler handler, + KeyguardUpdateMonitor keyguardUpdateMonitor, + DockManager dockManager, + ConfigurationController configurationController, + @Main Executor mainExecutor, ScreenOffAnimationController screenOffAnimationController, KeyguardUnlockAnimationController keyguardUnlockAnimationController, StatusBarKeyguardViewManager statusBarKeyguardViewManager) { @@ -826,20 +832,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mBehindTint = Color.BLACK; } else { mBehindAlpha = behindAlpha; - if (mState == ScrimState.SHADE_LOCKED) { + if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) { + mNotificationsAlpha = MathUtils + .saturate(mTransitionToLockScreenFullShadeNotificationsProgress); + } else if (mState == ScrimState.SHADE_LOCKED) { // going from KEYGUARD to SHADE_LOCKED state mNotificationsAlpha = getInterpolatedFraction(); } else { mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion); } - if (mState == ScrimState.KEYGUARD - && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) { - // Interpolate the notification alpha when transitioning! - mNotificationsAlpha = MathUtils.lerp( - mNotificationsAlpha, - getInterpolatedFraction(), - mTransitionToLockScreenFullShadeNotificationsProgress); - } mNotificationsTint = mState.getNotifTint(); mBehindTint = behindTint; } @@ -1430,6 +1431,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump pw.print(mNotificationsAlpha); pw.print(" tint=0x"); pw.println(Integer.toHexString(mNotificationsScrim.getTint())); + pw.print(" expansionProgress="); + pw.println(mTransitionToLockScreenFullShadeNotificationsProgress); pw.print(" mTracking="); pw.println(mTracking); 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 f08ad2453c5f..5d5918de3d9e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -94,6 +94,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { @Mock private QSPanel.QSTileLayout mQQsTileLayout; @Mock private QSAnimator mQSAnimator; @Mock private StatusBarStateController mStatusBarStateController; + @Mock private QSSquishinessController mSquishinessController; private View mQsFragmentView; public QSFragmentTest() { @@ -139,13 +140,15 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { } @Test - public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() { + public void transitionToFullShade_setsAlphaUsingShadeInterpolator() { QSFragment fragment = resumeAndGetFragment(); - enableSplitShade(); - int transitionPxAmount = 123; + setStatusBarState(StatusBarState.SHADE); + boolean isTransitioningToFullShade = true; float transitionProgress = 0.5f; + float squishinessFraction = 0.5f; - fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); assertThat(mQsFragmentView.getAlpha()) .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress)); @@ -153,31 +156,32 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { @Test public void - transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() { + transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() { QSFragment fragment = resumeAndGetFragment(); - enableSplitShade(); setStatusBarState(StatusBarState.KEYGUARD); when(mQSPanelController.isBouncerInTransit()).thenReturn(false); - int transitionPxAmount = 123; + boolean isTransitioningToFullShade = true; float transitionProgress = 0.5f; + float squishinessFraction = 0.5f; - fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); - assertThat(mQsFragmentView.getAlpha()) - .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress)); + assertThat(mQsFragmentView.getAlpha()).isEqualTo(transitionProgress); } @Test public void - transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() { + transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() { QSFragment fragment = resumeAndGetFragment(); - enableSplitShade(); setStatusBarState(StatusBarState.KEYGUARD); when(mQSPanelController.isBouncerInTransit()).thenReturn(true); - int transitionPxAmount = 123; + boolean isTransitioningToFullShade = true; float transitionProgress = 0.5f; + float squishinessFraction = 0.5f; - fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); assertThat(mQsFragmentView.getAlpha()) .isEqualTo( @@ -186,28 +190,44 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { } @Test - public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() { + public void transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1() { QSFragment fragment = resumeAndGetFragment(); - disableSplitShade(); + fragment.setIsNotificationPanelFullWidth(true); - int transitionPxAmount = 12; + boolean isTransitioningToFullShade = true; float transitionProgress = 0.1f; - fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + float squishinessFraction = 0.5f; + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); - transitionPxAmount = 123; transitionProgress = 0.5f; - fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); - transitionPxAmount = 234; transitionProgress = 0.7f; - fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); } @Test + public void transitionToFullShade_setsSquishinessOnController() { + QSFragment fragment = resumeAndGetFragment(); + boolean isTransitioningToFullShade = true; + float transitionProgress = 0.123f; + float squishinessFraction = 0.456f; + + fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, + squishinessFraction); + + verify(mQsFragmentComponent.getQSSquishinessController()) + .setSquishiness(squishinessFraction); + } + + @Test public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() { // Random test values without any meaning. They just have to be different from each other. float expansion = 0.123f; @@ -453,6 +473,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { when(mQsFragmentComponent.getQSFooterActionController()) .thenReturn(mQSFooterActionController); when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator); + when(mQsFragmentComponent.getQSSquishinessController()).thenReturn(mSquishinessController); } private QSFragment getFragment() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index f2670131081f..6aaa5e689111 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -42,7 +42,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.IdRes; -import android.app.ActivityManager; import android.content.ContentResolver; import android.content.res.Configuration; import android.content.res.Resources; @@ -57,6 +56,7 @@ import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewPropertyAnimator; import android.view.ViewStub; @@ -107,6 +107,7 @@ import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qrcodescanner.controller.QRCodeScannerController; +import com.android.systemui.qs.QSFragment; import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.shade.transition.ShadeTransitionController; import com.android.systemui.statusbar.CommandQueue; @@ -160,8 +161,6 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.time.SystemClock; import com.android.systemui.wallet.controller.QuickAccessWalletController; @@ -185,225 +184,134 @@ import java.util.Optional; public class NotificationPanelViewControllerTest extends SysuiTestCase { private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50; + private static final int PANEL_WIDTH = 500; // Random value just for the test. + + @Mock private CentralSurfaces mCentralSurfaces; + @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; + @Mock private KeyguardBottomAreaView mKeyguardBottomArea; + @Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController; + @Mock private KeyguardBottomAreaView mQsFrame; + @Mock private NotificationIconAreaController mNotificationAreaController; + @Mock private HeadsUpManagerPhone mHeadsUpManager; + @Mock private NotificationShelfController mNotificationShelfController; + @Mock private KeyguardStatusBarView mKeyguardStatusBar; + @Mock private KeyguardUserSwitcherView mUserSwitcherView; + @Mock private ViewStub mUserSwitcherStubView; + @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback; + @Mock private KeyguardUpdateMonitor mUpdateMonitor; + @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock private DozeParameters mDozeParameters; + @Mock private ScreenOffAnimationController mScreenOffAnimationController; + @Mock private NotificationPanelView mView; + @Mock private LayoutInflater mLayoutInflater; + @Mock private FeatureFlags mFeatureFlags; + @Mock private DynamicPrivacyController mDynamicPrivacyController; + @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; + @Mock private KeyguardStateController mKeyguardStateController; + @Mock private DozeLog mDozeLog; + @Mock private ShadeLogger mShadeLog; + @Mock private CommandQueue mCommandQueue; + @Mock private VibratorHelper mVibratorHelper; + @Mock private LatencyTracker mLatencyTracker; + @Mock private PowerManager mPowerManager; + @Mock private AccessibilityManager mAccessibilityManager; + @Mock private MetricsLogger mMetricsLogger; + @Mock private Resources mResources; + @Mock private Configuration mConfiguration; + @Mock private KeyguardClockSwitch mKeyguardClockSwitch; + @Mock private MediaHierarchyManager mMediaHiearchyManager; + @Mock private ConversationNotificationManager mConversationNotificationManager; + @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; + @Mock private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; + @Mock private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent; + @Mock private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; + @Mock private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; + @Mock private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent; + @Mock private KeyguardUserSwitcherController mKeyguardUserSwitcherController; + @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent; + @Mock private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; + @Mock private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; + @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; + @Mock private KeyguardStatusViewController mKeyguardStatusViewController; + @Mock private KeyguardStatusBarViewController mKeyguardStatusBarViewController; + @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; + @Mock private NotificationShadeDepthController mNotificationShadeDepthController; + @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController; + @Mock private AuthController mAuthController; + @Mock private ScrimController mScrimController; + @Mock private MediaDataManager mMediaDataManager; + @Mock private AmbientState mAmbientState; + @Mock private UserManager mUserManager; + @Mock private UiEventLogger mUiEventLogger; + @Mock private LockIconViewController mLockIconViewController; + @Mock private KeyguardMediaController mKeyguardMediaController; + @Mock private PrivacyDotViewController mPrivacyDotViewController; + @Mock private NavigationModeController mNavigationModeController; + @Mock private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController; + @Mock private ContentResolver mContentResolver; + @Mock private TapAgainViewController mTapAgainViewController; + @Mock private KeyguardIndicationController mKeyguardIndicationController; + @Mock private FragmentService mFragmentService; + @Mock private FragmentHostManager mFragmentHostManager; + @Mock private QuickAccessWalletController mQuickAccessWalletController; + @Mock private QRCodeScannerController mQrCodeScannerController; + @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager; + @Mock private RecordingController mRecordingController; + @Mock private ControlsComponent mControlsComponent; + @Mock private LockscreenGestureLogger mLockscreenGestureLogger; + @Mock private DumpManager mDumpManager; + @Mock private InteractionJankMonitor mInteractionJankMonitor; + @Mock private NotificationsQSContainerController mNotificationsQSContainerController; + @Mock private QsFrameTranslateController mQsFrameTranslateController; + @Mock private StatusBarWindowStateController mStatusBarWindowStateController; + @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + @Mock private NotificationShadeWindowController mNotificationShadeWindowController; + @Mock private SysUiState mSysUiState; + @Mock private NotificationListContainer mNotificationListContainer; + @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator; + @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + @Mock private ShadeTransitionController mShadeTransitionController; + @Mock private QS mQs; + @Mock private QSFragment mQSFragment; + @Mock private ViewGroup mQsHeader; + @Mock private ViewParent mViewParent; + @Mock private ViewTreeObserver mViewTreeObserver; + @Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel; + @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; - @Mock - private CentralSurfaces mCentralSurfaces; - @Mock - private NotificationStackScrollLayout mNotificationStackScrollLayout; - @Mock - private KeyguardBottomAreaView mKeyguardBottomArea; - @Mock - private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController; - @Mock - private KeyguardBottomAreaView mQsFrame; - private KeyguardStatusView mKeyguardStatusView; - @Mock - private NotificationIconAreaController mNotificationAreaController; - @Mock - private HeadsUpManagerPhone mHeadsUpManager; - @Mock - private NotificationShelfController mNotificationShelfController; - @Mock - private KeyguardStatusBarView mKeyguardStatusBar; - @Mock - private KeyguardUserSwitcherView mUserSwitcherView; - @Mock - private ViewStub mUserSwitcherStubView; - @Mock - private HeadsUpTouchHelper.Callback mHeadsUpCallback; - @Mock - private KeyguardUpdateMonitor mUpdateMonitor; - @Mock - private KeyguardBypassController mKeyguardBypassController; - @Mock - private DozeParameters mDozeParameters; - @Mock - private ScreenOffAnimationController mScreenOffAnimationController; - @Mock - private NotificationPanelView mView; - @Mock - private LayoutInflater mLayoutInflater; - @Mock - private FeatureFlags mFeatureFlags; - @Mock - private DynamicPrivacyController mDynamicPrivacyController; - @Mock - private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; - @Mock - private KeyguardStateController mKeyguardStateController; - @Mock - private DozeLog mDozeLog; - @Mock - private ShadeLogger mShadeLog; - @Mock - private CommandQueue mCommandQueue; - @Mock - private VibratorHelper mVibratorHelper; - @Mock - private LatencyTracker mLatencyTracker; - @Mock - private PowerManager mPowerManager; - @Mock - private AccessibilityManager mAccessibilityManager; - @Mock - private MetricsLogger mMetricsLogger; - @Mock - private ActivityManager mActivityManager; - @Mock - private Resources mResources; - @Mock - private Configuration mConfiguration; - private DisplayMetrics mDisplayMetrics = new DisplayMetrics(); - @Mock - private KeyguardClockSwitch mKeyguardClockSwitch; private NotificationPanelViewController.TouchHandler mTouchHandler; private ConfigurationController mConfigurationController; - @Mock - private MediaHierarchyManager mMediaHiearchyManager; - @Mock - private ConversationNotificationManager mConversationNotificationManager; - @Mock - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - @Mock - private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - @Mock - private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; - @Mock - private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent; - @Mock - private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; - @Mock - private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; - @Mock - private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent; - @Mock - private KeyguardUserSwitcherController mKeyguardUserSwitcherController; - @Mock - private KeyguardStatusViewComponent mKeyguardStatusViewComponent; - @Mock - private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; - @Mock - private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; - @Mock - private KeyguardClockSwitchController mKeyguardClockSwitchController; - @Mock - private KeyguardStatusViewController mKeyguardStatusViewController; - @Mock - private KeyguardStatusBarViewController mKeyguardStatusBarViewController; - @Mock - private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; - @Mock - private NotificationShadeDepthController mNotificationShadeDepthController; - @Mock - private LockscreenShadeTransitionController mLockscreenShadeTransitionController; - @Mock - private AuthController mAuthController; - @Mock - private ScrimController mScrimController; - @Mock - private MediaDataManager mMediaDataManager; - @Mock - private AmbientState mAmbientState; - @Mock - private UserManager mUserManager; - @Mock - private UiEventLogger mUiEventLogger; - @Mock - private LockIconViewController mLockIconViewController; - @Mock - private KeyguardMediaController mKeyguardMediaController; - @Mock - private PrivacyDotViewController mPrivacyDotViewController; - @Mock - private NavigationModeController mNavigationModeController; - @Mock - private SecureSettings mSecureSettings; - @Mock - private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController; - @Mock - private ContentResolver mContentResolver; - @Mock - private TapAgainViewController mTapAgainViewController; - @Mock - private KeyguardIndicationController mKeyguardIndicationController; - @Mock - private FragmentService mFragmentService; - @Mock - private FragmentHostManager mFragmentHostManager; - @Mock - private QuickAccessWalletController mQuickAccessWalletController; - @Mock - private QRCodeScannerController mQrCodeScannerController; - @Mock - private NotificationRemoteInputManager mNotificationRemoteInputManager; - @Mock - private RecordingController mRecordingController; - @Mock - private ControlsComponent mControlsComponent; - @Mock - private LockscreenGestureLogger mLockscreenGestureLogger; - @Mock - private DumpManager mDumpManager; - @Mock - private InteractionJankMonitor mInteractionJankMonitor; - @Mock - private NotificationsQSContainerController mNotificationsQSContainerController; - @Mock - private QsFrameTranslateController mQsFrameTranslateController; - @Mock - private StatusBarWindowStateController mStatusBarWindowStateController; - @Mock - private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; - @Mock - private NotificationShadeWindowController mNotificationShadeWindowController; - @Mock - private SysUiState mSysUiState; - @Mock - private NotificationListContainer mNotificationListContainer; - @Mock - private NotificationStackSizeCalculator mNotificationStackSizeCalculator; - @Mock - private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; - @Mock - private ShadeTransitionController mShadeTransitionController; - @Mock - private QS mQs; - @Mock - private View mQsHeader; - @Mock - private ViewParent mViewParent; - @Mock - private ViewTreeObserver mViewTreeObserver; - @Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel; - @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; - private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter; - private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty(); private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; private View.AccessibilityDelegate mAccessibiltyDelegate; private NotificationsQuickSettingsContainer mNotificationContainerParent; private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners; - private FalsingManagerFake mFalsingManager = new FalsingManagerFake(); - private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private Handler mMainHandler; + private View.OnLayoutChangeListener mLayoutChangeListener; + + private final FalsingManagerFake mFalsingManager = new FalsingManagerFake(); + private final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty(); + private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); private final PanelExpansionStateManager mPanelExpansionStateManager = new PanelExpansionStateManager(); - private SystemClock mSystemClock; + private FragmentHostManager.FragmentListener mFragmentListener; @Before public void setup() { MockitoAnnotations.initMocks(this); - mSystemClock = new FakeSystemClock(); + SystemClock systemClock = new FakeSystemClock(); mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager, mInteractionJankMonitor); - mKeyguardStatusView = new KeyguardStatusView(mContext); - mKeyguardStatusView.setId(R.id.keyguard_status_view); + KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext); + keyguardStatusView.setId(R.id.keyguard_status_view); DejankUtils.setImmediate(true); when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false); when(mHeadsUpCallback.getContext()).thenReturn(mContext); when(mView.getResources()).thenReturn(mResources); + when(mView.getWidth()).thenReturn(PANEL_WIDTH); when(mResources.getConfiguration()).thenReturn(mConfiguration); mConfiguration.orientation = ORIENTATION_PORTRAIT; when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); @@ -431,7 +339,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mView.findViewById(R.id.keyguard_status_view)) .thenReturn(mock(KeyguardStatusView.class)); mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null); - mNotificationContainerParent.addView(mKeyguardStatusView); + mNotificationContainerParent.addView(keyguardStatusView); mNotificationContainerParent.onFinishInflate(); when(mView.findViewById(R.id.notification_container_parent)) .thenReturn(mNotificationContainerParent); @@ -447,7 +355,12 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController()) .thenReturn(mKeyguardUserSwitcherController); when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true); - + when(mQs.getView()).thenReturn(mView); + when(mQSFragment.getView()).thenReturn(mView); + doAnswer(invocation -> { + mFragmentListener = invocation.getArgument(1); + return null; + }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any()); doAnswer((Answer<Void>) invocation -> { mTouchHandler = invocation.getArgument(0); return null; @@ -484,7 +397,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController()) .thenReturn(mKeyguardStatusBarViewController); when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean())) - .thenReturn(mKeyguardStatusView); + .thenReturn(keyguardStatusView); when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean())) .thenReturn(mUserSwitcherView); when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean())) @@ -499,13 +412,18 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { ((Runnable) invocation.getArgument(0)).run(); return null; }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any()); + doAnswer(invocation -> { + mLayoutChangeListener = invocation.getArgument(0); + return null; + }).when(mView).addOnLayoutChangeListener(any()); when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mView.getParent()).thenReturn(mViewParent); when(mQs.getHeader()).thenReturn(mQsHeader); mMainHandler = new Handler(Looper.getMainLooper()); - mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter(); + NotificationPanelViewController.PanelEventsEmitter panelEventsEmitter = + new NotificationPanelViewController.PanelEventsEmitter(); mNotificationPanelViewController = new NotificationPanelViewController( mView, @@ -563,11 +481,11 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { () -> mKeyguardBottomAreaViewController, mKeyguardUnlockAnimationController, mNotificationListContainer, - mPanelEventsEmitter, + panelEventsEmitter, mNotificationStackSizeCalculator, mUnlockedScreenOffAnimationController, mShadeTransitionController, - mSystemClock, + systemClock, mock(CameraGestureHelper.class), () -> mKeyguardBottomAreaViewModel, () -> mKeyguardBottomAreaInteractor); @@ -1484,6 +1402,96 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance); } + @Test + public void onLayoutChange_fullWidth_updatesQSWithFullWithTrue() { + mNotificationPanelViewController.mQs = mQs; + + setIsFullWidth(true); + + verify(mQs).setIsNotificationPanelFullWidth(true); + } + + @Test + public void onLayoutChange_notFullWidth_updatesQSWithFullWithFalse() { + mNotificationPanelViewController.mQs = mQs; + + setIsFullWidth(false); + + verify(mQs).setIsNotificationPanelFullWidth(false); + } + + @Test + public void onLayoutChange_qsNotSet_doesNotCrash() { + mNotificationPanelViewController.mQs = null; + + triggerLayoutChange(); + } + + @Test + public void onQsFragmentAttached_fullWidth_setsFullWidthTrueOnQS() { + setIsFullWidth(true); + givenViewAttached(); + mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment); + + verify(mQSFragment).setIsNotificationPanelFullWidth(true); + } + + @Test + public void onQsFragmentAttached_notFullWidth_setsFullWidthFalseOnQS() { + setIsFullWidth(false); + givenViewAttached(); + mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment); + + verify(mQSFragment).setIsNotificationPanelFullWidth(false); + } + + @Test + public void setQsExpansion_lockscreenShadeTransitionInProgress_usesLockscreenSquishiness() { + float squishinessFraction = 0.456f; + mNotificationPanelViewController.mQs = mQs; + when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction()) + .thenReturn(squishinessFraction); + when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction()) + .thenReturn(0.987f); + // Call setTransitionToFullShadeAmount to get into the full shade transition in progress + // state. + mNotificationPanelViewController.setTransitionToFullShadeAmount( + /* pxAmount= */ 234, + /* animate= */ false, + /* delay= */ 0 + ); + + mNotificationPanelViewController.setQsExpansion(/* height= */ 123); + + // First for setTransitionToFullShadeAmount and then setQsExpansion + verify(mQs, times(2)).setQsExpansion( + /* expansion= */ anyFloat(), + /* panelExpansionFraction= */ anyFloat(), + /* proposedTranslation= */ anyFloat(), + eq(squishinessFraction) + ); + } + + @Test + public void setQsExpansion_lockscreenShadeTransitionNotInProgress_usesStandardSquishiness() { + float lsSquishinessFraction = 0.456f; + float nsslSquishinessFraction = 0.987f; + mNotificationPanelViewController.mQs = mQs; + when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction()) + .thenReturn(lsSquishinessFraction); + when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction()) + .thenReturn(nsslSquishinessFraction); + + mNotificationPanelViewController.setQsExpansion(/* height= */ 123); + + verify(mQs).setQsExpansion( + /* expansion= */ anyFloat(), + /* panelExpansionFraction= */ anyFloat(), + /* proposedTranslation= */ anyFloat(), + eq(nsslSquishinessFraction) + ); + } + private static MotionEvent createMotionEvent(int x, int y, int action) { return MotionEvent.obtain( /* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0); @@ -1507,12 +1515,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } } - private void givenViewDetached() { - for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) { - listener.onViewDetachedFromWindow(mView); - } - } - private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) { ConstraintSet constraintSet = new ConstraintSet(); constraintSet.clone(mNotificationContainerParent); @@ -1569,4 +1571,24 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo( R.id.qs_edge_guideline); } + + private void setIsFullWidth(boolean fullWidth) { + float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f; + when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth); + triggerLayoutChange(); + } + + private void triggerLayoutChange() { + mLayoutChangeListener.onLayoutChange( + mView, + /* left= */ 0, + /* top= */ 0, + /* right= */ 0, + /* bottom= */ 0, + /* oldLeft= */ 0, + /* oldTop= */ 0, + /* oldRight= */ 0, + /* oldBottom= */ 0 + ); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt new file mode 100644 index 000000000000..70412626420d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.qs.QS +import com.android.systemui.statusbar.policy.FakeConfigurationController +import com.google.common.truth.Expect +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class LockscreenShadeQsTransitionControllerTest : SysuiTestCase() { + + private val configurationController = FakeConfigurationController() + + @get:Rule val expect: Expect = Expect.create() + + @Mock private lateinit var dumpManager: DumpManager + @Mock private lateinit var qS: QS + + private lateinit var controller: LockscreenShadeQsTransitionController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + setTransitionDistance(TRANSITION_DISTANCE) + setTransitionDelay(TRANSITION_DELAY) + setSquishTransitionDistance(SQUISH_TRANSITION_DISTANCE) + setSquishStartFraction(SQUISH_START_FRACTION) + + controller = + LockscreenShadeQsTransitionController( + context, + configurationController, + dumpManager, + qsProvider = { qS } + ) + } + + @Test + fun qsTransitionFraction_byDefault_returns0() { + assertThat(controller.qsTransitionFraction).isZero() + } + + @Test + fun qsTransitionFraction_noStartDelay_returnsBasedOnTransitionDistance() { + setTransitionDelay(0) + setTransitionDistance(100) + + controller.dragDownAmount = 25f + expect.that(controller.qsTransitionFraction).isEqualTo(0.25f) + + controller.dragDownAmount = 50f + expect.that(controller.qsTransitionFraction).isEqualTo(0.5f) + + controller.dragDownAmount = 75f + expect.that(controller.qsTransitionFraction).isEqualTo(0.75f) + + controller.dragDownAmount = 100f + expect.that(controller.qsTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsTransitionFraction_noStartDelay_returnsValuesBetween0and1() { + setTransitionDelay(0) + setTransitionDistance(100) + + controller.dragDownAmount = -500f + expect.that(controller.qsTransitionFraction).isEqualTo(0f) + + controller.dragDownAmount = 500f + expect.that(controller.qsTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsTransitionFraction_withStartDelay_returnsBasedOnTransitionDistanceAndDelay() { + setTransitionDelay(10) + setTransitionDistance(100) + + controller.dragDownAmount = 0f + expect.that(controller.qsTransitionFraction).isEqualTo(0f) + + controller.dragDownAmount = 10f + expect.that(controller.qsTransitionFraction).isEqualTo(0f) + + controller.dragDownAmount = 25f + expect.that(controller.qsTransitionFraction).isEqualTo(0.15f) + + controller.dragDownAmount = 100f + expect.that(controller.qsTransitionFraction).isEqualTo(0.9f) + + controller.dragDownAmount = 110f + expect.that(controller.qsTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsTransitionFraction_withStartDelay_returnsValuesBetween0and1() { + setTransitionDelay(10) + setTransitionDistance(100) + + controller.dragDownAmount = -500f + expect.that(controller.qsTransitionFraction).isEqualTo(0f) + + controller.dragDownAmount = 500f + expect.that(controller.qsTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsSquishTransitionFraction_byDefault_returnsValueSetFromResource() { + assertThat(controller.qsSquishTransitionFraction).isEqualTo(SQUISH_START_FRACTION) + } + + @Test + fun qsSquishTransitionFraction_noStartDelay_startFraction0_returnsBasedOnTransitionDistance() { + setTransitionDelay(0) + setSquishStartFraction(0f) + setSquishTransitionDistance(1000) + + controller.dragDownAmount = 250f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.25f) + + controller.dragDownAmount = 500f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f) + + controller.dragDownAmount = 750f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f) + + controller.dragDownAmount = 1000f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsSquishTransitionFraction_startDelay_startFraction0_basedOnTransitionDistanceAndDelay() { + setTransitionDelay(100) + setSquishStartFraction(0f) + setSquishTransitionDistance(1000) + + controller.dragDownAmount = 250f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.15f) + + controller.dragDownAmount = 500f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.4f) + + controller.dragDownAmount = 750f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.65f) + + controller.dragDownAmount = 1000f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.9f) + + controller.dragDownAmount = 1100f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsSquishTransitionFraction_noStartDelay_startFractionSet_returnsBasedOnStartAndDistance() { + setTransitionDelay(0) + setSquishStartFraction(0.5f) + setSquishTransitionDistance(1000) + + controller.dragDownAmount = 0f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f) + + controller.dragDownAmount = 500f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f) + + controller.dragDownAmount = 1000f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f) + } + + @Test + fun qsSquishTransitionFraction_startDelay_startFractionSet_basedOnStartAndDistanceAndDelay() { + setTransitionDelay(10) + setSquishStartFraction(0.5f) + setSquishTransitionDistance(100) + + controller.dragDownAmount = 0f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f) + + controller.dragDownAmount = 50f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.7f) + + controller.dragDownAmount = 100f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.95f) + + controller.dragDownAmount = 110f + expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f) + } + + @Test + fun onDragDownAmountChanged_setsValuesOnQS() { + val rawDragAmount = 200f + + controller.dragDownAmount = rawDragAmount + + verify(qS) + .setTransitionToFullShadeProgress( + /* isTransitioningToFullShade= */ true, + /* transitionFraction= */ controller.qsTransitionFraction, + /* squishinessFraction= */ controller.qsSquishTransitionFraction + ) + } + + private fun setTransitionDistance(value: Int) { + overrideResource(R.dimen.lockscreen_shade_qs_transition_distance, value) + configurationController.notifyConfigurationChanged() + } + + private fun setTransitionDelay(value: Int) { + overrideResource(R.dimen.lockscreen_shade_qs_transition_delay, value) + configurationController.notifyConfigurationChanged() + } + + private fun setSquishTransitionDistance(value: Int) { + overrideResource(R.dimen.lockscreen_shade_qs_squish_transition_distance, value) + configurationController.notifyConfigurationChanged() + } + + private fun setSquishStartFraction(value: Float) { + overrideResource(R.dimen.lockscreen_shade_qs_squish_start_fraction, value) + configurationController.notifyConfigurationChanged() + } + + companion object { + private const val TRANSITION_DELAY = 123 + private const val TRANSITION_DISTANCE = 321 + private const val SQUISH_START_FRACTION = 0.123f + private const val SQUISH_TRANSITION_DISTANCE = 456 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index fe1cd978ef91..8643e86acef2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -1,9 +1,9 @@ package com.android.systemui.statusbar -import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest import com.android.systemui.ExpandHelper import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -78,6 +78,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Mock lateinit var qS: QS @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller + @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController @JvmField @Rule val mockito = MockitoJUnit.rule() private val configurationController = FakeConfigurationController() @@ -120,7 +121,9 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { context, configurationController, dumpManager) - }) + }, + qsTransitionControllerFactory = { qsTransitionController }, + ) whenever(nsslController.view).thenReturn(stackscroller) whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback) transitionController.notificationPanelController = notificationPanelController @@ -249,7 +252,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat()) verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong()) - verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) + verify(qsTransitionController, never()).dragDownAmount = anyFloat() } @Test @@ -260,7 +263,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat()) verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong()) - verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) + verify(qsTransitionController).dragDownAmount = 10f verify(depthController).transitionToFullShadeProgress = anyFloat() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 7cd275db1ed6..4d1a52c494ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -59,16 +59,19 @@ import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.scrim.ScrimView; -import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.FakeConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.utils.os.FakeHandler; +import com.google.common.truth.Expect; + import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -86,6 +89,11 @@ import java.util.Map; @SmallTest public class ScrimControllerTest extends SysuiTestCase { + @Rule public Expect mExpect = Expect.create(); + + private final FakeConfigurationController mConfigurationController = + new FakeConfigurationController(); + private ScrimController mScrimController; private ScrimView mScrimBehind; private ScrimView mNotificationsScrim; @@ -96,32 +104,19 @@ public class ScrimControllerTest extends SysuiTestCase { private int mScrimVisibility; private boolean mAlwaysOnEnabled; private TestableLooper mLooper; - @Mock - private AlarmManager mAlarmManager; - @Mock - private DozeParameters mDozeParameters; - @Mock - LightBarController mLightBarController; - @Mock - DelayedWakeLock.Builder mDelayedWakeLockBuilder; - @Mock - private DelayedWakeLock mWakeLock; - @Mock - KeyguardStateController mKeyguardStateController; - @Mock - KeyguardUpdateMonitor mKeyguardUpdateMonitor; - @Mock - private DockManager mDockManager; - @Mock - private ConfigurationController mConfigurationController; - @Mock - private ScreenOffAnimationController mScreenOffAnimationController; - @Mock - private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + @Mock private AlarmManager mAlarmManager; + @Mock private DozeParameters mDozeParameters; + @Mock private LightBarController mLightBarController; + @Mock private DelayedWakeLock.Builder mDelayedWakeLockBuilder; + @Mock private DelayedWakeLock mWakeLock; + @Mock private KeyguardStateController mKeyguardStateController; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock private DockManager mDockManager; + @Mock private ScreenOffAnimationController mScreenOffAnimationController; + @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) - @Mock - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private static class AnimatorListener implements Animator.AnimatorListener { private int mNumStarts; @@ -1450,6 +1445,41 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + public void notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress() { + mScrimController.setClipsQsScrim(false); + mScrimController.transitionTo(ScrimState.KEYGUARD); + // RawPanelExpansion and QsExpansion are usually used for the notification alpha + // calculation. + // Here we set them to non-zero values explicitly to make sure that in not clipped mode, + // they are not being used even when set. + mScrimController.setRawPanelExpansionFraction(0.5f); + mScrimController.setQsPosition(/* expansionFraction= */ 0.5f, /* qsPanelBottomY= */ 500); + finishAnimationsImmediately(); + + float progress = 0.5f; + + float notificationExpansionProgress = 0f; + mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress); + mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress); + + notificationExpansionProgress = 0.25f; + mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress); + mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress); + + notificationExpansionProgress = 0.5f; + mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress); + mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress); + + notificationExpansionProgress = 0.75f; + mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress); + mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress); + + notificationExpansionProgress = 1f; + mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress); + mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress); + } + + @Test public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() { int overScrollAmount = 10; |