/* * 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.app.Notification import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.flags.andSceneContainer import com.android.systemui.res.R import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository import com.android.systemui.statusbar.notification.headsup.AvalancheController import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.testKosmos 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 import org.mockito.ArgumentMatchers.anyString import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters private const val MAX_PULSE_HEIGHT = 100000f @RunWith(ParameterizedAndroidJunit4::class) @SmallTest class AmbientStateTest(flags: FlagsParameterization) : SysuiTestCase() { private val kosmos = testKosmos() private val dumpManager = mock() private val sectionProvider = kosmos.stackScrollAlgorithmSectionProvider private val bypassController = StackScrollAlgorithm.BypassController { false } private val statusBarKeyguardViewManager = mock() private val largeScreenShadeInterpolator = mock() private val avalancheController = mock() private val headsupRepository = mock() private lateinit var sut: AmbientState companion object { @JvmStatic @Parameters(name = "{0}") fun getParams(): List { return FlagsParameterization.allCombinationsOf().andSceneContainer() } } init { mSetFlagsRule.setFlagsParameterization(flags) } @Before fun setUp() { sut = AmbientState( context, dumpManager, sectionProvider, bypassController, statusBarKeyguardViewManager, largeScreenShadeInterpolator, headsupRepository, avalancheController, ) } // 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 @DisableSceneContainer fun isSwipingUp_whenValueChangedToTrue_shouldRequireFling() { sut.isSwipingUp = false sut.isFlingRequiredAfterLockScreenSwipeUp = false sut.isSwipingUp = true assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse() } @Test @DisableSceneContainer fun isSwipingUp_whenValueChangedToFalse_shouldRequireFling() { sut.isSwipingUp = true sut.isFlingRequiredAfterLockScreenSwipeUp = false sut.isSwipingUp = false assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue() } // endregion // region isFlinging @Test @DisableSceneContainer fun isFlinging_shouldNotNeedFling() { sut.arrangeFlinging(true) sut.setFlinging(false) assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse() } @Test @DisableSceneContainer fun isFlinging_whenNotOnLockScreen_shouldDoNothing() { sut.arrangeFlinging(true) sut.setStatusBarState(StatusBarState.SHADE) sut.isFlingRequiredAfterLockScreenSwipeUp = true sut.setFlinging(false) assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue() } @Test @DisableSceneContainer fun isFlinging_whenValueChangedToTrue_shouldDoNothing() { sut.arrangeFlinging(false) sut.setFlinging(true) assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue() } // endregion // region scrollY @Test @DisableSceneContainer fun scrollY_shouldSetValueGreaterThanZero() { sut.scrollY = 0 sut.scrollY = 1 assertThat(sut.scrollY).isEqualTo(1) } @Test @DisableSceneContainer fun scrollY_shouldNotSetValueLessThanZero() { sut.scrollY = 0 sut.scrollY = -1 assertThat(sut.scrollY).isEqualTo(0) } // endregion // region setOverScrollAmount @Test @DisableSceneContainer 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 mIsClosing @Test fun isClosing_whenShadeClosing_shouldReturnTrue() { sut.setIsClosing(true) assertThat(sut.isClosing).isTrue() } @Test fun isClosing_whenShadeFinishClosing_shouldReturnFalse() { sut.setIsClosing(false) assertThat(sut.isClosing).isFalse() } // endregion // region isPulsing @Test @EnableFlags(NotificationBundleUi.FLAG_NAME) fun isPulsing_key() { whenever(headsupRepository.isHeadsUpEntry(anyString())).thenReturn(true) sut.isPulsing = true assertThat(sut.isPulsing("key")).isTrue() whenever(headsupRepository.isHeadsUpEntry(anyString())).thenReturn(false) sut.isPulsing = true assertThat(sut.isPulsing("key")).isFalse() } @Test @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isPulsing_entry() { val notification: Notification = Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build() val entry = NotificationEntryBuilder().setNotification(notification).build() sut.isPulsing = true entry.setIsHeadsUpEntry(true) assertThat(sut.isPulsing(entry)).isTrue() sut.isPulsing = true entry.setIsHeadsUpEntry(false) assertThat(sut.isPulsing(entry)).isFalse() } // endregion } // region Arrange helper methods. 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