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

Commit 83e90f0e authored by Luca Zuccarini's avatar Luca Zuccarini Committed by Android (Google) Code Review
Browse files

Merge "Enable origin animations when launching widgets from Communal." into main

parents baf2c31a 194fbdec
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
    }

    @Test
    fun keyguardGoesAway_forceBlankScene() =
    fun keyguardGoesAway_whenLaunchingWidget_doNotForceBlankScene() =
        with(kosmos) {
            testScope.runTest {
                val scene by collectLastValue(communalSceneInteractor.currentScene)
@@ -106,6 +106,27 @@ class CommunalSceneStartableTest : SysuiTestCase() {
                communalSceneInteractor.changeScene(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)

                communalSceneInteractor.setIsLaunchingWidget(true)
                fakeKeyguardTransitionRepository.sendTransitionSteps(
                    from = KeyguardState.PRIMARY_BOUNCER,
                    to = KeyguardState.GONE,
                    testScope = this
                )

                assertThat(scene).isEqualTo(CommunalScenes.Communal)
            }
        }

    @Test
    fun keyguardGoesAway_whenNotLaunchingWidget_forceBlankScene() =
        with(kosmos) {
            testScope.runTest {
                val scene by collectLastValue(communalSceneInteractor.currentScene)

                communalSceneInteractor.changeScene(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)

                communalSceneInteractor.setIsLaunchingWidget(false)
                fakeKeyguardTransitionRepository.sendTransitionSteps(
                    from = KeyguardState.PRIMARY_BOUNCER,
                    to = KeyguardState.GONE,
+42 −18
Original line number Diff line number Diff line
@@ -26,14 +26,23 @@ import androidx.core.util.component2
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.widgets.CommunalTransitionAnimatorController
import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.testKosmos
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.isNull
import org.mockito.kotlin.mock
import org.mockito.kotlin.notNull
import org.mockito.kotlin.refEq
import org.mockito.kotlin.verify

@@ -41,6 +50,7 @@ import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class SmartspaceInteractionHandlerTest : SysuiTestCase() {
    private val activityStarter = mock<ActivityStarter>()
    private val kosmos = testKosmos()

    private val testIntent =
        PendingIntent.getActivity(
@@ -51,12 +61,22 @@ class SmartspaceInteractionHandlerTest : SysuiTestCase() {
        )
    private val testResponse = RemoteResponse.fromPendingIntent(testIntent)

    private val underTest: SmartspaceInteractionHandler by lazy {
        SmartspaceInteractionHandler(activityStarter)
    private lateinit var underTest: SmartspaceInteractionHandler

    @Before
    fun setUp() {
        with(kosmos) {
            underTest = SmartspaceInteractionHandler(activityStarter, communalSceneInteractor)
        }
    }

    @Test
    fun launchAnimatorIsUsedForSmartspaceView() {
        with(kosmos) {
            testScope.runTest {
                val launching by collectLastValue(communalSceneInteractor.isLaunchingWidget)
                assertFalse(launching!!)

                val parent = FrameLayout(context)
                val view = SmartspaceAppWidgetHostView(context)
                parent.addView(view)
@@ -64,17 +84,21 @@ class SmartspaceInteractionHandlerTest : SysuiTestCase() {

                underTest.onInteraction(view, testIntent, testResponse)

        // Verify that we pass in a non-null animation controller
                // Verify that we set the state correctly
                assertTrue(launching!!)
                // Verify that we pass in a non-null Communal animation controller
                verify(activityStarter)
                    .startPendingIntentWithoutDismissing(
                        /* intent = */ eq(testIntent),
                        /* dismissShade = */ eq(false),
                        /* intentSentUiThreadCallback = */ isNull(),
                /* animationController = */ notNull(),
                        /* animationController = */ any<CommunalTransitionAnimatorController>(),
                        /* fillInIntent = */ refEq(fillInIntent),
                        /* extraOptions = */ refEq(activityOptions.toBundle()),
                    )
            }
        }
    }

    @Test
    fun launchAnimatorIsNotUsedForRegularView() {
+115 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.
 */

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.widgets.CommunalTransitionAnimatorController
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalTransitionAnimatorControllerTest : SysuiTestCase() {
    private val controller = mock<ActivityTransitionAnimator.Controller>()
    private val kosmos = testKosmos()

    private lateinit var underTest: CommunalTransitionAnimatorController

    @Before
    fun setUp() {
        with(kosmos) {
            underTest = CommunalTransitionAnimatorController(controller, communalSceneInteractor)
        }
    }

    @Test
    fun doNotAnimate_launchingWidgetStateIsCleared() {
        with(kosmos) {
            testScope.runTest {
                val launching by collectLastValue(communalSceneInteractor.isLaunchingWidget)

                communalSceneInteractor.setIsLaunchingWidget(true)
                assertTrue(launching!!)

                underTest.onIntentStarted(willAnimate = false)
                assertFalse(launching!!)
                verify(controller).onIntentStarted(willAnimate = false)
            }
        }
    }

    @Test
    fun animationCancelled_launchingWidgetStateIsClearedAndSceneIsNotChanged() {
        with(kosmos) {
            testScope.runTest {
                val launching by collectLastValue(communalSceneInteractor.isLaunchingWidget)
                val scene by collectLastValue(communalSceneInteractor.currentScene)

                communalSceneInteractor.changeScene(CommunalScenes.Communal)
                Truth.assertThat(scene).isEqualTo(CommunalScenes.Communal)
                communalSceneInteractor.setIsLaunchingWidget(true)
                assertTrue(launching!!)

                underTest.onIntentStarted(willAnimate = true)
                assertTrue(launching!!)
                verify(controller).onIntentStarted(willAnimate = true)

                underTest.onTransitionAnimationCancelled(newKeyguardOccludedState = true)
                assertFalse(launching!!)
                Truth.assertThat(scene).isEqualTo(CommunalScenes.Communal)
                verify(controller).onTransitionAnimationCancelled(newKeyguardOccludedState = true)
            }
        }
    }

    @Test
    fun animationComplete_launchingWidgetStateIsClearedAndSceneIsChanged() {
        with(kosmos) {
            testScope.runTest {
                val launching by collectLastValue(communalSceneInteractor.isLaunchingWidget)
                val scene by collectLastValue(communalSceneInteractor.currentScene)

                communalSceneInteractor.changeScene(CommunalScenes.Communal)
                Truth.assertThat(scene).isEqualTo(CommunalScenes.Communal)
                communalSceneInteractor.setIsLaunchingWidget(true)
                assertTrue(launching!!)

                underTest.onIntentStarted(willAnimate = true)
                assertTrue(launching!!)
                verify(controller).onIntentStarted(willAnimate = true)

                underTest.onTransitionAnimationEnd(isExpandingFullyAbove = true)
                assertFalse(launching!!)
                Truth.assertThat(scene).isEqualTo(CommunalScenes.Blank)
                verify(controller).onTransitionAnimationEnd(isExpandingFullyAbove = true)
            }
        }
    }
}
+42 −19
Original line number Diff line number Diff line
@@ -26,13 +26,21 @@ import androidx.core.util.component2
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.testKosmos
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.isNull
import org.mockito.kotlin.mock
import org.mockito.kotlin.notNull
import org.mockito.kotlin.refEq
import org.mockito.kotlin.verify

@@ -40,6 +48,7 @@ import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class WidgetInteractionHandlerTest : SysuiTestCase() {
    private val activityStarter = mock<ActivityStarter>()
    private val kosmos = testKosmos()

    private val testIntent =
        PendingIntent.getActivity(
@@ -50,12 +59,22 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
        )
    private val testResponse = RemoteResponse.fromPendingIntent(testIntent)

    private val underTest: WidgetInteractionHandler by lazy {
        WidgetInteractionHandler(activityStarter)
    private lateinit var underTest: WidgetInteractionHandler

    @Before
    fun setUp() {
        with(kosmos) {
            underTest = WidgetInteractionHandler(activityStarter, communalSceneInteractor)
        }
    }

    @Test
    fun launchAnimatorIsUsedForWidgetView() {
        with(kosmos) {
            testScope.runTest {
                val launching by collectLastValue(communalSceneInteractor.isLaunchingWidget)
                assertFalse(launching!!)

                val parent = FrameLayout(context)
                val view = CommunalAppWidgetHostView(context)
                parent.addView(view)
@@ -63,18 +82,22 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {

                underTest.onInteraction(view, testIntent, testResponse)

        // Verify that we pass in a non-null animation controller
                // Verify that we set the state correctly
                assertTrue(launching!!)
                // Verify that we pass in a non-null Communal animation controller
                verify(activityStarter)
                    .startPendingIntentMaybeDismissingKeyguard(
                        /* intent = */ eq(testIntent),
                        /* dismissShade = */ eq(false),
                        /* intentSentUiThreadCallback = */ isNull(),
                /* animationController = */ notNull(),
                        /* animationController = */ any<CommunalTransitionAnimatorController>(),
                        /* fillInIntent = */ refEq(fillInIntent),
                        /* extraOptions = */ refEq(activityOptions.toBundle()),
                        /* customMessage */ isNull(),
                    )
            }
        }
    }

    @Test
    fun launchAnimatorIsNotUsedForRegularView() {
+99 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.assist.AssistManager
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.data.repository.FakeShadeRepository
@@ -136,7 +137,9 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
                communalSceneInteractor = communalSceneInteractor,
            )
        `when`(userTracker.userHandle).thenReturn(UserHandle.OWNER)
        `when`(communalSceneInteractor.isCommunalVisible).thenReturn(MutableStateFlow(false))
        `when`(communalSceneInteractor.isIdleOnCommunal).thenReturn(MutableStateFlow(false))
        `when`(communalSceneInteractor.isLaunchingWidget).thenReturn(MutableStateFlow(false))
    }

    @Test
@@ -335,6 +338,102 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            )
    }

    @EnableFlags(Flags.FLAG_COMMUNAL_HUB)
    @Test
    fun startPendingIntentDismissingKeyguard_transitionAnimator_animateCommunal() {
        val parent = FrameLayout(context)
        val view =
            object : View(context), LaunchableView {
                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
            }
        parent.addView(view)
        val controller = ActivityTransitionAnimator.Controller.fromView(view)
        val pendingIntent = mock(PendingIntent::class.java)
        `when`(pendingIntent.isActivity).thenReturn(true)
        `when`(keyguardStateController.isShowing).thenReturn(true)
        `when`(keyguardStateController.isOccluded).thenReturn(true)
        `when`(communalSceneInteractor.isCommunalVisible).thenReturn(MutableStateFlow(true))
        `when`(communalSceneInteractor.isLaunchingWidget).thenReturn(MutableStateFlow(true))
        `when`(activityIntentHelper.wouldPendingLaunchResolverActivity(eq(pendingIntent), anyInt()))
            .thenReturn(false)
        `when`(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
            .thenReturn(false)

        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = false,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = false
        )
        mainExecutor.runAllReady()

        val actionCaptor = argumentCaptor<OnDismissAction>()
        verify(statusBarKeyguardViewManager)
            .dismissWithAction(actionCaptor.capture(), eq(null), anyBoolean(), eq(null))
        actionCaptor.firstValue.onDismiss()
        mainExecutor.runAllReady()

        verify(activityTransitionAnimator)
            .startPendingIntentWithAnimation(
                nullable(ActivityTransitionAnimator.Controller::class.java),
                eq(true),
                nullable(String::class.java),
                eq(false),
                any(),
            )
    }

    @DisableFlags(Flags.FLAG_COMMUNAL_HUB)
    @Test
    fun startPendingIntentDismissingKeyguard_transitionAnimator_doNotAnimateCommunal() {
        val parent = FrameLayout(context)
        val view =
            object : View(context), LaunchableView {
                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
            }
        parent.addView(view)
        val controller = ActivityTransitionAnimator.Controller.fromView(view)
        val pendingIntent = mock(PendingIntent::class.java)
        `when`(pendingIntent.isActivity).thenReturn(true)
        `when`(keyguardStateController.isShowing).thenReturn(true)
        `when`(keyguardStateController.isOccluded).thenReturn(true)
        `when`(communalSceneInteractor.isCommunalVisible).thenReturn(MutableStateFlow(true))
        `when`(communalSceneInteractor.isLaunchingWidget).thenReturn(MutableStateFlow(true))
        `when`(activityIntentHelper.wouldPendingLaunchResolverActivity(eq(pendingIntent), anyInt()))
            .thenReturn(false)
        `when`(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
            .thenReturn(false)

        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = false,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = false
        )
        mainExecutor.runAllReady()

        val actionCaptor = argumentCaptor<OnDismissAction>()
        verify(statusBarKeyguardViewManager)
            .dismissWithAction(actionCaptor.capture(), eq(null), anyBoolean(), eq(null))
        actionCaptor.firstValue.onDismiss()
        mainExecutor.runAllReady()

        val runnableCaptor = argumentCaptor<Runnable>()
        verify(statusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(runnableCaptor.capture())
        runnableCaptor.firstValue.run()

        verify(activityTransitionAnimator)
            .startPendingIntentWithAnimation(
                nullable(ActivityTransitionAnimator.Controller::class.java),
                eq(false),
                nullable(String::class.java),
                eq(false),
                any(),
            )
    }

    @Test
    fun startActivity_noUserHandleProvided_getUserHandle() {
        val intent = mock(Intent::class.java)
Loading