Delay the dozeAmount change animation.
This change builds on the previous refactor to introduce an animated delay. This delay animation is carefully crafted to avoid accidentally affecting doze amount state in any situation other than while the animation is running, without ever having to cancel the animation. Bug: 269085199 Test: atest NotificationWakeUpCoordinatorTest NotificationWakeUpCoordinatorLoggerTest Change-Id: I5946c59159f04b07c4a56e862e4b0ecc575849ce
This commit is contained in:
@@ -16,15 +16,17 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.util.FloatProperty
|
||||
import android.view.animation.Interpolator
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.animation.ObjectAnimator
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.animation.InterpolatorsAndroidX
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.NotificationPanelViewController.WAKEUP_ANIMATION_DELAY_MS
|
||||
import com.android.systemui.shade.ShadeExpansionChangeEvent
|
||||
import com.android.systemui.shade.ShadeExpansionListener
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
@@ -37,8 +39,11 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController.OnBypassSta
|
||||
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager
|
||||
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
|
||||
import com.android.systemui.util.doOnCancel
|
||||
import com.android.systemui.util.doOnEnd
|
||||
import java.io.PrintWriter
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@SysUISingleton
|
||||
@@ -57,23 +62,13 @@ constructor(
|
||||
StatusBarStateController.StateListener,
|
||||
ShadeExpansionListener,
|
||||
Dumpable {
|
||||
|
||||
private val mNotificationVisibility =
|
||||
object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
|
||||
|
||||
override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
|
||||
coordinator.setVisibilityAmount(value)
|
||||
}
|
||||
|
||||
override fun get(coordinator: NotificationWakeUpCoordinator): Float? {
|
||||
return coordinator.mLinearVisibilityAmount
|
||||
}
|
||||
}
|
||||
private lateinit var mStackScrollerController: NotificationStackScrollLayoutController
|
||||
private var mVisibilityInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE
|
||||
|
||||
private var inputLinearDozeAmount: Float = 0.0f
|
||||
private var inputEasedDozeAmount: Float = 0.0f
|
||||
private var delayedDozeAmountOverride: Float = 0.0f
|
||||
private var delayedDozeAmountAnimator: ObjectAnimator? = null
|
||||
/** Valid values: {1f, 0f, null} null => use input */
|
||||
private var hardDozeAmountOverride: Float? = null
|
||||
private var hardDozeAmountOverrideSource: String = "n/a"
|
||||
@@ -319,7 +314,8 @@ constructor(
|
||||
|
||||
private fun updateDozeAmount() {
|
||||
// Calculate new doze amount (linear)
|
||||
val newOutputLinearDozeAmount = hardDozeAmountOverride ?: inputLinearDozeAmount
|
||||
val newOutputLinearDozeAmount =
|
||||
hardDozeAmountOverride ?: max(inputLinearDozeAmount, delayedDozeAmountOverride)
|
||||
val changed = outputLinearDozeAmount != newOutputLinearDozeAmount
|
||||
|
||||
// notify when the animation is starting
|
||||
@@ -337,6 +333,7 @@ constructor(
|
||||
outputEasedDozeAmount = dozeAmountInterpolator.getInterpolation(outputLinearDozeAmount)
|
||||
logger.logUpdateDozeAmount(
|
||||
inputLinear = inputLinearDozeAmount,
|
||||
delayLinear = delayedDozeAmountOverride,
|
||||
hardOverride = hardDozeAmountOverride,
|
||||
outputLinear = outputLinearDozeAmount,
|
||||
state = statusBarStateController.state,
|
||||
@@ -365,8 +362,27 @@ constructor(
|
||||
wakingUp: Boolean,
|
||||
requestDelayedAnimation: Boolean,
|
||||
) {
|
||||
logger.logSetWakingUp(wakingUp, requestDelayedAnimation)
|
||||
this.wakingUp = wakingUp
|
||||
// TODO(jeffdq): Delay the wakeup animation if we're pressing to unlock.
|
||||
if (wakingUp && requestDelayedAnimation) {
|
||||
scheduleDelayedDozeAmountAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleDelayedDozeAmountAnimation() {
|
||||
val alreadyRunning = delayedDozeAmountAnimator != null
|
||||
logger.logStartDelayedDozeAmountAnimation(alreadyRunning)
|
||||
if (alreadyRunning) return
|
||||
delayedDozeAmount.setValue(this, 1.0f)
|
||||
delayedDozeAmountAnimator =
|
||||
ObjectAnimator.ofFloat(this, delayedDozeAmount, 0.0f).apply {
|
||||
interpolator = InterpolatorsAndroidX.LINEAR
|
||||
duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
|
||||
startDelay = WAKEUP_ANIMATION_DELAY_MS.toLong()
|
||||
doOnEnd { delayedDozeAmountAnimator = null }
|
||||
doOnCancel { delayedDozeAmountAnimator = null }
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStateChanged(newState: Int) {
|
||||
@@ -489,8 +505,8 @@ constructor(
|
||||
else Interpolators.FAST_OUT_SLOW_IN_REVERSE
|
||||
}
|
||||
val target = if (mNotificationsVisible) 1.0f else 0.0f
|
||||
val visibilityAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target)
|
||||
visibilityAnimator.interpolator = Interpolators.LINEAR
|
||||
val visibilityAnimator = ObjectAnimator.ofFloat(this, notificationVisibility, target)
|
||||
visibilityAnimator.interpolator = InterpolatorsAndroidX.LINEAR
|
||||
var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
|
||||
if (increaseSpeed) {
|
||||
duration = (duration.toFloat() / 1.5F).toLong()
|
||||
@@ -501,6 +517,7 @@ constructor(
|
||||
}
|
||||
|
||||
private fun setVisibilityAmount(visibilityAmount: Float) {
|
||||
logger.logSetVisibilityAmount(visibilityAmount)
|
||||
mLinearVisibilityAmount = visibilityAmount
|
||||
mVisibilityAmount = mVisibilityInterpolator.getInterpolation(visibilityAmount)
|
||||
handleAnimationFinished()
|
||||
@@ -517,6 +534,7 @@ constructor(
|
||||
private fun updateHideAmount() {
|
||||
val linearAmount = min(1.0f - mLinearVisibilityAmount, outputLinearDozeAmount)
|
||||
val amount = min(1.0f - mVisibilityAmount, outputEasedDozeAmount)
|
||||
logger.logSetHideAmount(linearAmount)
|
||||
mStackScrollerController.setHideAmount(linearAmount, amount)
|
||||
notificationsFullyHidden = linearAmount == 1.0f
|
||||
}
|
||||
@@ -558,6 +576,7 @@ constructor(
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println("inputLinearDozeAmount: $inputLinearDozeAmount")
|
||||
pw.println("inputEasedDozeAmount: $inputEasedDozeAmount")
|
||||
pw.println("delayedDozeAmountOverride: $delayedDozeAmountOverride")
|
||||
pw.println("hardDozeAmountOverride: $hardDozeAmountOverride")
|
||||
pw.println("hardDozeAmountOverrideSource: $hardDozeAmountOverrideSource")
|
||||
pw.println("outputLinearDozeAmount: $outputLinearDozeAmount")
|
||||
@@ -593,4 +612,32 @@ constructor(
|
||||
*/
|
||||
@JvmDefault fun onPulseExpansionChanged(expandingChanged: Boolean) {}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val notificationVisibility =
|
||||
object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
|
||||
|
||||
override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
|
||||
coordinator.setVisibilityAmount(value)
|
||||
}
|
||||
|
||||
override fun get(coordinator: NotificationWakeUpCoordinator): Float {
|
||||
return coordinator.mLinearVisibilityAmount
|
||||
}
|
||||
}
|
||||
|
||||
private val delayedDozeAmount =
|
||||
object : FloatProperty<NotificationWakeUpCoordinator>("delayedDozeAmount") {
|
||||
|
||||
override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
|
||||
coordinator.delayedDozeAmountOverride = value
|
||||
coordinator.logger.logSetDelayDozeAmountOverride(value)
|
||||
coordinator.updateDozeAmount()
|
||||
}
|
||||
|
||||
override fun get(coordinator: NotificationWakeUpCoordinator): Float {
|
||||
return coordinator.delayedDozeAmountOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,29 +22,40 @@ import javax.inject.Inject
|
||||
class NotificationWakeUpCoordinatorLogger
|
||||
@Inject
|
||||
constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
|
||||
private var lastSetDozeAmountLogWasFractional = false
|
||||
private var allowThrottle = true
|
||||
private var lastSetDozeAmountLogInputWasFractional = false
|
||||
private var lastSetDozeAmountLogDelayWasFractional = false
|
||||
private var lastSetDozeAmountLogState = -1
|
||||
private var lastSetHardOverride: Float? = null
|
||||
private var lastOnDozeAmountChangedLogWasFractional = false
|
||||
private var lastSetDelayDozeAmountOverrideLogWasFractional = false
|
||||
private var lastSetVisibilityAmountLogWasFractional = false
|
||||
private var lastSetHideAmountLogWasFractional = false
|
||||
private var lastSetHideAmount = -1f
|
||||
|
||||
fun logUpdateDozeAmount(
|
||||
inputLinear: Float,
|
||||
delayLinear: Float,
|
||||
hardOverride: Float?,
|
||||
outputLinear: Float,
|
||||
state: Int,
|
||||
changed: Boolean,
|
||||
) {
|
||||
// Avoid logging on every frame of the animation if important values are not changing
|
||||
val isFractional = inputLinear != 1f && inputLinear != 0f
|
||||
val isInputFractional = inputLinear != 1f && inputLinear != 0f
|
||||
val isDelayFractional = delayLinear != 1f && delayLinear != 0f
|
||||
if (
|
||||
lastSetDozeAmountLogWasFractional &&
|
||||
isFractional &&
|
||||
(isInputFractional || isDelayFractional) &&
|
||||
lastSetDozeAmountLogInputWasFractional == isInputFractional &&
|
||||
lastSetDozeAmountLogDelayWasFractional == isDelayFractional &&
|
||||
lastSetDozeAmountLogState == state &&
|
||||
lastSetHardOverride == hardOverride
|
||||
lastSetHardOverride == hardOverride &&
|
||||
allowThrottle
|
||||
) {
|
||||
return
|
||||
}
|
||||
lastSetDozeAmountLogWasFractional = isFractional
|
||||
lastSetDozeAmountLogInputWasFractional = isInputFractional
|
||||
lastSetDozeAmountLogDelayWasFractional = isDelayFractional
|
||||
lastSetDozeAmountLogState = state
|
||||
lastSetHardOverride = hardOverride
|
||||
|
||||
@@ -55,11 +66,13 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
|
||||
double1 = inputLinear.toDouble()
|
||||
str1 = hardOverride.toString()
|
||||
str2 = outputLinear.toString()
|
||||
str3 = delayLinear.toString()
|
||||
int1 = state
|
||||
bool1 = changed
|
||||
},
|
||||
{
|
||||
"updateDozeAmount() inputLinear=$double1 hardOverride=$str1 outputLinear=$str2" +
|
||||
"updateDozeAmount() inputLinear=$double1 delayLinear=$str3" +
|
||||
" hardOverride=$str1 outputLinear=$str2" +
|
||||
" state=${StatusBarState.toString(int1)} changed=$bool1"
|
||||
}
|
||||
)
|
||||
@@ -99,7 +112,7 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
|
||||
fun logOnDozeAmountChanged(linear: Float, eased: Float) {
|
||||
// Avoid logging on every frame of the animation when values are fractional
|
||||
val isFractional = linear != 1f && linear != 0f
|
||||
if (lastOnDozeAmountChangedLogWasFractional && isFractional) return
|
||||
if (lastOnDozeAmountChangedLogWasFractional && isFractional && allowThrottle) return
|
||||
lastOnDozeAmountChangedLogWasFractional = isFractional
|
||||
buffer.log(
|
||||
TAG,
|
||||
@@ -112,6 +125,47 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
|
||||
)
|
||||
}
|
||||
|
||||
fun logSetDelayDozeAmountOverride(linear: Float) {
|
||||
// Avoid logging on every frame of the animation when values are fractional
|
||||
val isFractional = linear != 1f && linear != 0f
|
||||
if (lastSetDelayDozeAmountOverrideLogWasFractional && isFractional && allowThrottle) return
|
||||
lastSetDelayDozeAmountOverrideLogWasFractional = isFractional
|
||||
buffer.log(
|
||||
TAG,
|
||||
DEBUG,
|
||||
{ double1 = linear.toDouble() },
|
||||
{ "setDelayDozeAmountOverride($double1)" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logSetVisibilityAmount(linear: Float) {
|
||||
// Avoid logging on every frame of the animation when values are fractional
|
||||
val isFractional = linear != 1f && linear != 0f
|
||||
if (lastSetVisibilityAmountLogWasFractional && isFractional && allowThrottle) return
|
||||
lastSetVisibilityAmountLogWasFractional = isFractional
|
||||
buffer.log(TAG, DEBUG, { double1 = linear.toDouble() }, { "setVisibilityAmount($double1)" })
|
||||
}
|
||||
|
||||
fun logSetHideAmount(linear: Float) {
|
||||
// Avoid logging the same value repeatedly
|
||||
if (lastSetHideAmount == linear && allowThrottle) return
|
||||
lastSetHideAmount = linear
|
||||
// Avoid logging on every frame of the animation when values are fractional
|
||||
val isFractional = linear != 1f && linear != 0f
|
||||
if (lastSetHideAmountLogWasFractional && isFractional && allowThrottle) return
|
||||
lastSetHideAmountLogWasFractional = isFractional
|
||||
buffer.log(TAG, DEBUG, { double1 = linear.toDouble() }, { "setHideAmount($double1)" })
|
||||
}
|
||||
|
||||
fun logStartDelayedDozeAmountAnimation(alreadyRunning: Boolean) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
DEBUG,
|
||||
{ bool1 = alreadyRunning },
|
||||
{ "startDelayedDozeAmountAnimation() alreadyRunning=$bool1" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnStateChanged(newState: Int, storedState: Int) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
@@ -127,6 +181,18 @@ constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
|
||||
)
|
||||
}
|
||||
|
||||
fun logSetWakingUp(wakingUp: Boolean, requestDelayedAnimation: Boolean) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
DEBUG,
|
||||
{
|
||||
bool1 = wakingUp
|
||||
bool2 = requestDelayedAnimation
|
||||
},
|
||||
{ "setWakingUp(wakingUp=$bool1, requestDelayedAnimation=$bool2)" }
|
||||
)
|
||||
}
|
||||
|
||||
fun logClockTransitionAnimationStarting(delayWakeUpAnimation: Boolean) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
|
||||
@@ -5565,6 +5565,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
public void setDozeAmount(float dozeAmount) {
|
||||
mAmbientState.setDozeAmount(dozeAmount);
|
||||
updateContinuousBackgroundDrawing();
|
||||
updateStackPosition();
|
||||
requestChildrenUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,51 +45,130 @@ class NotificationWakeUpCoordinatorLoggerTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDozeAmountWillThrottleFractionalInputUpdates() {
|
||||
logger.logUpdateDozeAmount(0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
fun updateVisibilityThrottleFractionalUpdates() {
|
||||
logger.logSetVisibilityAmount(0f)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.1f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
logger.logSetVisibilityAmount(0.1f)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.2f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.3f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.4f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
logger.logSetVisibilityAmount(0.2f)
|
||||
logger.logSetVisibilityAmount(0.3f)
|
||||
logger.logSetVisibilityAmount(0.4f)
|
||||
logger.logSetVisibilityAmount(0.5f)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(1f, null, 1f, StatusBarState.SHADE, changed = true)
|
||||
logger.logSetVisibilityAmount(1f)
|
||||
verifyDidLog(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateHideAmountThrottleFractionalOrRepeatedUpdates() {
|
||||
logger.logSetHideAmount(0f)
|
||||
verifyDidLog(1)
|
||||
logger.logSetHideAmount(0f)
|
||||
logger.logSetHideAmount(0f)
|
||||
verifyDidLog(0)
|
||||
logger.logSetHideAmount(0.1f)
|
||||
verifyDidLog(1)
|
||||
logger.logSetHideAmount(0.2f)
|
||||
logger.logSetHideAmount(0.3f)
|
||||
logger.logSetHideAmount(0.4f)
|
||||
logger.logSetHideAmount(0.5f)
|
||||
logger.logSetHideAmount(0.5f)
|
||||
logger.logSetHideAmount(0.5f)
|
||||
verifyDidLog(0)
|
||||
logger.logSetHideAmount(1f)
|
||||
verifyDidLog(1)
|
||||
logger.logSetHideAmount(1f)
|
||||
logger.logSetHideAmount(1f)
|
||||
verifyDidLog(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDozeAmountWillThrottleFractionalInputUpdates() {
|
||||
logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.1f, 0f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.2f, 0f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.3f, 0f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.4f, 0f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(1f, 0f, null, 1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDozeAmountWillThrottleFractionalDelayUpdates() {
|
||||
logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0f, 0.1f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0f, 0.2f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0f, 0.3f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0f, 0.4f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0f, 0.5f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(0f, 1f, null, 1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDozeAmountWillIncludeFractionalUpdatesWhenOtherInputChangesFractionality() {
|
||||
logger.logUpdateDozeAmount(0.0f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.1f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.2f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(0.3f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(0.4f, 1.0f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(0.5f, 0.9f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.6f, 0.8f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(0.8f, 0.6f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(0.9f, 0.5f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(1.0f, 0.4f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(1.0f, 0.3f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(1.0f, 0.2f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(1.0f, 0.1f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(1.0f, 0.0f, 1f, 1f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDozeAmountWillIncludeFractionalUpdatesWhenStateChanges() {
|
||||
logger.logUpdateDozeAmount(0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.1f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.1f, 0f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.2f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.3f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.4f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.2f, 0f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.3f, 0f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.4f, 0f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(0.5f, null, 0.5f, StatusBarState.KEYGUARD, changed = false)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.KEYGUARD, changed = false)
|
||||
verifyDidLog(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDozeAmountWillIncludeFractionalUpdatesWhenHardOverrideChanges() {
|
||||
logger.logUpdateDozeAmount(0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
logger.logUpdateDozeAmount(0f, 0f, null, 0f, StatusBarState.SHADE, changed = false)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.1f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.1f, 0f, null, 0.1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.2f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.3f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.4f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.2f, 0f, null, 0.2f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.3f, 0f, null, 0.3f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.4f, 0f, null, 0.4f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(0)
|
||||
logger.logUpdateDozeAmount(0.5f, 1f, 1f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, 1f, 1f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, 0f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, 0f, 0f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
logger.logUpdateDozeAmount(0.5f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
logger.logUpdateDozeAmount(0.5f, 0f, null, 0.5f, StatusBarState.SHADE, changed = true)
|
||||
verifyDidLog(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,16 @@
|
||||
package com.android.systemui.statusbar.notification
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.NotificationPanelViewController.WAKEUP_ANIMATION_DELAY_MS
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
|
||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_WAKEUP
|
||||
import com.android.systemui.statusbar.phone.DozeParameters
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
|
||||
@@ -32,16 +36,21 @@ import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.mockito.withArgCaptor
|
||||
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.Mockito.anyFloat
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
|
||||
|
||||
@get:Rule val animatorTestRule = AnimatorTestRule()
|
||||
|
||||
private val dumpManager: DumpManager = mock()
|
||||
private val headsUpManager: HeadsUpManager = mock()
|
||||
private val statusBarStateController: StatusBarStateController = mock()
|
||||
@@ -57,9 +66,8 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
|
||||
|
||||
private var bypassEnabled: Boolean = false
|
||||
private var statusBarState: Int = StatusBarState.KEYGUARD
|
||||
private var dozeAmount: Float = 0f
|
||||
private val easedDozeAmount: Float
|
||||
get() = notificationWakeUpCoordinator.dozeAmountInterpolator.getInterpolation(dozeAmount)
|
||||
private fun eased(dozeAmount: Float) =
|
||||
notificationWakeUpCoordinator.dozeAmountInterpolator.getInterpolation(dozeAmount)
|
||||
|
||||
private fun setBypassEnabled(enabled: Boolean) {
|
||||
bypassEnabled = enabled
|
||||
@@ -72,7 +80,6 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
private fun setDozeAmount(dozeAmount: Float) {
|
||||
this.dozeAmount = dozeAmount
|
||||
statusBarStateCallback.onDozeAmountChanged(dozeAmount, dozeAmount)
|
||||
}
|
||||
|
||||
@@ -123,11 +130,7 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun setDozeToHalfWillHalfShowNotifications() {
|
||||
setDozeAmount(0.5f)
|
||||
verifyStackScrollerDozeAndHideAmount(
|
||||
dozeAmount = easedDozeAmount,
|
||||
hideAmount = 0.5f,
|
||||
hideAmountEased = easedDozeAmount,
|
||||
)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
|
||||
}
|
||||
|
||||
@@ -135,7 +138,7 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
|
||||
fun setDozeToZeroWithBypassWillFullyHideNotifications() {
|
||||
bypassEnabled = true
|
||||
setDozeAmount(0f)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 01f, hideAmount = 1f)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
}
|
||||
|
||||
@@ -158,16 +161,91 @@ class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
|
||||
assertThat(notificationWakeUpCoordinator.statusBarState).isEqualTo(StatusBarState.SHADE)
|
||||
}
|
||||
|
||||
private fun verifyStackScrollerDozeAndHideAmount(
|
||||
dozeAmount: Float,
|
||||
hideAmount: Float,
|
||||
hideAmountEased: Float? = null,
|
||||
) {
|
||||
private val delayedDozeDelay = WAKEUP_ANIMATION_DELAY_MS.toLong()
|
||||
private val delayedDozeDuration = ANIMATION_DURATION_WAKEUP.toLong()
|
||||
|
||||
@Test
|
||||
fun dozeAmountOutputClampsTo1WhenDelayStarts() {
|
||||
notificationWakeUpCoordinator.setWakingUp(true, requestDelayedAnimation = true)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
|
||||
// verify further doze amount changes have no effect on output
|
||||
setDozeAmount(0.5f)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyDozeAmountOutputTracksDelay() {
|
||||
dozeAmountOutputClampsTo1WhenDelayStarts()
|
||||
|
||||
// Animator waiting the delay amount should not yet affect the output
|
||||
animatorTestRule.advanceTimeBy(delayedDozeDelay)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
|
||||
// input doze amount change to 0 has no effect
|
||||
setDozeAmount(0.0f)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
|
||||
// Advancing the delay to 50% will cause the 50% output
|
||||
animatorTestRule.advanceTimeBy(delayedDozeDuration / 2)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
|
||||
|
||||
// Now advance delay to 100% completion; notifications become fully visible
|
||||
animatorTestRule.advanceTimeBy(delayedDozeDuration / 2)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
|
||||
|
||||
// Now advance delay to 200% completion -- should not invoke anything else
|
||||
animatorTestRule.advanceTimeBy(delayedDozeDuration)
|
||||
verify(stackScrollerController, never()).setDozeAmount(anyFloat())
|
||||
verify(stackScrollerController, never()).setHideAmount(anyFloat(), anyFloat())
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyDelayedDozeAmountCanBeOverridden() {
|
||||
dozeAmountOutputClampsTo1WhenDelayStarts()
|
||||
|
||||
// input doze amount change to 0 has no effect
|
||||
setDozeAmount(0.0f)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
|
||||
// Advancing the delay to 50% will cause the 50% output
|
||||
animatorTestRule.advanceTimeBy(delayedDozeDelay + delayedDozeDuration / 2)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
|
||||
|
||||
// Enabling bypass and showing keyguard will override back to fully dozing/hidden
|
||||
setBypassEnabled(true)
|
||||
setStatusBarState(StatusBarState.KEYGUARD)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyRemovingOverrideRestoresOtherwiseCalculatedDozeAmount() {
|
||||
verifyDelayedDozeAmountCanBeOverridden()
|
||||
|
||||
// Disabling bypass will return back to the 50% value
|
||||
setBypassEnabled(false)
|
||||
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f)
|
||||
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
|
||||
}
|
||||
|
||||
private fun verifyStackScrollerDozeAndHideAmount(dozeAmount: Float, hideAmount: Float) {
|
||||
// First verify that we did in-fact receive the correct values
|
||||
verify(stackScrollerController).setDozeAmount(dozeAmount)
|
||||
verify(stackScrollerController).setHideAmount(hideAmount, hideAmountEased ?: hideAmount)
|
||||
verify(stackScrollerController).setDozeAmount(eased(dozeAmount))
|
||||
verify(stackScrollerController).setHideAmount(hideAmount, eased(hideAmount))
|
||||
// Now verify that there was just this ONE call to each of these methods
|
||||
verify(stackScrollerController).setDozeAmount(anyFloat())
|
||||
verify(stackScrollerController).setHideAmount(anyFloat(), anyFloat())
|
||||
// clear for next check
|
||||
clearInvocations(stackScrollerController)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user