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

Commit 7d5c42d4 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: I7710662d8f126314e11312cbda0a1809cb7344f1
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents a2e1f698 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())