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

Commit fdbf8c14 authored by Coco Duan's avatar Coco Duan Committed by Android (Google) Code Review
Browse files

Merge "Fix activity start on clicking Glance widget from GH" into main

parents 904159a4 67fd82b2
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ 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
@@ -29,6 +31,7 @@ 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
@@ -62,6 +65,7 @@ class WidgetInteractionHandlerTest : SysuiTestCase() {
        val parent = FrameLayout(context)
        val view = CommunalAppWidgetHostView(context)
        parent.addView(view)
        val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)

        underTest.onInteraction(view, testIntent, testResponse)

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

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

        underTest.onInteraction(view, testIntent, testResponse)

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

package com.android.systemui.statusbar.phone

import android.app.ActivityOptions
import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import android.os.RemoteException
import android.os.UserHandle
import android.view.View
import android.widget.FrameLayout
import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
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.util.concurrency.FakeExecutor
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.nullable
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
    fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
        val pendingIntent = mock(PendingIntent::class.java)
+12 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.systemui.plugins;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.View;

@@ -66,6 +67,17 @@ public interface ActivityStarter {
            @Nullable Runnable intentSentUiThreadCallback,
            @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().
     */
+24 −7
Original line number Diff line number Diff line
@@ -16,9 +16,14 @@

package com.android.systemui.communal.widgets

import android.app.ActivityOptions
import android.app.PendingIntent
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.plugins.ActivityStarter
@@ -33,21 +38,33 @@ constructor(
        view: View,
        pendingIntent: PendingIntent,
        response: RemoteViews.RemoteResponse
    ): Boolean =
        when {
            pendingIntent.isActivity -> startActivity(view, pendingIntent)
            else ->
                RemoteViews.startPendingIntent(view, pendingIntent, response.getLaunchOptions(view))
    ): 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)
        }
    }

    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 animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView)
        val (fillInIntent, activityOptions) = launchOptions

        activityStarter.startPendingIntentMaybeDismissingKeyguard(
            pendingIntent,
            /* intentSentUiThreadCallback = */ null,
            animationController
            animationController,
            fillInIntent,
            activityOptions.toBundle(),
        )
        return true
    }
+26 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.RemoteException
import android.os.UserHandle
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
     *   this.
@@ -554,6 +572,8 @@ constructor(
            associatedView: View? = null,
            animationController: ActivityTransitionAnimator.Controller? = null,
            showOverLockscreen: Boolean = false,
            fillInIntent: Intent? = null,
            extraOptions: Bundle? = null,
        ) {
            val animationController =
                if (associatedView is ExpandableNotificationRow) {
@@ -617,6 +637,7 @@ constructor(
                                                displayId,
                                                animationAdapter
                                            )
                                            .apply { extraOptions?.let { putAll(it) } }
                                    )
                                // TODO b/221255671: restrict this to only be set for
                                // notifications
@@ -625,9 +646,9 @@ constructor(
                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
                                )
                                return intent.sendAndReturnResult(
                                    null,
                                    context,
                                    0,
                                    null,
                                    fillInIntent,
                                    null,
                                    null,
                                    null,