Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ae95adb authored by Marcello Galhardo's avatar Marcello Galhardo Committed by Android (Google) Code Review
Browse files

Merge "Improve AmbientState test coverage" into tm-qpr-dev

parents f5ee8436 faeaa310
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -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);
    }
+1 −1
Original line number Diff line number Diff line
@@ -5021,7 +5021,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();
+390 −0
Original line number Diff line number Diff line
/*
 * 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
+1 −1
Original line number Diff line number Diff line
@@ -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());
    }
+12 −1
Original line number Diff line number Diff line
@@ -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(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
 */
inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)

/**
 * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when