diff options
| author | 2024-06-13 13:59:36 +0000 | |
|---|---|---|
| committer | 2024-06-13 13:59:36 +0000 | |
| commit | 36bb29c65fae38a2d93deabe16d13610f2f0cd55 (patch) | |
| tree | 79099bec061cb0e9a90cb154c6c7647c5248756d | |
| parent | 6be460678ed519259e84f61a717edbbdac4f13ef (diff) | |
| parent | 6fe1e9466aac1536e7ae4fa48d2a988ab646fbb2 (diff) | |
Merge "Fix live timer activity launches" into main
13 files changed, 298 insertions, 62 deletions
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index c61f996ae7cf..1cbf67ee0d0e 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1048,15 +1048,6 @@ 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" diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index b353b5adec4e..18085ab29135 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -25,9 +25,9 @@ import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope import com.android.compose.theme.LocalAndroidColorScheme +import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection 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 @@ -38,7 +38,7 @@ class CommunalContent @Inject constructor( private val viewModel: CommunalViewModel, - private val interactionHandler: WidgetInteractionHandler, + private val interactionHandler: SmartspaceInteractionHandler, private val dialogFactory: SystemUIDialogFactory, private val lockSection: LockSection, private val ambientStatusBarSection: AmbientStatusBarSection, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index a1899fd8dc2e..927890e9d6af 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -135,7 +135,6 @@ 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 @@ -1209,9 +1208,7 @@ private fun SmartspaceContent( modifier = modifier, factory = { context -> SmartspaceAppWidgetHostView(context).apply { - if (glanceableHubAnimateTimerActivityStarts()) { - interactionHandler?.let { setInteractionHandler(it) } - } + interactionHandler?.let { setInteractionHandler(it) } updateAppWidget(model.remoteViews) } }, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/smartspace/SmartspaceInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/smartspace/SmartspaceInteractionHandlerTest.kt new file mode 100644 index 000000000000..9e24ef840a5b --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/smartspace/SmartspaceInteractionHandlerTest.kt @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package com.android.systemui.communal.smartspace + +import android.app.PendingIntent +import android.content.Intent +import android.view.View +import android.widget.FrameLayout +import android.widget.RemoteViews.RemoteResponse +import androidx.core.util.component1 +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.widgets.SmartspaceAppWidgetHostView +import com.android.systemui.plugins.ActivityStarter +import org.junit.Test +import org.junit.runner.RunWith +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 SmartspaceInteractionHandlerTest : SysuiTestCase() { + private val activityStarter = mock<ActivityStarter>() + + private val testIntent = + PendingIntent.getActivity( + context, + /* requestCode = */ 0, + Intent("action"), + PendingIntent.FLAG_IMMUTABLE + ) + private val testResponse = RemoteResponse.fromPendingIntent(testIntent) + + private val underTest: SmartspaceInteractionHandler by lazy { + SmartspaceInteractionHandler(activityStarter) + } + + @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) + .startPendingIntentWithoutDismissing( + eq(testIntent), + eq(false), + isNull(), + notNull(), + refEq(fillInIntent), + refEq(activityOptions.toBundle()), + ) + } + + @Test + fun launchAnimatorIsNotUsedForRegularView() { + val parent = FrameLayout(context) + val view = View(context) + parent.addView(view) + val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view) + + underTest.onInteraction(view, testIntent, testResponse) + + verify(activityStarter) + .startPendingIntentWithoutDismissing( + eq(testIntent), + eq(false), + isNull(), + isNull(), + refEq(fillInIntent), + refEq(activityOptions.toBundle()), + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt index df7b291c4bab..bf6a2b084a9b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt @@ -75,26 +75,6 @@ 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) val view = View(context) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index de659315e176..7cf56aa5c40e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -58,6 +58,19 @@ public interface ActivityStarter { @Nullable ActivityTransitionAnimator.Controller animationController); /** + * Similar to {@link #startPendingIntentMaybeDismissingKeyguard(PendingIntent, Runnable, + * ActivityTransitionAnimator.Controller)} but will always not dismiss the keyguard when + * launching activities. This should be avoided and other alternatives should be used. + */ + void startPendingIntentWithoutDismissing( + PendingIntent intent, + boolean dismissShade, + Runnable intentSentUiThreadCallback, + @Nullable ActivityTransitionAnimator.Controller animationController, + @Nullable Intent fillInIntent, + @Nullable Bundle extraOptions); + + /** * Similar to {@link #startPendingIntentDismissingKeyguard}, except that it supports launching * activities on top of the keyguard. If the activity supports {@code showOverLockscreen}, it * will show over keyguard without first dimissing it. If it doesn't support it, calling this diff --git a/packages/SystemUI/src/com/android/systemui/communal/smartspace/SmartspaceInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/smartspace/SmartspaceInteractionHandler.kt new file mode 100644 index 000000000000..a88b777be785 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/smartspace/SmartspaceInteractionHandler.kt @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package com.android.systemui.communal.smartspace + +import android.app.ActivityOptions +import android.app.PendingIntent +import android.content.Intent +import android.view.View +import android.widget.RemoteViews +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.communal.util.InteractionHandlerDelegate +import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView +import com.android.systemui.plugins.ActivityStarter +import javax.inject.Inject + +/** + * Handles interactions on smartspace elements on the hub. + */ +class SmartspaceInteractionHandler @Inject constructor( + private val activityStarter: ActivityStarter, +) : RemoteViews.InteractionHandler { + private val delegate = InteractionHandlerDelegate( + findViewToAnimate = { view -> view is SmartspaceAppWidgetHostView }, + intentStarter = this::startIntent, + ) + + override fun onInteraction( + view: View, + pendingIntent: PendingIntent, + response: RemoteViews.RemoteResponse + ): Boolean = delegate.onInteraction(view, pendingIntent, response) + + private fun startIntent( + pendingIntent: PendingIntent, + fillInIntent: Intent, + extraOptions: ActivityOptions, + animationController: ActivityTransitionAnimator.Controller? + ): Boolean { + activityStarter.startPendingIntentWithoutDismissing( + pendingIntent, + /* dismissShade = */ false, + /* intentSentUiThreadCallback = */ null, + animationController, + fillInIntent, + extraOptions.toBundle() + ) + return true + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/InteractionHandlerDelegate.kt b/packages/SystemUI/src/com/android/systemui/communal/util/InteractionHandlerDelegate.kt new file mode 100644 index 000000000000..40b182dba817 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/util/InteractionHandlerDelegate.kt @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package com.android.systemui.communal.util + +import android.app.ActivityOptions +import android.app.PendingIntent +import android.content.Intent +import android.view.View +import android.widget.RemoteViews +import androidx.core.util.component1 +import androidx.core.util.component2 +import com.android.systemui.animation.ActivityTransitionAnimator + + +/** A delegate that can be used to launch activities from [RemoteViews] */ +class InteractionHandlerDelegate( + private val findViewToAnimate: (View) -> Boolean, + private val intentStarter: IntentStarter, +) : RemoteViews.InteractionHandler { + + /** + * Responsible for starting the pending intent for launching activities. + */ + fun interface IntentStarter { + fun startPendingIntent( + intent: PendingIntent, + fillInIntent: Intent, + activityOptions: ActivityOptions, + controller: ActivityTransitionAnimator.Controller?, + ): Boolean + } + + override fun onInteraction( + view: View, + pendingIntent: PendingIntent, + response: RemoteViews.RemoteResponse + ): Boolean { + val launchOptions = response.getLaunchOptions(view) + return when { + pendingIntent.isActivity -> { + // Forward the fill-in intent and activity options retrieved from the response + // to populate the pending intent, so that list items can launch respective + // activities. + val hostView = getNearestParent(view) + val animationController = + hostView?.let(ActivityTransitionAnimator.Controller::fromView) + val (fillInIntent, activityOptions) = launchOptions + intentStarter.startPendingIntent( + pendingIntent, + fillInIntent, + activityOptions, + animationController + ) + } + + else -> RemoteViews.startPendingIntent(view, pendingIntent, launchOptions) + } + } + + private fun getNearestParent(child: View): View? { + var view: Any? = child + while (view is View) { + if (findViewToAnimate(view)) return view + view = view.parent + } + return null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt index e88a8b5b7cdb..cbc6c977e3e6 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt @@ -18,15 +18,11 @@ package com.android.systemui.communal.widgets import android.app.ActivityOptions import android.app.PendingIntent -import android.appwidget.AppWidgetHostView import android.content.Intent -import android.util.Pair import android.view.View import android.widget.RemoteViews -import androidx.core.util.component1 -import androidx.core.util.component2 import com.android.systemui.animation.ActivityTransitionAnimator -import com.android.systemui.common.ui.view.getNearestParent +import com.android.systemui.communal.util.InteractionHandlerDelegate import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.ActivityStarter import javax.inject.Inject @@ -37,38 +33,32 @@ class WidgetInteractionHandler constructor( private val activityStarter: ActivityStarter, ) : RemoteViews.InteractionHandler { + + private val delegate = InteractionHandlerDelegate( + findViewToAnimate = { view -> view is CommunalAppWidgetHostView }, + intentStarter = this::startIntent, + ) + override fun onInteraction( view: View, pendingIntent: PendingIntent, response: RemoteViews.RemoteResponse - ): Boolean { - val launchOptions = response.getLaunchOptions(view) - return when { - pendingIntent.isActivity -> - // Forward the fill-in intent and activity options retrieved from the response - // to populate the pending intent, so that list items can launch respective - // activities. - startActivity(view, pendingIntent, launchOptions) - else -> RemoteViews.startPendingIntent(view, pendingIntent, launchOptions) - } - } + ): Boolean = delegate.onInteraction(view, pendingIntent, response) - private fun startActivity( - view: View, + + private fun startIntent( pendingIntent: PendingIntent, - launchOptions: Pair<Intent, ActivityOptions>, + fillInIntent: Intent, + extraOptions: ActivityOptions, + controller: ActivityTransitionAnimator.Controller? ): Boolean { - val hostView = view.getNearestParent<AppWidgetHostView>() - val animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView) - val (fillInIntent, activityOptions) = launchOptions - activityStarter.startPendingIntentMaybeDismissingKeyguard( pendingIntent, /* dismissShade = */ false, /* intentSentUiThreadCallback = */ null, - animationController, + controller, fillInIntent, - activityOptions.toBundle(), + extraOptions.toBundle(), ) return true } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt index 2ab7aa95ff56..fae0a4681493 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt @@ -85,6 +85,26 @@ constructor( ) } + override fun startPendingIntentWithoutDismissing( + intent: PendingIntent, + dismissShade: Boolean, + intentSentUiThreadCallback: Runnable?, + animationController: ActivityTransitionAnimator.Controller?, + fillInIntent: Intent?, + extraOptions: Bundle? + ) { + activityStarterInternal.startPendingIntentDismissingKeyguard( + intent = intent, + intentSentUiThreadCallback = intentSentUiThreadCallback, + animationController = animationController, + showOverLockscreen = true, + skipLockscreenChecks = true, + dismissShade = dismissShade, + fillInIntent = fillInIntent, + extraOptions = extraOptions, + ) + } + override fun startPendingIntentMaybeDismissingKeyguard( intent: PendingIntent, intentSentUiThreadCallback: Runnable?, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt index c9becb4289b9..cff9f5edad08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt @@ -39,6 +39,7 @@ interface ActivityStarterInternal { associatedView: View? = null, animationController: ActivityTransitionAnimator.Controller? = null, showOverLockscreen: Boolean = false, + skipLockscreenChecks: Boolean = false, fillInIntent: Intent? = null, extraOptions: Bundle? = null, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt index e580f6458be8..dbb95e602e43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt @@ -40,6 +40,7 @@ class ActivityStarterInternalImpl @Inject constructor() : ActivityStarterInterna associatedView: View?, animationController: ActivityTransitionAnimator.Controller?, showOverLockscreen: Boolean, + skipLockscreenChecks: Boolean, fillInIntent: Intent?, extraOptions: Bundle? ) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt index 800d7fda5b98..e400ab685d8e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt @@ -228,6 +228,7 @@ constructor( associatedView: View?, animationController: ActivityTransitionAnimator.Controller?, showOverLockscreen: Boolean, + skipLockscreenChecks: Boolean, fillInIntent: Intent?, extraOptions: Bundle?, ) { @@ -246,10 +247,10 @@ constructor( val actuallyShowOverLockscreen = showOverLockscreen && intent.isActivity && - activityIntentHelper.wouldPendingShowOverLockscreen( + (skipLockscreenChecks || activityIntentHelper.wouldPendingShowOverLockscreen( intent, lockScreenUserManager.currentUserId - ) + )) val animate = !willLaunchResolverActivity && |