Fix the weirdly broken code in NotificationWakeUpCoordinator

* Remove an extra block of bypass code that was unreachanle
* Update state and return early for EVERY special case in onStateChanged

Test: atest NotificationWakeUpCoordinatorTest
Bug: 250946719
Change-Id: I58117a5fecf8fb224915c7550e006b1b504ef09c
This commit is contained in:
Jeff DeCew
2022-12-12 19:20:51 +00:00
parent 24311a6474
commit bb70a79737
2 changed files with 172 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification
import android.animation.ObjectAnimator
import android.util.FloatProperty
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
@@ -302,29 +303,29 @@ class NotificationWakeUpCoordinator @Inject constructor(
// the doze amount to 0f (not dozing) so that the notifications are no longer hidden.
// See: UnlockedScreenOffAnimationController.onFinishedWakingUp()
setDozeAmount(0f, 0f, source = "Override: Shade->Shade (lock cancelled by unlock)")
this.state = newState
return
}
if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) {
this.state = newState
return
}
if (overrideDozeAmountIfBypass()) {
this.state = newState
return
}
maybeClearDozeAmountOverrideHidingNotifs()
if (bypassController.bypassEnabled &&
newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
(!statusBarStateController.isDozing || shouldAnimateVisibility())) {
// We're leaving shade locked. Let's animate the notifications away
setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
}
this.state = newState
}
@VisibleForTesting
val statusBarState: Int
get() = state
override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) {
val collapsedEnough = event.fraction <= 0.9f
if (collapsedEnough != this.collapsedEnoughToHide) {

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2023 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.notification
import android.testing.AndroidTestingRunner
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.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.util.mockito.mock
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.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.verify
@RunWith(AndroidTestingRunner::class)
@SmallTest
class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
private val dumpManager: DumpManager = mock()
private val headsUpManager: HeadsUpManager = mock()
private val statusBarStateController: StatusBarStateController = mock()
private val bypassController: KeyguardBypassController = mock()
private val dozeParameters: DozeParameters = mock()
private val screenOffAnimationController: ScreenOffAnimationController = mock()
private val logger: NotificationWakeUpCoordinatorLogger = mock()
private val stackScrollerController: NotificationStackScrollLayoutController = mock()
private lateinit var notificationWakeUpCoordinator: NotificationWakeUpCoordinator
private lateinit var statusBarStateCallback: StatusBarStateController.StateListener
private lateinit var bypassChangeCallback: KeyguardBypassController.OnBypassStateChangedListener
private var bypassEnabled: Boolean = false
private var statusBarState: Int = StatusBarState.KEYGUARD
private var dozeAmount: Float = 0f
private fun setBypassEnabled(enabled: Boolean) {
bypassEnabled = enabled
bypassChangeCallback.onBypassStateChanged(enabled)
}
private fun setStatusBarState(state: Int) {
statusBarState = state
statusBarStateCallback.onStateChanged(state)
}
private fun setDozeAmount(dozeAmount: Float) {
this.dozeAmount = dozeAmount
statusBarStateCallback.onDozeAmountChanged(dozeAmount, dozeAmount)
}
@Before
fun setup() {
whenever(bypassController.bypassEnabled).then { bypassEnabled }
whenever(statusBarStateController.state).then { statusBarState }
notificationWakeUpCoordinator =
NotificationWakeUpCoordinator(
dumpManager,
headsUpManager,
statusBarStateController,
bypassController,
dozeParameters,
screenOffAnimationController,
logger,
)
statusBarStateCallback = withArgCaptor {
verify(statusBarStateController).addCallback(capture())
}
bypassChangeCallback = withArgCaptor {
verify(bypassController).registerOnBypassStateChangedListener(capture())
}
notificationWakeUpCoordinator.setStackScroller(stackScrollerController)
}
@Test
fun setDozeToOneWillFullyHideNotifications() {
setDozeAmount(1f)
verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
}
@Test
fun setDozeToZeroWillFullyShowNotifications() {
setDozeAmount(0f)
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
}
@Test
fun setDozeToOneThenZeroWillFullyShowNotifications() {
setDozeToOneWillFullyHideNotifications()
clearInvocations(stackScrollerController)
setDozeToZeroWillFullyShowNotifications()
}
@Test
fun setDozeToHalfWillHalfShowNotifications() {
setDozeAmount(0.5f)
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f)
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
}
@Test
fun setDozeToZeroWithBypassWillFullyHideNotifications() {
bypassEnabled = true
setDozeAmount(0f)
verifyStackScrollerDozeAndHideAmount(dozeAmount = 01f, hideAmount = 1f)
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
}
@Test
fun disablingBypassWillShowNotifications() {
setDozeToZeroWithBypassWillFullyHideNotifications()
clearInvocations(stackScrollerController)
setBypassEnabled(false)
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
}
@Test
fun switchingToShadeWithBypassEnabledWillShowNotifications() {
setDozeToZeroWithBypassWillFullyHideNotifications()
clearInvocations(stackScrollerController)
setStatusBarState(StatusBarState.SHADE)
verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
assertThat(notificationWakeUpCoordinator.statusBarState).isEqualTo(StatusBarState.SHADE)
}
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, hideAmount)
// Now verify that there was just this ONE call to each of these methods
verify(stackScrollerController).setDozeAmount(anyFloat())
verify(stackScrollerController).setHideAmount(anyFloat(), anyFloat())
}
}