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

Commit e60d775d authored by Lucas Silva's avatar Lucas Silva
Browse files

Implement activity launch animations for live timers

We currently don't have any special handling for activity launches done
by live timers. This change wraps live timers in the same logic used to
handle intents from widgets.

However, this doesn't currently work as the intent triggered by live
timers today goes to a trampoline activity which isn't showWhenLocked.
Therefore this change causes the bouncer to trigger.

Bug: 345741071
Test: atest WidgetInteractionHandlerTest
Flag: com.android.systemui.glanceable_hub_animate_timer_activity_starts
Change-Id: I20db2561fc72e661ec6b7e99cdc192827e8ce431
parent 8e703eb3
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1038,6 +1038,16 @@ flag {
  bug: "343505271"
}

flag {
  name: "glanceable_hub_animate_timer_activity_starts"
  namespace: "systemui"
  description: "Properly animates activity starts from live timers on the glanceable hub"
  bug: "345741071"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "new_touchpad_gestures_tutorial"
  namespace: "systemui"
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -34,6 +35,7 @@ class CommunalContent
@Inject
constructor(
    private val viewModel: CommunalViewModel,
    private val interactionHandler: WidgetInteractionHandler,
    private val dialogFactory: SystemUIDialogFactory,
    private val lockSection: LockSection,
) {
@@ -45,6 +47,7 @@ constructor(
            content = {
                CommunalHub(
                    viewModel = viewModel,
                    interactionHandler = interactionHandler,
                    dialogFactory = dialogFactory,
                    modifier = Modifier.element(Communal.Elements.Grid)
                )
+19 −5
Original line number Diff line number Diff line
@@ -16,13 +16,13 @@

package com.android.systemui.communal.ui.compose

import android.appwidget.AppWidgetHostView
import android.graphics.drawable.Icon
import android.os.Bundle
import android.util.SizeF
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
import android.widget.FrameLayout
import android.widget.RemoteViews
import androidx.annotation.VisibleForTesting
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
@@ -132,6 +132,7 @@ import com.android.compose.modifiers.thenIf
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.internal.R.dimen.system_app_widget_background_radius
import com.android.systemui.Flags.glanceableHubAnimateTimerActivityStarts
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -144,6 +145,7 @@ import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.PopupType
import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -154,6 +156,7 @@ import kotlinx.coroutines.launch
fun CommunalHub(
    modifier: Modifier = Modifier,
    viewModel: BaseCommunalViewModel,
    interactionHandler: RemoteViews.InteractionHandler? = null,
    dialogFactory: SystemUIDialogFactory? = null,
    widgetConfigurator: WidgetConfigurator? = null,
    onOpenWidgetPicker: (() -> Unit)? = null,
@@ -262,6 +265,7 @@ fun CommunalHub(
                    contentListState = contentListState,
                    selectedKey = selectedKey,
                    widgetConfigurator = widgetConfigurator,
                    interactionHandler = interactionHandler,
                )
            }
        }
@@ -391,6 +395,7 @@ private fun BoxScope.CommunalHubLazyGrid(
    setGridCoordinates: (coordinates: LayoutCoordinates) -> Unit,
    updateDragPositionForRemove: (offset: Offset) -> Boolean,
    widgetConfigurator: WidgetConfigurator?,
    interactionHandler: RemoteViews.InteractionHandler?,
) {
    var gridModifier =
        Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
@@ -468,7 +473,8 @@ private fun BoxScope.CommunalHubLazyGrid(
                        selected = selected && !isDragging,
                        widgetConfigurator = widgetConfigurator,
                        index = index,
                        contentListState = contentListState
                        contentListState = contentListState,
                        interactionHandler = interactionHandler,
                    )
                }
            } else {
@@ -479,7 +485,8 @@ private fun BoxScope.CommunalHubLazyGrid(
                    size = size,
                    selected = false,
                    index = index,
                    contentListState = contentListState
                    contentListState = contentListState,
                    interactionHandler = interactionHandler,
                )
            }
        }
@@ -759,6 +766,7 @@ private fun CommunalContent(
    widgetConfigurator: WidgetConfigurator? = null,
    index: Int,
    contentListState: ContentListState,
    interactionHandler: RemoteViews.InteractionHandler?,
) {
    when (model) {
        is CommunalContentModel.WidgetContent.Widget ->
@@ -778,7 +786,7 @@ private fun CommunalContent(
        is CommunalContentModel.WidgetContent.PendingWidget ->
            PendingWidgetPlaceholder(model, modifier)
        is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier)
        is CommunalContentModel.Smartspace -> SmartspaceContent(model, modifier)
        is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier)
        is CommunalContentModel.Tutorial -> TutorialContent(modifier)
        is CommunalContentModel.Umo -> Umo(viewModel, modifier)
    }
@@ -1091,13 +1099,19 @@ fun PendingWidgetPlaceholder(

@Composable
private fun SmartspaceContent(
    interactionHandler: RemoteViews.InteractionHandler?,
    model: CommunalContentModel.Smartspace,
    modifier: Modifier = Modifier,
) {
    AndroidView(
        modifier = modifier,
        factory = { context ->
            AppWidgetHostView(context).apply { updateAppWidget(model.remoteViews) }
            SmartspaceAppWidgetHostView(context).apply {
                if (glanceableHubAnimateTimerActivityStarts()) {
                    interactionHandler?.let { setInteractionHandler(it) }
                }
                updateAppWidget(model.remoteViews)
            }
        },
        // For reusing composition in lazy lists.
        onReset = {},
+3 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
@@ -40,6 +41,7 @@ class CommunalScene
constructor(
    private val viewModel: CommunalViewModel,
    private val dialogFactory: SystemUIDialogFactory,
    private val interactionHandler: WidgetInteractionHandler,
) : ComposableScene {
    override val key = Scenes.Communal

@@ -53,6 +55,6 @@ constructor(

    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        CommunalHub(modifier, viewModel, dialogFactory)
        CommunalHub(modifier, viewModel, interactionHandler, dialogFactory)
    }
}
+29 −15
Original line number Diff line number Diff line
@@ -27,23 +27,19 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.util.mockito.eq
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.refEq
import org.mockito.Mock
import org.mockito.Mockito.isNull
import org.mockito.Mockito.notNull
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
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

@SmallTest
@RunWith(AndroidJUnit4::class)
class WidgetInteractionHandlerTest : SysuiTestCase() {
    @Mock private lateinit var activityStarter: ActivityStarter

    private lateinit var underTest: WidgetInteractionHandler
    private val activityStarter = mock<ActivityStarter>()

    private val testIntent =
        PendingIntent.getActivity(
@@ -54,10 +50,8 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
        )
    private val testResponse = RemoteResponse.fromPendingIntent(testIntent)

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        underTest = WidgetInteractionHandler(activityStarter)
    private val underTest: WidgetInteractionHandler by lazy {
        WidgetInteractionHandler(activityStarter)
    }

    @Test
@@ -80,6 +74,26 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
            )
    }

    @Test
    fun launchAnimatorIsUsedForSmartspaceView() {
        val parent = FrameLayout(context)
        val view = SmartspaceAppWidgetHostView(context)
        parent.addView(view)
        val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)

        underTest.onInteraction(view, testIntent, testResponse)

        verify(activityStarter)
            .startPendingIntentMaybeDismissingKeyguard(
                eq(testIntent),
                eq(false),
                isNull(),
                notNull(),
                refEq(fillInIntent),
                refEq(activityOptions.toBundle()),
            )
    }

    @Test
    fun launchAnimatorIsNotUsedForRegularView() {
        val parent = FrameLayout(context)
Loading