Improve AmbientState test coverage
AmbientState is a critical state holder for system holder but does not contains unit tests. The tests here are extracted from the attempt to convert AmbientState to Kotlin, and introduce a basic unit test coverage that we can build upon to increase changes confidence. Because AmbientState is a simple state holder, the tests are mostly checking property modifications. We did not include test for any property that does not contain a custom getter or setter. Test: atest ~/tm-qpr-dev/frameworks/base/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt Fixes: 242754590 Change-Id: Ieb95b9845ee044ae293a3934b9a688c879c64249
This commit is contained in:
@@ -23,6 +23,8 @@ import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.util.MathUtils;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
@@ -137,7 +139,17 @@ public class AmbientState implements Dumpable {
|
||||
* True right after we swipe up on lockscreen and have not finished the fling down that follows.
|
||||
* False when we stop flinging or leave lockscreen.
|
||||
*/
|
||||
private boolean mNeedFlingAfterLockscreenSwipeUp = false;
|
||||
private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false;
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isFlingRequiredAfterLockScreenSwipeUp() {
|
||||
return mIsFlingRequiredAfterLockScreenSwipeUp;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setFlingRequiredAfterLockScreenSwipeUp(boolean value) {
|
||||
mIsFlingRequiredAfterLockScreenSwipeUp = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Height of the notifications panel without top padding when expansion completes.
|
||||
@@ -181,7 +193,7 @@ public class AmbientState implements Dumpable {
|
||||
public void setSwipingUp(boolean isSwipingUp) {
|
||||
if (!isSwipingUp && mIsSwipingUp) {
|
||||
// Just stopped swiping up.
|
||||
mNeedFlingAfterLockscreenSwipeUp = true;
|
||||
mIsFlingRequiredAfterLockScreenSwipeUp = true;
|
||||
}
|
||||
mIsSwipingUp = isSwipingUp;
|
||||
}
|
||||
@@ -196,10 +208,10 @@ public class AmbientState implements Dumpable {
|
||||
/**
|
||||
* @param isFlinging Whether we are flinging the shade open or closed.
|
||||
*/
|
||||
public void setIsFlinging(boolean isFlinging) {
|
||||
public void setFlinging(boolean isFlinging) {
|
||||
if (isOnKeyguard() && !isFlinging && mIsFlinging) {
|
||||
// Just stopped flinging.
|
||||
mNeedFlingAfterLockscreenSwipeUp = false;
|
||||
mIsFlingRequiredAfterLockScreenSwipeUp = false;
|
||||
}
|
||||
mIsFlinging = isFlinging;
|
||||
}
|
||||
@@ -508,7 +520,7 @@ public class AmbientState implements Dumpable {
|
||||
|
||||
public void setStatusBarState(int statusBarState) {
|
||||
if (mStatusBarState != StatusBarState.KEYGUARD) {
|
||||
mNeedFlingAfterLockscreenSwipeUp = false;
|
||||
mIsFlingRequiredAfterLockScreenSwipeUp = false;
|
||||
}
|
||||
mStatusBarState = statusBarState;
|
||||
}
|
||||
@@ -576,7 +588,7 @@ public class AmbientState implements Dumpable {
|
||||
* @return Whether we need to do a fling down after swiping up on lockscreen.
|
||||
*/
|
||||
public boolean isFlingingAfterSwipeUpOnLockscreen() {
|
||||
return mIsFlinging && mNeedFlingAfterLockscreenSwipeUp;
|
||||
return mIsFlinging && mIsFlingRequiredAfterLockScreenSwipeUp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -744,7 +756,8 @@ public class AmbientState implements Dumpable {
|
||||
pw.println("mIsSwipingUp=" + mIsSwipingUp);
|
||||
pw.println("mPanelTracking=" + mPanelTracking);
|
||||
pw.println("mIsFlinging=" + mIsFlinging);
|
||||
pw.println("mNeedFlingAfterLockscreenSwipeUp=" + mNeedFlingAfterLockscreenSwipeUp);
|
||||
pw.println("mIsFlingRequiredAfterLockScreenSwipeUp="
|
||||
+ mIsFlingRequiredAfterLockScreenSwipeUp);
|
||||
pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements);
|
||||
pw.println("mBaseZHeight=" + mBaseZHeight);
|
||||
}
|
||||
|
||||
@@ -5042,7 +5042,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
public void setPanelFlinging(boolean flinging) {
|
||||
mAmbientState.setIsFlinging(flinging);
|
||||
mAmbientState.setFlinging(flinging);
|
||||
if (!flinging) {
|
||||
// re-calculate the stack height which was frozen while flinging
|
||||
updateStackPosition();
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* 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.notification.stack
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
private const val MAX_PULSE_HEIGHT = 100000f
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
class AmbientStateTest : SysuiTestCase() {
|
||||
|
||||
private val dumpManager = mock<DumpManager>()
|
||||
private val sectionProvider = StackScrollAlgorithm.SectionProvider { _, _ -> false }
|
||||
private val bypassController = StackScrollAlgorithm.BypassController { false }
|
||||
private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
|
||||
|
||||
private lateinit var sut: AmbientState
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
sut =
|
||||
AmbientState(
|
||||
context,
|
||||
dumpManager,
|
||||
sectionProvider,
|
||||
bypassController,
|
||||
statusBarKeyguardViewManager,
|
||||
)
|
||||
}
|
||||
|
||||
// region isDimmed
|
||||
@Test
|
||||
fun isDimmed_whenTrue_shouldReturnTrue() {
|
||||
sut.arrangeDimmed(true)
|
||||
|
||||
assertThat(sut.isDimmed).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isDimmed_whenFalse_shouldReturnFalse() {
|
||||
sut.arrangeDimmed(false)
|
||||
|
||||
assertThat(sut.isDimmed).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isDimmed_whenDozeAmountIsEmpty_shouldReturnTrue() {
|
||||
sut.arrangeDimmed(true)
|
||||
sut.dozeAmount = 0f
|
||||
|
||||
assertThat(sut.isDimmed).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isDimmed_whenPulseExpandingIsFalse_shouldReturnTrue() {
|
||||
sut.arrangeDimmed(true)
|
||||
sut.arrangePulseExpanding(false)
|
||||
sut.dozeAmount = 1f // arrangePulseExpanding changes dozeAmount
|
||||
|
||||
assertThat(sut.isDimmed).isTrue()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region pulseHeight
|
||||
@Test
|
||||
fun pulseHeight_whenValueChanged_shouldCallListener() {
|
||||
var listenerCalledCount = 0
|
||||
sut.pulseHeight = MAX_PULSE_HEIGHT
|
||||
sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
|
||||
|
||||
sut.pulseHeight = 0f
|
||||
|
||||
assertThat(listenerCalledCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulseHeight_whenSetSameValue_shouldDoNothing() {
|
||||
var listenerCalledCount = 0
|
||||
sut.pulseHeight = MAX_PULSE_HEIGHT
|
||||
sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
|
||||
|
||||
sut.pulseHeight = MAX_PULSE_HEIGHT
|
||||
|
||||
assertThat(listenerCalledCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulseHeight_whenValueIsFull_shouldReturn0() {
|
||||
sut.pulseHeight = MAX_PULSE_HEIGHT
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulseHeight_whenValueIsNotFull_shouldReturnValue() {
|
||||
val expected = MAX_PULSE_HEIGHT - 0.1f
|
||||
sut.pulseHeight = expected
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(expected)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region statusBarState
|
||||
@Test
|
||||
fun statusBarState_whenPreviousStateIsNotKeyguardAndChange_shouldSetIsFlingRequiredToFalse() {
|
||||
sut.setStatusBarState(StatusBarState.SHADE)
|
||||
sut.isFlingRequiredAfterLockScreenSwipeUp = true
|
||||
|
||||
sut.setStatusBarState(StatusBarState.KEYGUARD)
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun statusBarState_whenPreviousStateIsKeyguardAndChange_shouldDoNothing() {
|
||||
sut.setStatusBarState(StatusBarState.KEYGUARD)
|
||||
sut.isFlingRequiredAfterLockScreenSwipeUp = true
|
||||
|
||||
sut.setStatusBarState(StatusBarState.SHADE)
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region hideAmount
|
||||
@Test
|
||||
fun hideAmount_whenSetToFullValue_shouldReturnZeroFromPulseHeight() {
|
||||
sut.hideAmount = 0f
|
||||
sut.pulseHeight = 1f
|
||||
|
||||
sut.hideAmount = 1f
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hideAmount_whenSetToAnyNotFullValue_shouldDoNothing() {
|
||||
sut.hideAmount = 1f
|
||||
sut.pulseHeight = 1f
|
||||
|
||||
sut.hideAmount = 0f
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(1f)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region dozeAmount
|
||||
@Test
|
||||
fun dozeAmount_whenDozeAmountIsSetToFullDozing_shouldReturnZeroFromPulseHeight() {
|
||||
sut.dozeAmount = 0f
|
||||
sut.pulseHeight = 1f
|
||||
|
||||
sut.dozeAmount = 1f
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dozeAmount_whenDozeAmountIsSetToFullAwake_shouldReturnZeroFromPulseHeight() {
|
||||
sut.dozeAmount = 1f
|
||||
sut.pulseHeight = 1f
|
||||
|
||||
sut.dozeAmount = 0f
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dozeAmount_whenDozeAmountIsSetAnyValueNotFullAwakeOrDozing_shouldDoNothing() {
|
||||
sut.dozeAmount = 1f
|
||||
sut.pulseHeight = 1f
|
||||
|
||||
sut.dozeAmount = 0.5f
|
||||
|
||||
assertThat(sut.pulseHeight).isEqualTo(1f)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region trackedHeadsUpRow
|
||||
@Test
|
||||
fun trackedHeadsUpRow_whenIsAboveTheShelf_shouldReturnInstance() {
|
||||
sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(true) }
|
||||
|
||||
assertThat(sut.trackedHeadsUpRow).isNotNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun trackedHeadsUpRow_whenIsNotAboveTheShelf_shouldReturnNull() {
|
||||
sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(false) }
|
||||
|
||||
assertThat(sut.trackedHeadsUpRow).isNull()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region isSwipingUp
|
||||
@Test
|
||||
fun isSwipingUp_whenValueChangedToTrue_shouldRequireFling() {
|
||||
sut.isSwipingUp = false
|
||||
sut.isFlingRequiredAfterLockScreenSwipeUp = false
|
||||
|
||||
sut.isSwipingUp = true
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSwipingUp_whenValueChangedToFalse_shouldRequireFling() {
|
||||
sut.isSwipingUp = true
|
||||
sut.isFlingRequiredAfterLockScreenSwipeUp = false
|
||||
|
||||
sut.isSwipingUp = false
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region isFlinging
|
||||
@Test
|
||||
fun isFlinging_shouldNotNeedFling() {
|
||||
sut.arrangeFlinging(true)
|
||||
|
||||
sut.setFlinging(false)
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isFlinging_whenNotOnLockScreen_shouldDoNothing() {
|
||||
sut.arrangeFlinging(true)
|
||||
sut.setStatusBarState(StatusBarState.SHADE)
|
||||
sut.isFlingRequiredAfterLockScreenSwipeUp = true
|
||||
|
||||
sut.setFlinging(false)
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isFlinging_whenValueChangedToTrue_shouldDoNothing() {
|
||||
sut.arrangeFlinging(false)
|
||||
|
||||
sut.setFlinging(true)
|
||||
|
||||
assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region scrollY
|
||||
@Test
|
||||
fun scrollY_shouldSetValueGreaterThanZero() {
|
||||
sut.scrollY = 0
|
||||
|
||||
sut.scrollY = 1
|
||||
|
||||
assertThat(sut.scrollY).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun scrollY_shouldNotSetValueLessThanZero() {
|
||||
sut.scrollY = 0
|
||||
|
||||
sut.scrollY = -1
|
||||
|
||||
assertThat(sut.scrollY).isEqualTo(0)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region setOverScrollAmount
|
||||
fun setOverScrollAmount_shouldSetValueOnTop() {
|
||||
sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ true)
|
||||
|
||||
val resultOnTop = sut.getOverScrollAmount(/* top = */ true)
|
||||
val resultOnBottom = sut.getOverScrollAmount(/* top = */ false)
|
||||
|
||||
assertThat(resultOnTop).isEqualTo(10f)
|
||||
assertThat(resultOnBottom).isEqualTo(0f)
|
||||
}
|
||||
|
||||
fun setOverScrollAmount_shouldSetValueOnBottom() {
|
||||
sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ false)
|
||||
|
||||
val resultOnTop = sut.getOverScrollAmount(/* top */ true)
|
||||
val resultOnBottom = sut.getOverScrollAmount(/* top */ false)
|
||||
|
||||
assertThat(resultOnTop).isEqualTo(0f)
|
||||
assertThat(resultOnBottom).isEqualTo(10f)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region IsPulseExpanding
|
||||
@Test
|
||||
fun isPulseExpanding_shouldReturnTrue() {
|
||||
sut.arrangePulseExpanding(true)
|
||||
|
||||
assertThat(sut.isPulseExpanding).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isPulseExpanding_whenPulseHeightIsMax_shouldReturnFalse() {
|
||||
sut.arrangePulseExpanding(true)
|
||||
sut.pulseHeight = MAX_PULSE_HEIGHT
|
||||
|
||||
assertThat(sut.isPulseExpanding).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isPulseExpanding_whenDozeAmountIsZero_shouldReturnFalse() {
|
||||
sut.arrangePulseExpanding(true)
|
||||
sut.dozeAmount = 0f
|
||||
|
||||
assertThat(sut.isPulseExpanding).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isPulseExpanding_whenHideAmountIsFull_shouldReturnFalse() {
|
||||
sut.arrangePulseExpanding(true)
|
||||
sut.hideAmount = 1f
|
||||
|
||||
assertThat(sut.isPulseExpanding).isFalse()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region isOnKeyguard
|
||||
@Test
|
||||
fun isOnKeyguard_whenStatusBarStateIsKeyguard_shouldReturnTrue() {
|
||||
sut.setStatusBarState(StatusBarState.KEYGUARD)
|
||||
|
||||
assertThat(sut.isOnKeyguard).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isOnKeyguard_whenStatusBarStateIsNotKeyguard_shouldReturnFalse() {
|
||||
sut.setStatusBarState(StatusBarState.SHADE)
|
||||
|
||||
assertThat(sut.isOnKeyguard).isFalse()
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
// region Arrange helper methods.
|
||||
private fun AmbientState.arrangeDimmed(value: Boolean) {
|
||||
isDimmed = value
|
||||
dozeAmount = if (value) 0f else 1f
|
||||
arrangePulseExpanding(!value)
|
||||
}
|
||||
|
||||
private fun AmbientState.arrangePulseExpanding(value: Boolean) {
|
||||
if (value) {
|
||||
dozeAmount = 1f
|
||||
hideAmount = 0f
|
||||
pulseHeight = 0f
|
||||
} else {
|
||||
dozeAmount = 0f
|
||||
hideAmount = 1f
|
||||
pulseHeight = MAX_PULSE_HEIGHT
|
||||
}
|
||||
}
|
||||
|
||||
private fun AmbientState.arrangeFlinging(value: Boolean) {
|
||||
setStatusBarState(StatusBarState.KEYGUARD)
|
||||
setFlinging(value)
|
||||
isFlingRequiredAfterLockScreenSwipeUp = true
|
||||
}
|
||||
// endregion
|
||||
@@ -250,7 +250,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
// Validate that when the animation ends the stackEndHeight is recalculated immediately
|
||||
clearInvocations(mAmbientState);
|
||||
mStackScroller.setPanelFlinging(false);
|
||||
verify(mAmbientState).setIsFlinging(eq(false));
|
||||
verify(mAmbientState).setFlinging(eq(false));
|
||||
verify(mAmbientState).setStackEndHeight(anyFloat());
|
||||
verify(mAmbientState).setStackHeight(anyFloat());
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ package com.android.systemui.util.mockito
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatcher
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.stubbing.OngoingStubbing
|
||||
|
||||
/**
|
||||
* Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
|
||||
@@ -77,8 +78,18 @@ inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> =
|
||||
* Helper function for creating new mocks, without the need to pass in a [Class] instance.
|
||||
*
|
||||
* Generic T is nullable because implicitly bounded by Any?.
|
||||
*
|
||||
* @param apply builder function to simplify stub configuration by improving type inference.
|
||||
*/
|
||||
inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
|
||||
inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java)
|
||||
.apply(apply)
|
||||
|
||||
/**
|
||||
* Helper function for stubbing methods without the need to use backticks.
|
||||
*
|
||||
* @see Mockito.when
|
||||
*/
|
||||
fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
|
||||
|
||||
/**
|
||||
* A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
|
||||
|
||||
Reference in New Issue
Block a user