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

Commit 67fd82b2 authored by Coco Duan's avatar Coco Duan
Browse files

Fix activity start on clicking Glance widget from GH

Activites failed to launch when clicking on Glance widget lazy list
because pending intent template is not filled in when calling
`startPendingIntentMaybeDismissingKeyguard`.
The fix is to refactor `startPendingIntentDismissingKeyguard` to accept
the extra params so that the the fill-in intent is set when calling
`PendingIntent#sendAndReturnResult`.

Bug: b/324062788
Test: atest ActivityStarterImplTest
Test: verfied app opened on clicking News, Finance and TV after keyguard is dismissed
Flag: ACONFIG com.android.systemui.communal_hub TEAMFOOD
Change-Id: Ib4bc1dde62a3837b9747b7c4e9c40b17c1fe4b5e
parent 25530406
Loading
Loading
Loading
Loading
+14 −1
Original line number Original line Diff line number Diff line
@@ -21,6 +21,8 @@ import android.content.Intent
import android.view.View
import android.view.View
import android.widget.FrameLayout
import android.widget.FrameLayout
import android.widget.RemoteViews.RemoteResponse
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.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
@@ -29,6 +31,7 @@ import com.android.systemui.util.mockito.eq
import org.junit.Before
import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.refEq
import org.mockito.Mock
import org.mockito.Mock
import org.mockito.Mockito.isNull
import org.mockito.Mockito.isNull
import org.mockito.Mockito.notNull
import org.mockito.Mockito.notNull
@@ -62,6 +65,7 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
        val parent = FrameLayout(context)
        val parent = FrameLayout(context)
        val view = CommunalAppWidgetHostView(context)
        val view = CommunalAppWidgetHostView(context)
        parent.addView(view)
        parent.addView(view)
        val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)


        underTest.onInteraction(view, testIntent, testResponse)
        underTest.onInteraction(view, testIntent, testResponse)


@@ -70,6 +74,8 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
                eq(testIntent),
                eq(testIntent),
                isNull(),
                isNull(),
                notNull(),
                notNull(),
                refEq(fillInIntent),
                refEq(activityOptions.toBundle()),
            )
            )
    }
    }


@@ -78,10 +84,17 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
        val parent = FrameLayout(context)
        val parent = FrameLayout(context)
        val view = View(context)
        val view = View(context)
        parent.addView(view)
        parent.addView(view)
        val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)


        underTest.onInteraction(view, testIntent, testResponse)
        underTest.onInteraction(view, testIntent, testResponse)


        verify(activityStarter)
        verify(activityStarter)
            .startPendingIntentMaybeDismissingKeyguard(eq(testIntent), isNull(), isNull())
            .startPendingIntentMaybeDismissingKeyguard(
                eq(testIntent),
                isNull(),
                isNull(),
                refEq(fillInIntent),
                refEq(activityOptions.toBundle()),
            )
    }
    }
}
}
+51 −0
Original line number Original line Diff line number Diff line
@@ -16,12 +16,15 @@


package com.android.systemui.statusbar.phone
package com.android.systemui.statusbar.phone


import android.app.ActivityOptions
import android.app.PendingIntent
import android.app.PendingIntent
import android.content.Intent
import android.content.Intent
import android.os.Bundle
import android.os.RemoteException
import android.os.RemoteException
import android.os.UserHandle
import android.os.UserHandle
import android.view.View
import android.view.View
import android.widget.FrameLayout
import android.widget.FrameLayout
import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitor
@@ -48,6 +51,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.whenever
@@ -173,6 +177,53 @@ class ActivityStarterImplTest : SysuiTestCase() {
            )
            )
    }
    }


    fun startPendingIntentDismissingKeyguard_fillInIntentAndExtraOptions_sendAndReturnResult() {
        val pendingIntent = mock(PendingIntent::class.java)
        val fillInIntent = mock(Intent::class.java)
        val parent = FrameLayout(context)
        val view =
            object : View(context), LaunchableView {
                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
            }
        parent.addView(view)
        val controller = ActivityTransitionAnimator.Controller.fromView(view)
        whenever(pendingIntent.isActivity).thenReturn(true)
        whenever(keyguardStateController.isShowing).thenReturn(true)
        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
            .thenReturn(false)

        // extra activity options to set on pending intent
        val activityOptions = mock(ActivityOptions::class.java)
        activityOptions.splashScreenStyle = SPLASH_SCREEN_STYLE_SOLID_COLOR
        activityOptions.isPendingIntentBackgroundActivityLaunchAllowedByPermission = false
        val bundleCaptor = argumentCaptor<Bundle>()

        underTest.startPendingIntentMaybeDismissingKeyguard(
            intent = pendingIntent,
            animationController = controller,
            intentSentUiThreadCallback = null,
            fillInIntent = fillInIntent,
            extraOptions = activityOptions.toBundle(),
        )
        mainExecutor.runAllReady()

        // Fill-in intent is passed and options contain extra values specified
        verify(pendingIntent)
            .sendAndReturnResult(
                eq(context),
                eq(0),
                eq(fillInIntent),
                nullable(),
                nullable(),
                nullable(),
                bundleCaptor.capture()
            )
        val options = ActivityOptions.fromBundle(bundleCaptor.value)
        assertThat(options.isPendingIntentBackgroundActivityLaunchAllowedByPermission).isFalse()
        assertThat(options.splashScreenStyle).isEqualTo(SPLASH_SCREEN_STYLE_SOLID_COLOR)
    }

    @Test
    @Test
    fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
    fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
        val pendingIntent = mock(PendingIntent::class.java)
        val pendingIntent = mock(PendingIntent::class.java)
+12 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.systemui.plugins;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserHandle;
import android.view.View;
import android.view.View;


@@ -66,6 +67,17 @@ public interface ActivityStarter {
            @Nullable Runnable intentSentUiThreadCallback,
            @Nullable Runnable intentSentUiThreadCallback,
            @Nullable ActivityTransitionAnimator.Controller animationController);
            @Nullable ActivityTransitionAnimator.Controller animationController);


    /**
     * Similar to {@link #startPendingIntentMaybeDismissingKeyguard(PendingIntent, Runnable,
     * ActivityTransitionAnimator.Controller)}, but also specifies a fill-in intent and extra
     * options that could be used to populate the pending intent and launch the activity.
     */
    void startPendingIntentMaybeDismissingKeyguard(PendingIntent intent,
            @Nullable Runnable intentSentUiThreadCallback,
            @Nullable ActivityTransitionAnimator.Controller animationController,
            @Nullable Intent fillInIntent,
            @Nullable Bundle extraOptions);

    /**
    /**
     * The intent flag can be specified in startActivity().
     * The intent flag can be specified in startActivity().
     */
     */
+24 −7
Original line number Original line Diff line number Diff line
@@ -16,9 +16,14 @@


package com.android.systemui.communal.widgets
package com.android.systemui.communal.widgets


import android.app.ActivityOptions
import android.app.PendingIntent
import android.app.PendingIntent
import android.content.Intent
import android.util.Pair
import android.view.View
import android.view.View
import android.widget.RemoteViews
import android.widget.RemoteViews
import androidx.core.util.component1
import androidx.core.util.component2
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.common.ui.view.getNearestParent
import com.android.systemui.common.ui.view.getNearestParent
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.ActivityStarter
@@ -33,21 +38,33 @@ constructor(
        view: View,
        view: View,
        pendingIntent: PendingIntent,
        pendingIntent: PendingIntent,
        response: RemoteViews.RemoteResponse
        response: RemoteViews.RemoteResponse
    ): Boolean =
    ): Boolean {
        when {
        val launchOptions = response.getLaunchOptions(view)
            pendingIntent.isActivity -> startActivity(view, pendingIntent)
        return when {
            else ->
            pendingIntent.isActivity ->
                RemoteViews.startPendingIntent(view, pendingIntent, response.getLaunchOptions(view))
                // 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)
        }
    }
    }


    private fun startActivity(view: View, pendingIntent: PendingIntent): Boolean {
    private fun startActivity(
        view: View,
        pendingIntent: PendingIntent,
        launchOptions: Pair<Intent, ActivityOptions>,
    ): Boolean {
        val hostView = view.getNearestParent<CommunalAppWidgetHostView>()
        val hostView = view.getNearestParent<CommunalAppWidgetHostView>()
        val animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView)
        val animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView)
        val (fillInIntent, activityOptions) = launchOptions


        activityStarter.startPendingIntentMaybeDismissingKeyguard(
        activityStarter.startPendingIntentMaybeDismissingKeyguard(
            pendingIntent,
            pendingIntent,
            /* intentSentUiThreadCallback = */ null,
            /* intentSentUiThreadCallback = */ null,
            animationController
            animationController,
            fillInIntent,
            activityOptions.toBundle(),
        )
        )
        return true
        return true
    }
    }
+26 −5
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.app.TaskStackBuilder
import android.content.Context
import android.content.Context
import android.content.Intent
import android.content.Intent
import android.os.Bundle
import android.os.RemoteException
import android.os.RemoteException
import android.os.UserHandle
import android.os.UserHandle
import android.provider.Settings
import android.provider.Settings
@@ -149,6 +150,23 @@ constructor(
        )
        )
    }
    }


    override fun startPendingIntentMaybeDismissingKeyguard(
        intent: PendingIntent,
        intentSentUiThreadCallback: Runnable?,
        animationController: ActivityTransitionAnimator.Controller?,
        fillInIntent: Intent?,
        extraOptions: Bundle?,
    ) {
        activityStarterInternal.startPendingIntentDismissingKeyguard(
            intent = intent,
            intentSentUiThreadCallback = intentSentUiThreadCallback,
            animationController = animationController,
            showOverLockscreen = true,
            fillInIntent = fillInIntent,
            extraOptions = extraOptions,
        )
    }

    /**
    /**
     * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
     * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
     *   this.
     *   this.
@@ -554,6 +572,8 @@ constructor(
            associatedView: View? = null,
            associatedView: View? = null,
            animationController: ActivityTransitionAnimator.Controller? = null,
            animationController: ActivityTransitionAnimator.Controller? = null,
            showOverLockscreen: Boolean = false,
            showOverLockscreen: Boolean = false,
            fillInIntent: Intent? = null,
            extraOptions: Bundle? = null,
        ) {
        ) {
            val animationController =
            val animationController =
                if (associatedView is ExpandableNotificationRow) {
                if (associatedView is ExpandableNotificationRow) {
@@ -617,6 +637,7 @@ constructor(
                                                displayId,
                                                displayId,
                                                animationAdapter
                                                animationAdapter
                                            )
                                            )
                                            .apply { extraOptions?.let { putAll(it) } }
                                    )
                                    )
                                // TODO b/221255671: restrict this to only be set for
                                // TODO b/221255671: restrict this to only be set for
                                // notifications
                                // notifications
@@ -625,9 +646,9 @@ constructor(
                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
                                )
                                )
                                return intent.sendAndReturnResult(
                                return intent.sendAndReturnResult(
                                    null,
                                    context,
                                    0,
                                    0,
                                    null,
                                    fillInIntent,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,