Merge "[Large screens][Motion] Improve expansion timing on lockscreen" into tm-qpr-dev

This commit is contained in:
Alex Florescu
2022-09-14 12:22:01 +00:00
committed by Android (Google) Code Review
14 changed files with 915 additions and 339 deletions

View File

@@ -16,6 +16,8 @@ package com.android.systemui.plugins.qs;
import android.view.View; import android.view.View;
import androidx.annotation.FloatRange;
import com.android.systemui.plugins.FragmentBase; import com.android.systemui.plugins.FragmentBase;
import com.android.systemui.plugins.annotations.DependsOn; import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface; import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -107,10 +109,24 @@ public interface QS extends FragmentBase {
void setInSplitShade(boolean shouldTranslate); void setInSplitShade(boolean shouldTranslate);
/** /**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full * Sets the progress of the transition to full shade on the lockscreen.
* shade. 0.0f means we're not transitioning yet. *
* @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. * A rounded corner clipping that makes QS feel as if it were behind everything.
@@ -139,6 +155,12 @@ public interface QS extends FragmentBase {
*/ */
default void setOverScrollAmount(int overScrollAmount) {} 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 * Callback for when QSPanel container is scrolled
*/ */

View File

@@ -49,54 +49,29 @@
<dimen name="status_view_margin_horizontal">8dp</dimen> <dimen name="status_view_margin_horizontal">8dp</dimen>
<!-- Distance that the full shade transition takes in order to complete by tapping on a button <!-- Lockscreen shade transition values -->
like "expand". -->
<dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen> <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> <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
<!-- Media transition distance = qs delay + qs distance -->
<!-- Distance that the full shade transition takes in order for media to fully transition to <dimen name="lockscreen_shade_media_transition_distance">129.28dp</dimen>
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) -->
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen> <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
<!-- The notifications scrim transition should start when the other scrims' transition is at <!-- The notifications scrim transition should start when the other scrims' transition is at
95%. --> 95%. -->
<dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen> <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' <!-- 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> <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> <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> <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_notifications_scrim_transition_distance</dimen>
<!-- Distance that the full shade transition takes in order for the Quick Settings to fully <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_notifications_scrim_transition_delay</dimen>
fade and expand. --> <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
<dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_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>
<!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully <!-- On split-shade, there should be no depth effect, so setting the value to 0. -->
change.
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> <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> <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_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> <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 <!-- Roughly the same distance as media on LS to media on QS. We will translate by this value

View File

@@ -73,4 +73,24 @@
<dimen name="large_dialog_width">472dp</dimen> <dimen name="large_dialog_width">472dp</dimen>
<dimen name="large_screen_shade_header_height">42dp</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> </resources>

View File

@@ -1212,6 +1212,17 @@
fade and expand. --> fade and expand. -->
<dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> <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 <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
change. --> change. -->
<dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen> <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>

View File

@@ -34,6 +34,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import androidx.annotation.FloatRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
@@ -166,6 +167,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
// visible; // visible;
private boolean mQsVisible; 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 @Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler, public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
QSTileHost qsTileHost, QSTileHost qsTileHost,
@@ -571,15 +579,17 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
} }
@Override @Override
public void setTransitionToFullShadeAmount(float pxAmount, float progress) { public void setTransitionToFullShadeProgress(
boolean isTransitioningToFullShade = pxAmount > 0; boolean isTransitioningToFullShade,
@FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
@FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {
if (isTransitioningToFullShade != mTransitioningToFullShade) { if (isTransitioningToFullShade != mTransitioningToFullShade) {
mTransitioningToFullShade = isTransitioningToFullShade; mTransitioningToFullShade = isTransitioningToFullShade;
updateShowCollapsedOnKeyguard(); updateShowCollapsedOnKeyguard();
} }
mFullShadeProgress = progress; mFullShadeProgress = qsTransitionFraction;
setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation, setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
isTransitioningToFullShade ? progress : mSquishinessFraction); isTransitioningToFullShade ? qsSquishinessFraction : mSquishinessFraction);
} }
@Override @Override
@@ -597,13 +607,17 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
+ mHeader.getPaddingBottom(); + mHeader.getPaddingBottom();
} }
@Override
public void setIsNotificationPanelFullWidth(boolean isFullWidth) {
mIsNotificationPanelFullWidth = isFullWidth;
}
@Override @Override
public void setQsExpansion(float expansion, float panelExpansionFraction, public void setQsExpansion(float expansion, float panelExpansionFraction,
float proposedTranslation, float squishinessFraction) { float proposedTranslation, float squishinessFraction) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation; float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD float alphaProgress = calculateAlphaProgress(panelExpansionFraction);
? mFullShadeProgress : panelExpansionFraction; setAlphaAnimationProgress(alphaProgress);
setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1);
mContainer.setExpansion(expansion); mContainer.setExpansion(expansion);
final float translationScaleY = (mInSplitShade final float translationScaleY = (mInSplitShade
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
@@ -683,10 +697,43 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
} else if (progress > 0 && view.getVisibility() != View.VISIBLE) { } else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
view.setVisibility((View.VISIBLE)); view.setVisibility((View.VISIBLE));
} }
float alpha = mQSPanelController.isBouncerInTransit() view.setAlpha(interpolateAlphaAnimationProgress(progress));
? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress) }
: ShadeInterpolation.getContentAlpha(progress);
view.setAlpha(alpha); 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() { private void updateQsBounds() {

View File

@@ -1326,6 +1326,9 @@ public final class NotificationPanelViewController extends PanelViewController {
mIsFullWidth = isFullWidth; mIsFullWidth = isFullWidth;
mScrimController.setClipsQsScrim(isFullWidth); mScrimController.setClipsQsScrim(isFullWidth);
mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth); mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
if (mQs != null) {
mQs.setIsNotificationPanelFullWidth(isFullWidth);
}
} }
private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) { private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -2434,8 +2437,8 @@ public final class NotificationPanelViewController extends PanelViewController {
final float squishiness; final float squishiness;
if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) { if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) {
squishiness = 1; squishiness = 1;
} else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) { } else if (mTransitioningToFullShadeProgress > 0.0f) {
squishiness = mLockscreenShadeTransitionController.getQSDragProgress(); squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction();
} else { } else {
squishiness = mNotificationStackScrollLayoutController squishiness = mNotificationStackScrollLayoutController
.getNotificationSquishinessFraction(); .getNotificationSquishinessFraction();
@@ -3763,6 +3766,7 @@ public final class NotificationPanelViewController extends PanelViewController {
mQs.setHeaderClickable(isQsExpansionEnabled()); mQs.setHeaderClickable(isQsExpansionEnabled());
mQs.setOverscrolling(mStackScrollerOverscrolling); mQs.setOverscrolling(mStackScrollerOverscrolling);
mQs.setInSplitShade(mSplitShadeEnabled); mQs.setInSplitShade(mSplitShadeEnabled);
mQs.setIsNotificationPanelFullWidth(mIsFullWidth);
// recompute internal state when qspanel height changes // recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener( mQs.getView().addOnLayoutChangeListener(

View File

@@ -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
}
}

View File

@@ -11,6 +11,7 @@ import android.util.MathUtils
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewConfiguration import android.view.ViewConfiguration
import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable import com.android.systemui.Dumpable
import com.android.systemui.ExpandHelper import com.android.systemui.ExpandHelper
@@ -68,7 +69,8 @@ class LockscreenShadeTransitionController @Inject constructor(
wakefulnessLifecycle: WakefulnessLifecycle, wakefulnessLifecycle: WakefulnessLifecycle,
configurationController: ConfigurationController, configurationController: ConfigurationController,
falsingManager: FalsingManager, falsingManager: FalsingManager,
dumpManager: DumpManager dumpManager: DumpManager,
qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
) : Dumpable { ) : Dumpable {
private var pulseHeight: Float = 0f private var pulseHeight: Float = 0f
@get:VisibleForTesting @get:VisibleForTesting
@@ -119,12 +121,6 @@ class LockscreenShadeTransitionController @Inject constructor(
*/ */
private var notificationShelfTransitionDistance = 0 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 * Distance that the full shade transition takes in order for depth of the wallpaper to fully
* change. * change.
@@ -188,6 +184,18 @@ class LockscreenShadeTransitionController @Inject constructor(
keyguardTransitionControllerFactory.create(notificationPanelController) 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 * [LockScreenShadeOverScroller] property that delegates to either
* [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller]. * [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller].
@@ -242,8 +250,6 @@ class LockscreenShadeTransitionController @Inject constructor(
R.dimen.lockscreen_shade_transition_by_tap_distance) R.dimen.lockscreen_shade_transition_by_tap_distance)
notificationShelfTransitionDistance = context.resources.getDimensionPixelSize( notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_notif_shelf_transition_distance) R.dimen.lockscreen_shade_notif_shelf_transition_distance)
qsTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance)
depthControllerTransitionDistance = context.resources.getDimensionPixelSize( depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_depth_controller_transition_distance) R.dimen.lockscreen_shade_depth_controller_transition_distance)
udfpsTransitionDistance = context.resources.getDimensionPixelSize( udfpsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -411,8 +417,7 @@ class LockscreenShadeTransitionController @Inject constructor(
MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance) MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
nsslController.setTransitionToFullShadeAmount(fractionToShade) nsslController.setTransitionToFullShadeAmount(fractionToShade)
qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance) qsTransitionController.dragDownAmount = value
qS.setTransitionToFullShadeAmount(field, qSDragProgress)
notificationPanelController.setTransitionToFullShadeAmount(field, notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */) false /* animate */, 0 /* delay */)
@@ -426,12 +431,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) { private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
if (depthControllerTransitionDistance == 0) { // split shade if (depthControllerTransitionDistance == 0) { // split shade
depthController.transitionToFullShadeProgress = 0f depthController.transitionToFullShadeProgress = 0f
@@ -704,7 +703,6 @@ class LockscreenShadeTransitionController @Inject constructor(
it.println("pulseHeight: $pulseHeight") it.println("pulseHeight: $pulseHeight")
it.println("useSplitShade: $useSplitShade") it.println("useSplitShade: $useSplitShade")
it.println("dragDownAmount: $dragDownAmount") it.println("dragDownAmount: $dragDownAmount")
it.println("qSDragProgress: $qSDragProgress")
it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled") it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled")
it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded") it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded")
it.println("isWakingToShadeLocked: $isWakingToShadeLocked") it.println("isWakingToShadeLocked: $isWakingToShadeLocked")

View File

@@ -259,11 +259,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private boolean mKeyguardOccluded; private boolean mKeyguardOccluded;
@Inject @Inject
public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters, public ScrimController(
AlarmManager alarmManager, KeyguardStateController keyguardStateController, LightBarController lightBarController,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler, DozeParameters dozeParameters,
KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager, AlarmManager alarmManager,
ConfigurationController configurationController, @Main Executor mainExecutor, KeyguardStateController keyguardStateController,
DelayedWakeLock.Builder delayedWakeLockBuilder,
Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor,
DockManager dockManager,
ConfigurationController configurationController,
@Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController, ScreenOffAnimationController screenOffAnimationController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController, KeyguardUnlockAnimationController keyguardUnlockAnimationController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager) { StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
@@ -826,20 +832,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mBehindTint = Color.BLACK; mBehindTint = Color.BLACK;
} else { } else {
mBehindAlpha = behindAlpha; 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 // going from KEYGUARD to SHADE_LOCKED state
mNotificationsAlpha = getInterpolatedFraction(); mNotificationsAlpha = getInterpolatedFraction();
} else { } else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion); 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(); mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint; mBehindTint = behindTint;
} }
@@ -1430,6 +1431,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
pw.print(mNotificationsAlpha); pw.print(mNotificationsAlpha);
pw.print(" tint=0x"); pw.print(" tint=0x");
pw.println(Integer.toHexString(mNotificationsScrim.getTint())); pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
pw.print(" expansionProgress=");
pw.println(mTransitionToLockScreenFullShadeNotificationsProgress);
pw.print(" mTracking="); pw.print(" mTracking=");
pw.println(mTracking); pw.println(mTracking);

View File

@@ -94,6 +94,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
@Mock private QSPanel.QSTileLayout mQQsTileLayout; @Mock private QSPanel.QSTileLayout mQQsTileLayout;
@Mock private QSAnimator mQSAnimator; @Mock private QSAnimator mQSAnimator;
@Mock private StatusBarStateController mStatusBarStateController; @Mock private StatusBarStateController mStatusBarStateController;
@Mock private QSSquishinessController mSquishinessController;
private View mQsFragmentView; private View mQsFragmentView;
public QSFragmentTest() { public QSFragmentTest() {
@@ -139,13 +140,15 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
} }
@Test @Test
public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() { public void transitionToFullShade_setsAlphaUsingShadeInterpolator() {
QSFragment fragment = resumeAndGetFragment(); QSFragment fragment = resumeAndGetFragment();
enableSplitShade(); setStatusBarState(StatusBarState.SHADE);
int transitionPxAmount = 123; boolean isTransitioningToFullShade = true;
float transitionProgress = 0.5f; float transitionProgress = 0.5f;
float squishinessFraction = 0.5f;
fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
squishinessFraction);
assertThat(mQsFragmentView.getAlpha()) assertThat(mQsFragmentView.getAlpha())
.isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress)); .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
@@ -153,31 +156,32 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
@Test @Test
public void public void
transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() { transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() {
QSFragment fragment = resumeAndGetFragment(); QSFragment fragment = resumeAndGetFragment();
enableSplitShade();
setStatusBarState(StatusBarState.KEYGUARD); setStatusBarState(StatusBarState.KEYGUARD);
when(mQSPanelController.isBouncerInTransit()).thenReturn(false); when(mQSPanelController.isBouncerInTransit()).thenReturn(false);
int transitionPxAmount = 123; boolean isTransitioningToFullShade = true;
float transitionProgress = 0.5f; float transitionProgress = 0.5f;
float squishinessFraction = 0.5f;
fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
squishinessFraction);
assertThat(mQsFragmentView.getAlpha()) assertThat(mQsFragmentView.getAlpha()).isEqualTo(transitionProgress);
.isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
} }
@Test @Test
public void public void
transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() { transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() {
QSFragment fragment = resumeAndGetFragment(); QSFragment fragment = resumeAndGetFragment();
enableSplitShade();
setStatusBarState(StatusBarState.KEYGUARD); setStatusBarState(StatusBarState.KEYGUARD);
when(mQSPanelController.isBouncerInTransit()).thenReturn(true); when(mQSPanelController.isBouncerInTransit()).thenReturn(true);
int transitionPxAmount = 123; boolean isTransitioningToFullShade = true;
float transitionProgress = 0.5f; float transitionProgress = 0.5f;
float squishinessFraction = 0.5f;
fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
squishinessFraction);
assertThat(mQsFragmentView.getAlpha()) assertThat(mQsFragmentView.getAlpha())
.isEqualTo( .isEqualTo(
@@ -186,27 +190,43 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
} }
@Test @Test
public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() { public void transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1() {
QSFragment fragment = resumeAndGetFragment(); QSFragment fragment = resumeAndGetFragment();
disableSplitShade(); fragment.setIsNotificationPanelFullWidth(true);
int transitionPxAmount = 12; boolean isTransitioningToFullShade = true;
float transitionProgress = 0.1f; float transitionProgress = 0.1f;
fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); float squishinessFraction = 0.5f;
fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
squishinessFraction);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
transitionPxAmount = 123;
transitionProgress = 0.5f; transitionProgress = 0.5f;
fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
squishinessFraction);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
transitionPxAmount = 234;
transitionProgress = 0.7f; transitionProgress = 0.7f;
fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
squishinessFraction);
assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); 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 @Test
public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() { public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() {
// Random test values without any meaning. They just have to be different from each other. // Random test values without any meaning. They just have to be different from each other.
@@ -453,6 +473,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
when(mQsFragmentComponent.getQSFooterActionController()) when(mQsFragmentComponent.getQSFooterActionController())
.thenReturn(mQSFooterActionController); .thenReturn(mQSFooterActionController);
when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator); when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator);
when(mQsFragmentComponent.getQSSquishinessController()).thenReturn(mSquishinessController);
} }
private QSFragment getFragment() { private QSFragment getFragment() {

View File

@@ -42,7 +42,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.annotation.IdRes; import android.annotation.IdRes;
import android.app.ActivityManager;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
@@ -57,6 +56,7 @@ import android.util.DisplayMetrics;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent; import android.view.ViewParent;
import android.view.ViewPropertyAnimator; import android.view.ViewPropertyAnimator;
import android.view.ViewStub; 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.FalsingManager;
import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController; import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.transition.ShadeTransitionController; import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.CommandQueue; 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.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent; 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.FakeSystemClock;
import com.android.systemui.util.time.SystemClock; import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wallet.controller.QuickAccessWalletController; import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -186,225 +185,134 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400; private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50; 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 @Mock private CentralSurfaces mCentralSurfaces;
private CentralSurfaces mCentralSurfaces; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
@Mock @Mock private KeyguardBottomAreaView mKeyguardBottomArea;
private NotificationStackScrollLayout mNotificationStackScrollLayout; @Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
@Mock @Mock private KeyguardBottomAreaView mQsFrame;
private KeyguardBottomAreaView mKeyguardBottomArea; @Mock private NotificationIconAreaController mNotificationAreaController;
@Mock @Mock private HeadsUpManagerPhone mHeadsUpManager;
private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController; @Mock private NotificationShelfController mNotificationShelfController;
@Mock @Mock private KeyguardStatusBarView mKeyguardStatusBar;
private KeyguardBottomAreaView mQsFrame; @Mock private KeyguardUserSwitcherView mUserSwitcherView;
private KeyguardStatusView mKeyguardStatusView; @Mock private ViewStub mUserSwitcherStubView;
@Mock @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback;
private NotificationIconAreaController mNotificationAreaController; @Mock private KeyguardUpdateMonitor mUpdateMonitor;
@Mock @Mock private KeyguardBypassController mKeyguardBypassController;
private HeadsUpManagerPhone mHeadsUpManager; @Mock private DozeParameters mDozeParameters;
@Mock @Mock private ScreenOffAnimationController mScreenOffAnimationController;
private NotificationShelfController mNotificationShelfController; @Mock private NotificationPanelView mView;
@Mock @Mock private LayoutInflater mLayoutInflater;
private KeyguardStatusBarView mKeyguardStatusBar; @Mock private FeatureFlags mFeatureFlags;
@Mock @Mock private DynamicPrivacyController mDynamicPrivacyController;
private KeyguardUserSwitcherView mUserSwitcherView; @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@Mock @Mock private KeyguardStateController mKeyguardStateController;
private ViewStub mUserSwitcherStubView; @Mock private DozeLog mDozeLog;
@Mock @Mock private ShadeLogger mShadeLog;
private HeadsUpTouchHelper.Callback mHeadsUpCallback; @Mock private CommandQueue mCommandQueue;
@Mock @Mock private VibratorHelper mVibratorHelper;
private KeyguardUpdateMonitor mUpdateMonitor; @Mock private LatencyTracker mLatencyTracker;
@Mock @Mock private PowerManager mPowerManager;
private KeyguardBypassController mKeyguardBypassController; @Mock private AccessibilityManager mAccessibilityManager;
@Mock @Mock private MetricsLogger mMetricsLogger;
private DozeParameters mDozeParameters; @Mock private Resources mResources;
@Mock @Mock private Configuration mConfiguration;
private ScreenOffAnimationController mScreenOffAnimationController; @Mock private KeyguardClockSwitch mKeyguardClockSwitch;
@Mock @Mock private MediaHierarchyManager mMediaHiearchyManager;
private NotificationPanelView mView; @Mock private ConversationNotificationManager mConversationNotificationManager;
@Mock @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private LayoutInflater mLayoutInflater; @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@Mock @Mock private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
private FeatureFlags mFeatureFlags; @Mock private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
@Mock @Mock private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
private DynamicPrivacyController mDynamicPrivacyController; @Mock private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
@Mock @Mock private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; @Mock private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
@Mock @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
private KeyguardStateController mKeyguardStateController; @Mock private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
@Mock @Mock private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
private DozeLog mDozeLog; @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock @Mock private KeyguardStatusViewController mKeyguardStatusViewController;
private ShadeLogger mShadeLog; @Mock private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
@Mock @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private CommandQueue mCommandQueue; @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private VibratorHelper mVibratorHelper; @Mock private AuthController mAuthController;
@Mock @Mock private ScrimController mScrimController;
private LatencyTracker mLatencyTracker; @Mock private MediaDataManager mMediaDataManager;
@Mock @Mock private AmbientState mAmbientState;
private PowerManager mPowerManager; @Mock private UserManager mUserManager;
@Mock @Mock private UiEventLogger mUiEventLogger;
private AccessibilityManager mAccessibilityManager; @Mock private LockIconViewController mLockIconViewController;
@Mock @Mock private KeyguardMediaController mKeyguardMediaController;
private MetricsLogger mMetricsLogger; @Mock private PrivacyDotViewController mPrivacyDotViewController;
@Mock @Mock private NavigationModeController mNavigationModeController;
private ActivityManager mActivityManager; @Mock private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
@Mock @Mock private ContentResolver mContentResolver;
private Resources mResources; @Mock private TapAgainViewController mTapAgainViewController;
@Mock @Mock private KeyguardIndicationController mKeyguardIndicationController;
private Configuration mConfiguration; @Mock private FragmentService mFragmentService;
private DisplayMetrics mDisplayMetrics = new DisplayMetrics(); @Mock private FragmentHostManager mFragmentHostManager;
@Mock @Mock private QuickAccessWalletController mQuickAccessWalletController;
private KeyguardClockSwitch mKeyguardClockSwitch; @Mock private QRCodeScannerController mQrCodeScannerController;
private NotificationPanelViewController.TouchHandler mTouchHandler; @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
private ConfigurationController mConfigurationController; @Mock private RecordingController mRecordingController;
@Mock @Mock private ControlsComponent mControlsComponent;
private MediaHierarchyManager mMediaHiearchyManager; @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
@Mock @Mock private DumpManager mDumpManager;
private ConversationNotificationManager mConversationNotificationManager; @Mock private InteractionJankMonitor mInteractionJankMonitor;
@Mock @Mock private NotificationsQSContainerController mNotificationsQSContainerController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private QsFrameTranslateController mQsFrameTranslateController;
@Mock @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; @Mock private SysUiState mSysUiState;
@Mock @Mock private NotificationListContainer mNotificationListContainer;
private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent; @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Mock @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; @Mock private ShadeTransitionController mShadeTransitionController;
@Mock @Mock private QS mQs;
private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; @Mock private QSFragment mQSFragment;
@Mock @Mock private ViewGroup mQsHeader;
private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent; @Mock private ViewParent mViewParent;
@Mock @Mock private ViewTreeObserver mViewTreeObserver;
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 KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
@Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; @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 SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController; private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate; private View.AccessibilityDelegate mAccessibiltyDelegate;
private NotificationsQuickSettingsContainer mNotificationContainerParent; private NotificationsQuickSettingsContainer mNotificationContainerParent;
private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners; private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private Handler mMainHandler; 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 = private final PanelExpansionStateManager mPanelExpansionStateManager =
new PanelExpansionStateManager(); new PanelExpansionStateManager();
private SystemClock mSystemClock; private FragmentHostManager.FragmentListener mFragmentListener;
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mSystemClock = new FakeSystemClock(); SystemClock systemClock = new FakeSystemClock();
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager, mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
mInteractionJankMonitor); mInteractionJankMonitor);
mKeyguardStatusView = new KeyguardStatusView(mContext); KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
mKeyguardStatusView.setId(R.id.keyguard_status_view); keyguardStatusView.setId(R.id.keyguard_status_view);
DejankUtils.setImmediate(true); DejankUtils.setImmediate(true);
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false); when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext); when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources); when(mView.getResources()).thenReturn(mResources);
when(mView.getWidth()).thenReturn(PANEL_WIDTH);
when(mResources.getConfiguration()).thenReturn(mConfiguration); when(mResources.getConfiguration()).thenReturn(mConfiguration);
mConfiguration.orientation = ORIENTATION_PORTRAIT; mConfiguration.orientation = ORIENTATION_PORTRAIT;
when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
@@ -434,7 +342,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_status_view)) when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class)); .thenReturn(mock(KeyguardStatusView.class));
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null); mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(mKeyguardStatusView); mNotificationContainerParent.addView(keyguardStatusView);
mNotificationContainerParent.onFinishInflate(); mNotificationContainerParent.onFinishInflate();
when(mView.findViewById(R.id.notification_container_parent)) when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent); .thenReturn(mNotificationContainerParent);
@@ -450,7 +358,12 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController()) when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
.thenReturn(mKeyguardUserSwitcherController); .thenReturn(mKeyguardUserSwitcherController);
when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true); 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 -> { doAnswer((Answer<Void>) invocation -> {
mTouchHandler = invocation.getArgument(0); mTouchHandler = invocation.getArgument(0);
return null; return null;
@@ -487,7 +400,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController()) when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController); .thenReturn(mKeyguardStatusBarViewController);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean())) 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())) when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
.thenReturn(mUserSwitcherView); .thenReturn(mUserSwitcherView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean())) when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
@@ -502,13 +415,18 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
((Runnable) invocation.getArgument(0)).run(); ((Runnable) invocation.getArgument(0)).run();
return null; return null;
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any()); }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
doAnswer(invocation -> {
mLayoutChangeListener = invocation.getArgument(0);
return null;
}).when(mView).addOnLayoutChangeListener(any());
when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
when(mView.getParent()).thenReturn(mViewParent); when(mView.getParent()).thenReturn(mViewParent);
when(mQs.getHeader()).thenReturn(mQsHeader); when(mQs.getHeader()).thenReturn(mQsHeader);
mMainHandler = new Handler(Looper.getMainLooper()); mMainHandler = new Handler(Looper.getMainLooper());
mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter(); NotificationPanelViewController.PanelEventsEmitter panelEventsEmitter =
new NotificationPanelViewController.PanelEventsEmitter();
mNotificationPanelViewController = new NotificationPanelViewController( mNotificationPanelViewController = new NotificationPanelViewController(
mView, mView,
@@ -563,11 +481,11 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
() -> mKeyguardBottomAreaViewController, () -> mKeyguardBottomAreaViewController,
mKeyguardUnlockAnimationController, mKeyguardUnlockAnimationController,
mNotificationListContainer, mNotificationListContainer,
mPanelEventsEmitter, panelEventsEmitter,
mNotificationStackSizeCalculator, mNotificationStackSizeCalculator,
mUnlockedScreenOffAnimationController, mUnlockedScreenOffAnimationController,
mShadeTransitionController, mShadeTransitionController,
mSystemClock, systemClock,
mock(CameraGestureHelper.class), mock(CameraGestureHelper.class),
mKeyguardBottomAreaViewModel, mKeyguardBottomAreaViewModel,
mKeyguardBottomAreaInteractor); mKeyguardBottomAreaInteractor);
@@ -1492,6 +1410,96 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE); assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
} }
@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) { private static MotionEvent createMotionEvent(int x, int y, int action) {
return MotionEvent.obtain( return MotionEvent.obtain(
/* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0); /* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
@@ -1565,4 +1573,24 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo( assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
R.id.qs_edge_guideline); 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
);
}
} }

View File

@@ -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
}
}

View File

@@ -1,9 +1,9 @@
package com.android.systemui.statusbar package com.android.systemui.statusbar
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.ExpandHelper import com.android.systemui.ExpandHelper
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
@@ -78,6 +78,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
@Mock lateinit var qS: QS @Mock lateinit var qS: QS
@Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
@Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
@Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
@JvmField @Rule val mockito = MockitoJUnit.rule() @JvmField @Rule val mockito = MockitoJUnit.rule()
private val configurationController = FakeConfigurationController() private val configurationController = FakeConfigurationController()
@@ -120,7 +121,9 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
context, context,
configurationController, configurationController,
dumpManager) dumpManager)
}) },
qsTransitionControllerFactory = { qsTransitionController },
)
whenever(nsslController.view).thenReturn(stackscroller) whenever(nsslController.view).thenReturn(stackscroller)
whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback) whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
transitionController.notificationPanelController = notificationPanelController transitionController.notificationPanelController = notificationPanelController
@@ -249,7 +252,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat()) verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(), verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong()) anyBoolean(), anyLong())
verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) verify(qsTransitionController, never()).dragDownAmount = anyFloat()
} }
@Test @Test
@@ -260,7 +263,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat()) verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(), verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong()) anyBoolean(), anyLong())
verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) verify(qsTransitionController).dragDownAmount = 10f
verify(depthController).transitionToFullShadeProgress = anyFloat() verify(depthController).transitionToFullShadeProgress = anyFloat()
} }

View File

@@ -59,16 +59,19 @@ import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.scrim.ScrimView; 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.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.utils.os.FakeHandler; import com.android.systemui.utils.os.FakeHandler;
import com.google.common.truth.Expect;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
@@ -86,6 +89,11 @@ import java.util.Map;
@SmallTest @SmallTest
public class ScrimControllerTest extends SysuiTestCase { public class ScrimControllerTest extends SysuiTestCase {
@Rule public Expect mExpect = Expect.create();
private final FakeConfigurationController mConfigurationController =
new FakeConfigurationController();
private ScrimController mScrimController; private ScrimController mScrimController;
private ScrimView mScrimBehind; private ScrimView mScrimBehind;
private ScrimView mNotificationsScrim; private ScrimView mNotificationsScrim;
@@ -96,32 +104,19 @@ public class ScrimControllerTest extends SysuiTestCase {
private int mScrimVisibility; private int mScrimVisibility;
private boolean mAlwaysOnEnabled; private boolean mAlwaysOnEnabled;
private TestableLooper mLooper; private TestableLooper mLooper;
@Mock @Mock private AlarmManager mAlarmManager;
private AlarmManager mAlarmManager; @Mock private DozeParameters mDozeParameters;
@Mock @Mock private LightBarController mLightBarController;
private DozeParameters mDozeParameters; @Mock private DelayedWakeLock.Builder mDelayedWakeLockBuilder;
@Mock @Mock private DelayedWakeLock mWakeLock;
LightBarController mLightBarController; @Mock private KeyguardStateController mKeyguardStateController;
@Mock @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
DelayedWakeLock.Builder mDelayedWakeLockBuilder; @Mock private DockManager mDockManager;
@Mock @Mock private ScreenOffAnimationController mScreenOffAnimationController;
private DelayedWakeLock mWakeLock; @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
KeyguardStateController mKeyguardStateController;
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private DockManager mDockManager;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private ScreenOffAnimationController mScreenOffAnimationController;
@Mock
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // 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.) // event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@Mock @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private static class AnimatorListener implements Animator.AnimatorListener { private static class AnimatorListener implements Animator.AnimatorListener {
private int mNumStarts; private int mNumStarts;
@@ -1449,6 +1444,41 @@ public class ScrimControllerTest extends SysuiTestCase {
assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress); assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
} }
@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 @Test
public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() { public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() {
int overScrollAmount = 10; int overScrollAmount = 10;