Loading packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt +40 −18 Original line number Diff line number Diff line Loading @@ -144,7 +144,7 @@ class QSLongPressEffectTest : SysuiTestCase() { longPressEffect.handleActionUp() // THEN the effect reverses assertEffectReverses() assertEffectReverses(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) } @Test Loading @@ -171,18 +171,17 @@ class QSLongPressEffectTest : SysuiTestCase() { longPressEffect.handleActionCancel() // THEN the effect gets reversed assertEffectReverses() assertEffectReverses(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) } @Test fun onAnimationComplete_keyguardDismissible_effectEndsWithPrepare() = fun onAnimationComplete_keyguardDismissible_effectCompletes() = testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() // THEN the long-press effect completes and the view is called to prepare // THEN the long-press effect completes assertEffectCompleted() verify(callback, times(1)).onPrepareForLaunch() } @Test Loading @@ -199,6 +198,26 @@ class QSLongPressEffectTest : SysuiTestCase() { verify(callback, times(1)).onResetProperties() } @Test fun onAnimationComplete_whenRunningBackwardsFromUp_endsWithFinishedReversing() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() // THEN the callback for finished reversing is used. verify(callback, times(1)).onEffectFinishedReversing() } @Test fun onAnimationComplete_whenRunningBackwardsFromCancel_endsInIdle() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() // THEN the effect ends in the idle state. assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE) } @Test fun onActionDown_whileRunningBackwards_cancels() = testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) { Loading @@ -223,11 +242,8 @@ class QSLongPressEffectTest : SysuiTestCase() { } @Test fun onAnimationComplete_whileRunningBackwards_goesToIdle() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS) { // GIVEN an action cancel occurs and the effect gets reversed longPressEffect.handleActionCancel() fun onAnimationComplete_whileRunningBackwardsFromCancel_goesToIdle() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() Loading Loading @@ -307,12 +323,16 @@ class QSLongPressEffectTest : SysuiTestCase() { /** * Asserts that the effect did not start by checking that: * 1. No haptics are played * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS] or * [QSLongPressEffect.State.RUNNING_FORWARD] * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP] or * [QSLongPressEffect.State.RUNNING_FORWARD] or * [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL] */ private fun assertEffectDidNotStart() { assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD) assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS) assertThat(longPressEffect.state) .isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) assertThat(longPressEffect.state) .isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) assertThat(vibratorHelper.totalVibrations).isEqualTo(0) } Loading @@ -330,12 +350,14 @@ class QSLongPressEffectTest : SysuiTestCase() { } /** * Assert that the effect gets reverted by checking that: * 1. The internal state is [QSLongPressEffect.State.RUNNING_BACKWARDS] * 2. An action to reverse the animator is emitted * Assert that the effect gets reverted by checking that the callback to reverse the animator is * used, and that the state is given reversing state. * * @param[reversingState] Either [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL] or * [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP] */ private fun assertEffectReverses() { assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS) private fun assertEffectReverses(reversingState: QSLongPressEffect.State) { assertThat(longPressEffect.state).isEqualTo(reversingState) verify(callback, times(1)).onReverseAnimator() } } packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt +29 −21 Original line number Diff line number Diff line Loading @@ -97,14 +97,15 @@ constructor( State.IDLE -> { setState(State.TIMEOUT_WAIT) } State.RUNNING_BACKWARDS -> callback?.onCancelAnimator() State.RUNNING_BACKWARDS_FROM_UP, State.RUNNING_BACKWARDS_FROM_CANCEL -> callback?.onCancelAnimator() else -> {} } } fun handleActionUp() { if (state == State.RUNNING_FORWARD) { setState(State.RUNNING_BACKWARDS) setState(State.RUNNING_BACKWARDS_FROM_UP) callback?.onReverseAnimator() } } Loading @@ -113,7 +114,7 @@ constructor( when (state) { State.TIMEOUT_WAIT -> setState(State.IDLE) State.RUNNING_FORWARD -> { setState(State.RUNNING_BACKWARDS) setState(State.RUNNING_BACKWARDS_FROM_CANCEL) callback?.onReverseAnimator() } else -> {} Loading @@ -127,20 +128,24 @@ constructor( /** This function is called both when an animator completes or gets cancelled */ fun handleAnimationComplete() { if (state == State.RUNNING_FORWARD) { when (state) { State.RUNNING_FORWARD -> { setState(State.IDLE) vibrate(snapEffect) if (keyguardStateController.isUnlocked) { callback?.onPrepareForLaunch() qsTile?.longClick(expandable) } else { callback?.onResetProperties() qsTile?.longClick(expandable) } } if (state != State.TIMEOUT_WAIT) { // This will happen if the animator did not finish by being cancelled State.RUNNING_BACKWARDS_FROM_UP -> { setState(State.IDLE) callback?.onEffectFinishedReversing() qsTile?.click(expandable) } State.RUNNING_BACKWARDS_FROM_CANCEL -> setState(State.IDLE) else -> {} } } Loading Loading @@ -191,20 +196,23 @@ constructor( enum class State { IDLE, /* The effect is idle waiting for touch input */ TIMEOUT_WAIT, /* The effect is waiting for a [PRESSED_TIMEOUT] period */ TIMEOUT_WAIT, /* The effect is waiting for a tap timeout period */ RUNNING_FORWARD, /* The effect is running normally */ RUNNING_BACKWARDS, /* The effect was interrupted and is now running backwards */ /* The effect was interrupted by an ACTION_UP and is now running backwards */ RUNNING_BACKWARDS_FROM_UP, /* The effect was interrupted by an ACTION_CANCEL and is now running backwards */ RUNNING_BACKWARDS_FROM_CANCEL, } /** Callbacks to notify view and animator actions */ interface Callback { /** Prepare for an activity launch */ fun onPrepareForLaunch() /** Reset the tile visual properties */ fun onResetProperties() /** Event where the effect completed by being reversed */ fun onEffectFinishedReversing() /** Start the effect animator */ fun onStartAnimator() Loading packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +15 −4 Original line number Diff line number Diff line Loading @@ -350,6 +350,10 @@ constructor( initialLongPressProperties?.width = width finalLongPressProperties?.width = LONG_PRESS_EFFECT_WIDTH_SCALE * width val deltaW = (LONG_PRESS_EFFECT_WIDTH_SCALE - 1f) * width paddingForLaunch.left = -deltaW.toInt() / 2 paddingForLaunch.right = deltaW.toInt() / 2 } private fun maybeUpdateLongPressEffectHeight(height: Float) { Loading @@ -357,6 +361,10 @@ constructor( initialLongPressProperties?.height = height finalLongPressProperties?.height = LONG_PRESS_EFFECT_HEIGHT_SCALE * height val deltaH = (LONG_PRESS_EFFECT_HEIGHT_SCALE - 1f) * height paddingForLaunch.top = -deltaH.toInt() / 2 paddingForLaunch.bottom = deltaH.toInt() / 2 } override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) { Loading Loading @@ -432,14 +440,16 @@ constructor( longPressEffect?.callback = object : QSLongPressEffect.Callback { override fun onPrepareForLaunch() { prepareForLaunch() } override fun onResetProperties() { resetLongPressEffectProperties() } override fun onEffectFinishedReversing() { // The long-press effect properties finished at the same starting point. // This is the same as if the properties were reset haveLongPressPropertiesBeenReset = true } override fun onStartAnimator() { if (longPressEffectAnimator?.isRunning != true) { longPressEffectAnimator = Loading Loading @@ -1043,6 +1053,7 @@ constructor( getOverlayColorForState(Tile.STATE_ACTIVE), Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive), ) prepareForLaunch() } private fun changeCornerRadius(radius: Float) { Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt +40 −18 Original line number Diff line number Diff line Loading @@ -144,7 +144,7 @@ class QSLongPressEffectTest : SysuiTestCase() { longPressEffect.handleActionUp() // THEN the effect reverses assertEffectReverses() assertEffectReverses(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) } @Test Loading @@ -171,18 +171,17 @@ class QSLongPressEffectTest : SysuiTestCase() { longPressEffect.handleActionCancel() // THEN the effect gets reversed assertEffectReverses() assertEffectReverses(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) } @Test fun onAnimationComplete_keyguardDismissible_effectEndsWithPrepare() = fun onAnimationComplete_keyguardDismissible_effectCompletes() = testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() // THEN the long-press effect completes and the view is called to prepare // THEN the long-press effect completes assertEffectCompleted() verify(callback, times(1)).onPrepareForLaunch() } @Test Loading @@ -199,6 +198,26 @@ class QSLongPressEffectTest : SysuiTestCase() { verify(callback, times(1)).onResetProperties() } @Test fun onAnimationComplete_whenRunningBackwardsFromUp_endsWithFinishedReversing() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() // THEN the callback for finished reversing is used. verify(callback, times(1)).onEffectFinishedReversing() } @Test fun onAnimationComplete_whenRunningBackwardsFromCancel_endsInIdle() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() // THEN the effect ends in the idle state. assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE) } @Test fun onActionDown_whileRunningBackwards_cancels() = testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) { Loading @@ -223,11 +242,8 @@ class QSLongPressEffectTest : SysuiTestCase() { } @Test fun onAnimationComplete_whileRunningBackwards_goesToIdle() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS) { // GIVEN an action cancel occurs and the effect gets reversed longPressEffect.handleActionCancel() fun onAnimationComplete_whileRunningBackwardsFromCancel_goesToIdle() = testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) { // GIVEN that the animation completes longPressEffect.handleAnimationComplete() Loading Loading @@ -307,12 +323,16 @@ class QSLongPressEffectTest : SysuiTestCase() { /** * Asserts that the effect did not start by checking that: * 1. No haptics are played * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS] or * [QSLongPressEffect.State.RUNNING_FORWARD] * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP] or * [QSLongPressEffect.State.RUNNING_FORWARD] or * [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL] */ private fun assertEffectDidNotStart() { assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD) assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS) assertThat(longPressEffect.state) .isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) assertThat(longPressEffect.state) .isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL) assertThat(vibratorHelper.totalVibrations).isEqualTo(0) } Loading @@ -330,12 +350,14 @@ class QSLongPressEffectTest : SysuiTestCase() { } /** * Assert that the effect gets reverted by checking that: * 1. The internal state is [QSLongPressEffect.State.RUNNING_BACKWARDS] * 2. An action to reverse the animator is emitted * Assert that the effect gets reverted by checking that the callback to reverse the animator is * used, and that the state is given reversing state. * * @param[reversingState] Either [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_CANCEL] or * [QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP] */ private fun assertEffectReverses() { assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS) private fun assertEffectReverses(reversingState: QSLongPressEffect.State) { assertThat(longPressEffect.state).isEqualTo(reversingState) verify(callback, times(1)).onReverseAnimator() } }
packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt +29 −21 Original line number Diff line number Diff line Loading @@ -97,14 +97,15 @@ constructor( State.IDLE -> { setState(State.TIMEOUT_WAIT) } State.RUNNING_BACKWARDS -> callback?.onCancelAnimator() State.RUNNING_BACKWARDS_FROM_UP, State.RUNNING_BACKWARDS_FROM_CANCEL -> callback?.onCancelAnimator() else -> {} } } fun handleActionUp() { if (state == State.RUNNING_FORWARD) { setState(State.RUNNING_BACKWARDS) setState(State.RUNNING_BACKWARDS_FROM_UP) callback?.onReverseAnimator() } } Loading @@ -113,7 +114,7 @@ constructor( when (state) { State.TIMEOUT_WAIT -> setState(State.IDLE) State.RUNNING_FORWARD -> { setState(State.RUNNING_BACKWARDS) setState(State.RUNNING_BACKWARDS_FROM_CANCEL) callback?.onReverseAnimator() } else -> {} Loading @@ -127,20 +128,24 @@ constructor( /** This function is called both when an animator completes or gets cancelled */ fun handleAnimationComplete() { if (state == State.RUNNING_FORWARD) { when (state) { State.RUNNING_FORWARD -> { setState(State.IDLE) vibrate(snapEffect) if (keyguardStateController.isUnlocked) { callback?.onPrepareForLaunch() qsTile?.longClick(expandable) } else { callback?.onResetProperties() qsTile?.longClick(expandable) } } if (state != State.TIMEOUT_WAIT) { // This will happen if the animator did not finish by being cancelled State.RUNNING_BACKWARDS_FROM_UP -> { setState(State.IDLE) callback?.onEffectFinishedReversing() qsTile?.click(expandable) } State.RUNNING_BACKWARDS_FROM_CANCEL -> setState(State.IDLE) else -> {} } } Loading Loading @@ -191,20 +196,23 @@ constructor( enum class State { IDLE, /* The effect is idle waiting for touch input */ TIMEOUT_WAIT, /* The effect is waiting for a [PRESSED_TIMEOUT] period */ TIMEOUT_WAIT, /* The effect is waiting for a tap timeout period */ RUNNING_FORWARD, /* The effect is running normally */ RUNNING_BACKWARDS, /* The effect was interrupted and is now running backwards */ /* The effect was interrupted by an ACTION_UP and is now running backwards */ RUNNING_BACKWARDS_FROM_UP, /* The effect was interrupted by an ACTION_CANCEL and is now running backwards */ RUNNING_BACKWARDS_FROM_CANCEL, } /** Callbacks to notify view and animator actions */ interface Callback { /** Prepare for an activity launch */ fun onPrepareForLaunch() /** Reset the tile visual properties */ fun onResetProperties() /** Event where the effect completed by being reversed */ fun onEffectFinishedReversing() /** Start the effect animator */ fun onStartAnimator() Loading
packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +15 −4 Original line number Diff line number Diff line Loading @@ -350,6 +350,10 @@ constructor( initialLongPressProperties?.width = width finalLongPressProperties?.width = LONG_PRESS_EFFECT_WIDTH_SCALE * width val deltaW = (LONG_PRESS_EFFECT_WIDTH_SCALE - 1f) * width paddingForLaunch.left = -deltaW.toInt() / 2 paddingForLaunch.right = deltaW.toInt() / 2 } private fun maybeUpdateLongPressEffectHeight(height: Float) { Loading @@ -357,6 +361,10 @@ constructor( initialLongPressProperties?.height = height finalLongPressProperties?.height = LONG_PRESS_EFFECT_HEIGHT_SCALE * height val deltaH = (LONG_PRESS_EFFECT_HEIGHT_SCALE - 1f) * height paddingForLaunch.top = -deltaH.toInt() / 2 paddingForLaunch.bottom = deltaH.toInt() / 2 } override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) { Loading Loading @@ -432,14 +440,16 @@ constructor( longPressEffect?.callback = object : QSLongPressEffect.Callback { override fun onPrepareForLaunch() { prepareForLaunch() } override fun onResetProperties() { resetLongPressEffectProperties() } override fun onEffectFinishedReversing() { // The long-press effect properties finished at the same starting point. // This is the same as if the properties were reset haveLongPressPropertiesBeenReset = true } override fun onStartAnimator() { if (longPressEffectAnimator?.isRunning != true) { longPressEffectAnimator = Loading Loading @@ -1043,6 +1053,7 @@ constructor( getOverlayColorForState(Tile.STATE_ACTIVE), Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive), ) prepareForLaunch() } private fun changeCornerRadius(radius: Float) { Loading