Merge "[Motion] Split-shade expansion: shorten the required drag down amount to fully expand shade" into tm-qpr-dev

This commit is contained in:
Christian Göllner
2022-06-15 10:15:33 +00:00
committed by Android (Google) Code Review
11 changed files with 236 additions and 22 deletions

View File

@@ -1246,6 +1246,15 @@
<!-- Maximum overshoot for the pulse expansion -->
<dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
<!-- The drag amount required for the split shade to fully expand. -->
<dimen name="split_shade_full_transition_distance">200dp</dimen>
<!--
The drag amount required for the scrim to fully fade in when expanding the split shade.
Currently setting it a little longer than the full shade transition distance, to avoid
having a state where the screen is fully black without any content showing.
-->
<dimen name="split_shade_scrim_transition_distance">300dp</dimen>
<!-- Alpha in duration in ms for the auth ripple to become fully vislble. If set to 0,
it is immediately visible. -->
<integer name="auth_ripple_alpha_in_duration">100</integer>

View File

@@ -666,6 +666,9 @@ public class NotificationPanelViewController extends PanelViewController {
private Optional<NotificationPanelUnfoldAnimationController>
mNotificationPanelUnfoldAnimationController;
/** The drag distance required to fully expand the split shade. */
private int mSplitShadeFullTransitionDistance;
private final NotificationListContainer mNotificationListContainer;
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@@ -1165,6 +1168,9 @@ public class NotificationPanelViewController extends PanelViewController {
if (splitShadeChanged) {
onSplitShadeEnabledChanged();
}
mSplitShadeFullTransitionDistance =
mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance);
}
private void onSplitShadeEnabledChanged() {
@@ -3054,7 +3060,16 @@ public class NotificationPanelViewController extends PanelViewController {
int maxHeight;
if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted
|| mPulsing || mSplitShadeEnabled) {
maxHeight = calculatePanelHeightQsExpanded();
if (mSplitShadeEnabled && mBarState == SHADE) {
// Max panel height is used to calculate the fraction of the shade expansion.
// Traditionally the value is based on the number of notifications.
// On split-shade, we want the required distance to be a specific and constant
// value, to make sure the expansion motion has the expected speed.
// We also only want this on non-lockscreen for now.
maxHeight = mSplitShadeFullTransitionDistance;
} else {
maxHeight = calculatePanelHeightQsExpanded();
}
} else {
maxHeight = calculatePanelHeightShade();
}

View File

@@ -55,7 +55,6 @@ import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.AlarmTimeout;
@@ -265,7 +264,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
ConfigurationController configurationController, @Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
PanelExpansionStateManager panelExpansionStateManager,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mScrimStateListener = lightBarController::setScrimState;
@@ -305,10 +303,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
ScrimController.this.onThemeChanged();
}
});
panelExpansionStateManager.addExpansionListener(
event -> setRawPanelExpansionFraction(event.getFraction())
);
mColors = new GradientColors();
}
@@ -553,13 +547,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*
* The expansion fraction is tied to the scrim opacity.
*
* See {@link PanelExpansionListener#onPanelExpansionChanged}.
* See {@link ScrimShadeTransitionController#onPanelExpansionChanged}.
*
* @param rawPanelExpansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
*/
@VisibleForTesting
void setRawPanelExpansionFraction(
@FloatRange(from = 0.0, to = 1.0) float rawPanelExpansionFraction) {
public void setRawPanelExpansionFraction(
@FloatRange(from = 0.0, to = 1.0) float rawPanelExpansionFraction) {
if (isNaN(rawPanelExpansionFraction)) {
throw new IllegalArgumentException("rawPanelExpansionFraction should not be NaN");
}

View File

@@ -0,0 +1,78 @@
package com.android.systemui.statusbar.phone.shade.transition
import android.content.res.Configuration
import android.content.res.Resources
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.LargeScreenUtils
import java.io.PrintWriter
import javax.inject.Inject
/** Controls the scrim properties during the shade expansion transition on non-lockscreen. */
@SysUISingleton
class ScrimShadeTransitionController
@Inject
constructor(
configurationController: ConfigurationController,
dumpManager: DumpManager,
private val scrimController: ScrimController,
@Main private val resources: Resources
) {
private var inSplitShade = false
private var splitShadeScrimTransitionDistance = 0
private var lastExpansionFraction: Float = 0f
private var lastExpansionEvent: PanelExpansionChangeEvent? = null
init {
updateResources()
configurationController.addCallback(
object : ConfigurationController.ConfigurationListener {
override fun onConfigChanged(newConfig: Configuration?) {
updateResources()
}
})
dumpManager
.registerDumpable(ScrimShadeTransitionController::class.java.simpleName, this::dump)
}
private fun updateResources() {
inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(resources)
splitShadeScrimTransitionDistance =
resources.getDimensionPixelSize(R.dimen.split_shade_scrim_transition_distance)
}
fun onPanelExpansionChanged(panelExpansionChangeEvent: PanelExpansionChangeEvent) {
val expansionFraction = calculateScrimExpansionFraction(panelExpansionChangeEvent)
scrimController.setRawPanelExpansionFraction(expansionFraction)
lastExpansionFraction = expansionFraction
lastExpansionEvent = panelExpansionChangeEvent
}
private fun calculateScrimExpansionFraction(expansionEvent: PanelExpansionChangeEvent): Float {
return if (inSplitShade) {
expansionEvent.dragDownPxAmount / splitShadeScrimTransitionDistance
} else {
expansionEvent.fraction
}
}
private fun dump(printWriter: PrintWriter, args: Array<String>) {
printWriter.println(
"""
ScrimShadeTransitionController:
Resources:
inSplitShade: $inSplitShade
splitShadeScrimTransitionDistance: $splitShadeScrimTransitionDistance
State:
lastExpansionFraction: $lastExpansionFraction
lastExpansionEvent: $lastExpansionEvent
""".trimIndent()
)
}
}

View File

@@ -22,7 +22,8 @@ constructor(
panelExpansionStateManager: PanelExpansionStateManager,
private val context: Context,
private val splitShadeOverScrollerFactory: SplitShadeOverScroller.Factory,
private val noOpOverScroller: NoOpOverScroller
private val noOpOverScroller: NoOpOverScroller,
private val scrimShadeTransitionController: ScrimShadeTransitionController
) {
lateinit var notificationPanelViewController: NotificationPanelViewController
@@ -64,6 +65,7 @@ constructor(
private fun onPanelExpansionChanged(event: PanelExpansionChangeEvent) {
shadeOverScroller.onDragDownAmountChanged(event.dragDownPxAmount)
scrimShadeTransitionController.onPanelExpansionChanged(event)
}
private fun propertiesInitialized() =

View File

@@ -129,7 +129,8 @@ constructor(
previousOverscrollAmount: $previousOverscrollAmount
dragDownAmount: $dragDownAmount
panelState: $panelState
""".trimIndent())
""".trimIndent()
)
}
@AssistedFactory

View File

@@ -60,6 +60,7 @@ import android.view.View;
import android.view.ViewParent;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -349,6 +350,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private View mQsHeader;
@Mock
private ViewParent mViewParent;
@Mock
private ViewTreeObserver mViewTreeObserver;
private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
@@ -474,6 +477,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
return null;
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
when(mView.getParent()).thenReturn(mViewParent);
when(mQs.getHeader()).thenReturn(mQsHeader);
@@ -1296,6 +1300,43 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
false/*goingToFullShade*/, SHADE/*oldStatusBarState*/);
}
@Test
public void getMaxPanelHeight_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() {
int splitShadeFullTransitionDistance = 123456;
enableSplitShade(true);
setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
mNotificationPanelViewController.expandWithQs();
int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
assertThat(maxPanelHeight).isEqualTo(splitShadeFullTransitionDistance);
}
@Test
public void getMaxPanelHeight_expandingSplitShade_keyguard_returnsNonSplitShadeValue() {
mStatusBarStateController.setState(KEYGUARD);
int splitShadeFullTransitionDistance = 123456;
enableSplitShade(true);
setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
mNotificationPanelViewController.expandWithQs();
int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
}
@Test
public void getMaxPanelHeight_expanding_notSplitShade_returnsNonSplitShadeValue() {
int splitShadeFullTransitionDistance = 123456;
enableSplitShade(false);
setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
mNotificationPanelViewController.expandWithQs();
int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
}
private static MotionEvent createMotionEvent(int x, int y, int action) {
return MotionEvent.obtain(
/* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
@@ -1355,4 +1396,10 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private void onTouchEvent(MotionEvent ev) {
mTouchHandler.onTouch(mView, ev);
}
private void setSplitShadeFullTransitionDistance(int splitShadeFullTransitionDistance) {
when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
.thenReturn(splitShadeFullTransitionDistance);
mNotificationPanelViewController.updateResources();
}
}

View File

@@ -59,7 +59,6 @@ import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -122,8 +121,6 @@ public class ScrimControllerTest extends SysuiTestCase {
// 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 PanelExpansionStateManager mPanelExpansionStateManager;
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private static class AnimatorListener implements Animator.AnimatorListener {
@@ -237,7 +234,6 @@ public class ScrimControllerTest extends SysuiTestCase {
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mPanelExpansionStateManager,
mKeyguardUnlockAnimationController,
mStatusBarKeyguardViewManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
@@ -860,7 +856,6 @@ public class ScrimControllerTest extends SysuiTestCase {
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mPanelExpansionStateManager,
mKeyguardUnlockAnimationController,
mStatusBarKeyguardViewManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);

View File

@@ -0,0 +1,69 @@
package com.android.systemui.statusbar.phone.shade.transition
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.statusbar.phone.ScrimController
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent
import com.android.systemui.statusbar.policy.FakeConfigurationController
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class ScrimShadeTransitionControllerTest : SysuiTestCase() {
@Mock private lateinit var scrimController: ScrimController
@Mock private lateinit var dumpManager: DumpManager
private val configurationController = FakeConfigurationController()
private lateinit var controller: ScrimShadeTransitionController
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
context.ensureTestableResources()
controller =
ScrimShadeTransitionController(
configurationController, dumpManager, scrimController, context.resources
)
}
@Test
fun onPanelExpansionChanged_inSingleShade_setsFractionEqualToEventFraction() {
setSplitShadeEnabled(false)
controller.onPanelExpansionChanged(EXPANSION_EVENT)
verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
}
@Test
fun onPanelExpansionChanged_inSplitShade_setsFractionBasedOnDragDownAmount() {
val scrimShadeTransitionDistance =
context.resources.getDimensionPixelSize(R.dimen.split_shade_scrim_transition_distance)
setSplitShadeEnabled(true)
controller.onPanelExpansionChanged(EXPANSION_EVENT)
val expectedFraction = EXPANSION_EVENT.dragDownPxAmount / scrimShadeTransitionDistance
verify(scrimController).setRawPanelExpansionFraction(expectedFraction)
}
private fun setSplitShadeEnabled(enabled: Boolean) {
overrideResource(R.bool.config_use_split_notification_shade, enabled)
configurationController.notifyConfigurationChanged()
}
companion object {
val EXPANSION_EVENT =
PanelExpansionChangeEvent(
fraction = 0.5f, expanded = true, tracking = true, dragDownPxAmount = 10f
)
}
}

View File

@@ -28,6 +28,7 @@ class ShadeTransitionControllerTest : SysuiTestCase() {
@Mock private lateinit var qs: QS
@Mock private lateinit var noOpOverScroller: NoOpOverScroller
@Mock private lateinit var splitShadeOverScroller: SplitShadeOverScroller
@Mock private lateinit var scrimShadeTransitionController: ScrimShadeTransitionController
private lateinit var controller: ShadeTransitionController
@@ -44,7 +45,9 @@ class ShadeTransitionControllerTest : SysuiTestCase() {
panelExpansionStateManager,
context,
splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
noOpOverScroller)
noOpOverScroller,
scrimShadeTransitionController
)
// Resetting as they are notified upon initialization.
reset(noOpOverScroller, splitShadeOverScroller)
@@ -109,7 +112,8 @@ class ShadeTransitionControllerTest : SysuiTestCase() {
fraction = 0.5f,
expanded = true,
tracking = true,
dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT)
dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT
)
}
companion object {

View File

@@ -1,6 +1,5 @@
package com.android.systemui.statusbar.phone.shade.transition
import org.mockito.Mockito.`when` as whenever
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -21,6 +20,7 @@ import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -43,7 +43,8 @@ class SplitShadeOverScrollerTest : SysuiTestCase() {
whenever(nsslController.height).thenReturn(1000)
overScroller =
SplitShadeOverScroller(
configurationController, dumpManager, context, scrimController, qs, nsslController)
configurationController, dumpManager, context, scrimController, qs, nsslController
)
}
@Test