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

Commit 9d43da47 authored by Johannes Gallmann's avatar Johannes Gallmann Committed by Automerger Merge Worker
Browse files

Merge "Fix persistent dot not removed due to race condition in scheduler" into...

Merge "Fix persistent dot not removed due to race condition in scheduler" into udc-dev am: 31a8777c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/25379523



Change-Id: I120a18d795ab59bd03beb67f1beed8d0d8a807b3
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 48917af7 31a8777c
Loading
Loading
Loading
Loading
+12 −20
Original line number Diff line number Diff line
@@ -182,19 +182,19 @@ constructor(
        // Set hasPersistentDot to false. If the animationState is anything before ANIMATING_OUT,
        // the disappear animation will not animate into a dot but remove the chip entirely
        hasPersistentDot = false
        // if we are currently showing a persistent dot, hide it
        if (animationState.value == SHOWING_PERSISTENT_DOT) notifyHidePersistentDot()
        // if we are currently animating into a dot, wait for the animation to finish and then hide
        // the dot
        if (animationState.value == ANIMATING_OUT) {
            coroutineScope.launch {
                withTimeout(DISAPPEAR_ANIMATION_DURATION) {
                    animationState.first {
                        it == SHOWING_PERSISTENT_DOT || it == IDLE || it == ANIMATION_QUEUED
                    }

        if (animationState.value == SHOWING_PERSISTENT_DOT) {
            // if we are currently showing a persistent dot, hide it and update the animationState
            notifyHidePersistentDot()
            if (scheduledEvent.value != null) {
                animationState.value = ANIMATION_QUEUED
            } else {
                animationState.value = IDLE
            }
            }
        } else if (animationState.value == ANIMATING_OUT) {
            // if we are currently animating out, hide the dot. The animationState will be updated
            // once the animation has ended in the onAnimationEnd callback
            notifyHidePersistentDot()
        }
    }

@@ -376,14 +376,6 @@ constructor(
        Assert.isMainThread()
        val anims: List<Animator> = listeners.mapNotNull { it.onHidePersistentDot() }

        if (animationState.value == SHOWING_PERSISTENT_DOT) {
            if (scheduledEvent.value != null) {
                animationState.value = ANIMATION_QUEUED
            } else {
                animationState.value = IDLE
            }
        }

        if (anims.isNotEmpty()) {
            val aSet = AnimatorSet()
            aSet.playTogether(anims)
+40 −4
Original line number Diff line number Diff line
@@ -410,15 +410,16 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {

        // remove persistent dot
        systemStatusAnimationScheduler.removePersistentDot()
        testScheduler.runCurrent()

        // verify that the onHidePersistentDot callback is invoked
        verify(listener, times(1)).onHidePersistentDot()

        // skip disappear animation
        animatorTestRule.advanceTimeBy(DISAPPEAR_ANIMATION_DURATION)
        testScheduler.runCurrent()

        // verify that animationState changes to IDLE and onHidePersistentDot callback is invoked
        // verify that animationState changes to IDLE
        assertEquals(IDLE, systemStatusAnimationScheduler.getAnimationState())
        verify(listener, times(1)).onHidePersistentDot()
    }

    @Test
@@ -483,7 +484,6 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {

        // request removal of persistent dot
        systemStatusAnimationScheduler.removePersistentDot()
        testScheduler.runCurrent()

        // schedule another high priority event while the event is animating out
        createAndScheduleFakePrivacyEvent()
@@ -499,6 +499,42 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
        verify(listener, times(1)).onHidePersistentDot()
    }

    @Test
    fun testDotIsRemoved_evenIfAnimatorCallbackIsDelayed() = runTest {
        // Instantiate class under test with TestScope from runTest
        initializeSystemStatusAnimationScheduler(testScope = this)

        // create and schedule high priority event
        createAndScheduleFakePrivacyEvent()

        // skip chip animation lifecycle and fast forward to ANIMATING_OUT state
        fastForwardAnimationToState(ANIMATING_OUT)
        assertEquals(ANIMATING_OUT, systemStatusAnimationScheduler.getAnimationState())
        verify(listener, times(1)).onSystemStatusAnimationTransitionToPersistentDot(any())

        // request removal of persistent dot
        systemStatusAnimationScheduler.removePersistentDot()

        // verify that the state is still ANIMATING_OUT
        assertEquals(ANIMATING_OUT, systemStatusAnimationScheduler.getAnimationState())

        // skip disappear animation duration
        testScheduler.advanceTimeBy(DISAPPEAR_ANIMATION_DURATION + 1)
        // In an old implementation this would trigger a coroutine timeout causing the
        // onHidePersistentDot callback to be missed.
        testScheduler.runCurrent()

        // advance animator time to invoke onAnimationEnd callback
        animatorTestRule.advanceTimeBy(DISAPPEAR_ANIMATION_DURATION)
        testScheduler.runCurrent()

        // verify that onHidePersistentDot is invoked despite the animator callback being delayed
        // (it's invoked more than DISAPPEAR_ANIMATION_DURATION after the dot removal was requested)
        verify(listener, times(1)).onHidePersistentDot()
        // verify that animationState is IDLE
        assertEquals(IDLE, systemStatusAnimationScheduler.getAnimationState())
    }

    private fun TestScope.fastForwardAnimationToState(@SystemAnimationState animationState: Int) {
        // this function should only be called directly after posting a status event
        assertEquals(ANIMATION_QUEUED, systemStatusAnimationScheduler.getAnimationState())