[Large screens][Motion] Improve expansion timing on lockscreen
- Adds more xml resource configs to be able to more precisely control
the expansion transition:
- QS transition start delay
- QS squish transition distance
- QS squish transition start fraction
- On split shade:
- Fades in notifications scrim later
- Fades in QS earlier
- QS squshiness starts at 0.5 instead of 0
- On large screen portrait:
- Fades in QS and notifications only after the behind scrim finished
fading in
- QS squshiness starts at 0.5 instead of 0
Change-Id: Id0941d11fe194c8be74f6101cf6f9f7d22888fc9
Test: QSFragmentTest.java
Test: NotificationPanelViewControllerTest.java
Test: ScrimControllerTest.java
Test: LockscreenShadeQsTransitionControllerTest.kt
Test: LockscreenShadeTransitionControllerTest.kt
Test: Manually
Bug: 239904136
(cherry picked from commit ae32ffdaedbe2acdf56cf8931063d468b1b93948)
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 57193e7..436145e 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 @@
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 @@
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 @@
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 d638c9d..f4d4824 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 008299b..a587e5a 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 4136b04..342a416 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1210,6 +1210,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 05b3eae..90fa94c 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.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 @@
// 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 @@
}
@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 @@
}
@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);
@@ -683,10 +697,43 @@
} 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 c3b265f..156b123 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1320,6 +1320,9 @@
mIsFullWidth = isFullWidth;
mScrimController.setClipsQsScrim(isFullWidth);
mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
+ if (mQs != null) {
+ mQs.setIsNotificationPanelFullWidth(isFullWidth);
+ }
}
private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -2428,8 +2431,8 @@
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();
@@ -3716,6 +3719,7 @@
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 0000000..62c225b
--- /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 d3343df..8006931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -11,6 +11,7 @@
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
@@ -68,7 +69,8 @@
wakefulnessLifecycle: WakefulnessLifecycle,
configurationController: ConfigurationController,
falsingManager: FalsingManager,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
+ qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
) : Dumpable {
private var pulseHeight: Float = 0f
@get:VisibleForTesting
@@ -120,12 +122,6 @@
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.
*/
@@ -188,6 +184,18 @@
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].
@@ -242,8 +250,6 @@
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(
@@ -411,8 +417,7 @@
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 */)
@@ -426,12 +431,6 @@
}
}
- /**
- * 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
@@ -704,7 +703,6 @@
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 cb0a148..4d1c361 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 @@
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 @@
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 @@
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 f08ad24..5d5918d 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 @@
@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 @@
}
@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 @@
@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 @@
}
@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 @@
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 3224a6f..f1c54ef 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.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.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.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.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 @@
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;
- 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 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;
- private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
- private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+
+ private NotificationPanelViewController.TouchHandler mTouchHandler;
+ private ConfigurationController mConfigurationController;
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 @@
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 @@
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 @@
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 @@
((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,
@@ -560,11 +478,11 @@
() -> mKeyguardBottomAreaViewController,
mKeyguardUnlockAnimationController,
mNotificationListContainer,
- mPanelEventsEmitter,
+ panelEventsEmitter,
mNotificationStackSizeCalculator,
mUnlockedScreenOffAnimationController,
mShadeTransitionController,
- mSystemClock,
+ systemClock,
mock(CameraGestureHelper.class),
mKeyguardBottomAreaViewModel,
mKeyguardBottomAreaInteractor);
@@ -1481,6 +1399,96 @@
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);
@@ -1504,12 +1512,6 @@
}
}
- 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);
@@ -1566,4 +1568,24 @@
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 0000000..7041262
--- /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 fe1cd97..8643e86 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 @@
@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 @@
context,
configurationController,
dumpManager)
- })
+ },
+ qsTransitionControllerFactory = { qsTransitionController },
+ )
whenever(nsslController.view).thenReturn(stackscroller)
whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
transitionController.notificationPanelController = notificationPanelController
@@ -249,7 +252,7 @@
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 @@
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 7cd275d..4d1a52c 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.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 @@
@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 @@
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 @@
}
@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;