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

Commit 006d4de0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Apply WCT#setTaskForceExcludedFromRecents for bubble tasks." into main

parents f0354eeb 9fdaf8ed
Loading
Loading
Loading
Loading
+59 −8
Original line number Diff line number Diff line
@@ -18,18 +18,32 @@ package com.android.wm.shell.bubbles

import android.content.ComponentName
import android.content.Context
import android.os.IBinder
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.platform.test.flag.junit.SetFlagsRule
import android.window.IWindowContainerToken
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.SmallTest
import com.android.wm.shell.Flags
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS
import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_TASK_VIEW_LISTENER
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.taskview.TaskView
import com.android.wm.shell.taskview.TaskViewController
import com.android.wm.shell.taskview.TaskViewTaskController
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@@ -44,10 +58,29 @@ class BubbleExpandedViewTest(flags: FlagsParameterization) {
    private val context = ApplicationProvider.getApplicationContext<Context>()
    private val componentName = ComponentName(context, "TestClass")

    @Test
    fun getTaskId_onTaskCreated_returnsCorrectTaskId() {
        val bubbleTaskView = BubbleTaskView(mock<TaskView>(), directExecutor())
        val expandedView = BubbleExpandedView(context).apply {
    private val taskOrganizer = mock<ShellTaskOrganizer>()
    private val taskViewTaskToken = WindowContainerToken(mock<IWindowContainerToken> {
        on { asBinder() } doReturn mock<IBinder>()
    })
    private var taskViewController = mock<TaskViewController>()
    private val taskViewTaskController = mock<TaskViewTaskController> {
        on { taskOrganizer } doReturn taskOrganizer
        on { taskToken } doReturn taskViewTaskToken
    }

    private lateinit var taskView: TaskView
    private lateinit var bubbleTaskView: BubbleTaskView
    private lateinit var expandedView: BubbleExpandedView

    @Before
    fun setUp() {
        ProtoLog.REQUIRE_PROTOLOGTOOL = false
        ProtoLog.init()

        taskView = TaskView(context, taskViewController, taskViewTaskController)
        bubbleTaskView = BubbleTaskView(taskView, directExecutor())

        expandedView = BubbleExpandedView(context).apply {
            initialize(
                mock<BubbleExpandedViewManager>(),
                mock<BubbleStackView>(),
@@ -57,17 +90,35 @@ class BubbleExpandedViewTest(flags: FlagsParameterization) {
            )
            setAnimating(true) // Skips setContentVisibility for testing.
        }
    }

    @Test
    fun getTaskId_onTaskCreated_returnsCorrectTaskId() {
        bubbleTaskView.listener.onTaskCreated(123 /* taskId */, componentName)

        bubbleTaskView.listener.onTaskCreated(123, componentName)
        assertThat(expandedView.taskId).isEqualTo(123)
    }

    @Test
    @EnableFlags(FLAG_EXCLUDE_TASK_FROM_RECENTS)
    fun onTaskCreated_excludesTaskFromRecents() {
        bubbleTaskView.listener.onTaskCreated(123 /* taskId */, componentName)

        assertThat(expandedView.getTaskId()).isEqualTo(123)
        val wctCaptor = argumentCaptor<WindowContainerTransaction>()
        verify(taskOrganizer).applyTransaction(wctCaptor.capture())
        val wct = wctCaptor.lastValue
        assertThat(wct.changes).hasSize(1)
        val chg = wct.changes.get(taskViewTaskToken.asBinder())
        assertThat(chg).isNotNull()
        assertThat(chg!!.forceExcludedFromRecents).isTrue()
    }

    companion object {
        @JvmStatic
        @Parameters(name = "{0}")
        fun getParams() = FlagsParameterization.allCombinationsOf(
            Flags.FLAG_ENABLE_BUBBLE_TASK_VIEW_LISTENER,
            FLAG_ENABLE_BUBBLE_TASK_VIEW_LISTENER,
            FLAG_EXCLUDE_TASK_FROM_RECENTS,
        )
    }
}
+39 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.Context
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.graphics.drawable.Icon
import android.os.IBinder
import android.os.UserHandle
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
@@ -31,13 +32,18 @@ import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.StatusBarNotification
import android.view.View
import android.widget.FrameLayout
import android.window.IWindowContainerToken
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS
import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_ANYTHING
import com.android.wm.shell.R
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener
import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.taskview.TaskView
@@ -72,7 +78,15 @@ class BubbleTaskViewListenerTest {

    private val context = ApplicationProvider.getApplicationContext<Context>()

    private val taskOrganizer = mock<ShellTaskOrganizer>()
    private val taskViewTaskToken = WindowContainerToken(mock<IWindowContainerToken> {
        on { asBinder() } doReturn mock<IBinder>()
    })
    private var taskViewController = mock<TaskViewController>()
    private val taskViewTaskController = mock<TaskViewTaskController> {
        on { taskOrganizer } doReturn taskOrganizer
        on { taskToken } doReturn taskViewTaskToken
    }
    private var listenerCallback = mock<BubbleTaskViewListener.Callback>()
    private var expandedViewManager = mock<BubbleExpandedViewManager>()

@@ -92,7 +106,7 @@ class BubbleTaskViewListenerTest {
        mainExecutor = TestShellExecutor()
        bgExecutor = TestShellExecutor()

        taskView = TaskView(context, taskViewController, mock<TaskViewTaskController>())
        taskView = TaskView(context, taskViewController, taskViewTaskController)
        bubbleTaskView = BubbleTaskView(taskView, mainExecutor)

        bubbleTaskViewListener =
@@ -325,7 +339,6 @@ class BubbleTaskViewListenerTest {
        assertThat(optionsCaptor.lastValue.taskAlwaysOnTop).isTrue()
    }


    @Test
    fun onInitialized_preparingTransition() {
        val b = createAppBubble()
@@ -401,6 +414,30 @@ class BubbleTaskViewListenerTest {
        assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId)
    }

    @Test
    @EnableFlags(FLAG_EXCLUDE_TASK_FROM_RECENTS)
    fun onTaskCreated_excludesTaskFromRecents() {
        val b = createAppBubble()
        bubbleTaskViewListener.setBubble(b)
        getInstrumentation().runOnMainSync {
            bubbleTaskViewListener.onInitialized()
        }
        getInstrumentation().waitForIdleSync()

        getInstrumentation().runOnMainSync {
            bubbleTaskViewListener.onTaskCreated(123 /* taskId */, mock<ComponentName>())
        }
        getInstrumentation().waitForIdleSync()

        val wctCaptor = argumentCaptor<WindowContainerTransaction>()
        verify(taskOrganizer).applyTransaction(wctCaptor.capture())
        val wct = wctCaptor.lastValue
        assertThat(wct.changes).hasSize(1)
        val chg = wct.changes.get(taskViewTaskToken.asBinder())
        assertThat(chg).isNotNull()
        assertThat(chg!!.forceExcludedFromRecents).isTrue()
    }

    @Test
    fun onTaskCreated_noteBubble() {
        val b = createNoteBubble()
+10 −1
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.window.ScreenCapture;
import android.window.WindowContainerTransaction;

import androidx.annotation.Nullable;

@@ -75,6 +76,7 @@ import com.android.wm.shell.shared.TriangleShape;
import com.android.wm.shell.shared.TypefaceUtils;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.taskview.TaskView;
import com.android.wm.shell.taskview.TaskViewTaskController;

import java.io.PrintWriter;

@@ -226,7 +228,7 @@ public class BubbleExpandedView extends LinearLayout {
                    Rect launchBounds = new Rect();
                    mTaskView.getBoundsOnScreen(launchBounds);

                    options.setTaskAlwaysOnTop(true);
                    options.setTaskAlwaysOnTop(true /* alwaysOnTop */);
                    options.setPendingIntentBackgroundActivityStartMode(
                            MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);

@@ -299,6 +301,13 @@ public class BubbleExpandedView extends LinearLayout {
                mManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId);
            }

            if (com.android.window.flags.Flags.excludeTaskFromRecents()) {
                final TaskViewTaskController tvc = mTaskView.getController();
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                wct.setTaskForceExcludedFromRecents(tvc.getTaskToken(), true /* forceExcluded */);
                tvc.getTaskOrganizer().applyTransaction(wct);
            }

            // With the task org, the taskAppeared callback will only happen once the task has
            // already drawn
            setContentVisibility(true);
+10 −1
Original line number Diff line number Diff line
@@ -33,12 +33,14 @@ import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.window.WindowContainerTransaction;

import androidx.annotation.Nullable;

import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.taskview.TaskView;
import com.android.wm.shell.taskview.TaskViewTaskController;

/**
 * A listener that works with task views for bubbles, manages launching the appropriate
@@ -117,7 +119,7 @@ public class BubbleTaskViewListener implements TaskView.Listener {
            ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
                    getBubbleKey());
            try {
                options.setTaskAlwaysOnTop(true);
                options.setTaskAlwaysOnTop(true /* alwaysOnTop */);
                options.setPendingIntentBackgroundActivityStartMode(
                        MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
                final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId()
@@ -194,6 +196,13 @@ public class BubbleTaskViewListener implements TaskView.Listener {
            mExpandedViewManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId);
        }

        if (com.android.window.flags.Flags.excludeTaskFromRecents()) {
            final TaskViewTaskController tvCtrl = mTaskView.getController();
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            wct.setTaskForceExcludedFromRecents(tvCtrl.getTaskToken(), true /* forceExcluded */);
            tvCtrl.getTaskOrganizer().applyTransaction(wct);
        }

        // With the task org, the taskAppeared callback will only happen once the task has
        // already drawn
        mCallback.onTaskCreated();
+19 −10
Original line number Diff line number Diff line
@@ -283,7 +283,7 @@ public class BubbleTransitions {
            }
            final Rect launchBounds = new Rect();
            mLayerView.getExpandedViewRestBounds(launchBounds);
            WindowContainerTransaction wct = new WindowContainerTransaction();
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            mHomeIntentProvider.addLaunchHomePendingIntent(wct, mTaskInfo.displayId,
                    mTaskInfo.userId);

@@ -293,7 +293,10 @@ public class BubbleTransitions {
                }
            }

            wct.setAlwaysOnTop(mTaskInfo.token, true);
            wct.setAlwaysOnTop(mTaskInfo.token, true /* alwaysOnTop */);
            if (com.android.window.flags.Flags.excludeTaskFromRecents()) {
                wct.setTaskForceExcludedFromRecents(mTaskInfo.token, true /* forceExcluded */);
            }
            wct.setWindowingMode(mTaskInfo.token, WINDOWING_MODE_MULTI_WINDOW);
            wct.setBounds(mTaskInfo.token, launchBounds);

@@ -525,11 +528,14 @@ public class BubbleTransitions {
            mTaskInfo = taskInfo;

            mBubble.setPreparingTransition(this);
            WindowContainerTransaction wct = new WindowContainerTransaction();
            WindowContainerToken token = mTaskInfo.getToken();
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            final WindowContainerToken token = mTaskInfo.getToken();
            wct.setWindowingMode(token, WINDOWING_MODE_UNDEFINED);
            wct.setAlwaysOnTop(token, false);
            mTaskOrganizer.setInterceptBackPressedOnTaskRoot(token, false);
            wct.setAlwaysOnTop(token, false /* alwaysOnTop */);
            if (com.android.window.flags.Flags.excludeTaskFromRecents()) {
                wct.setTaskForceExcludedFromRecents(token, false /* forceExcluded */);
            }
            mTaskOrganizer.setInterceptBackPressedOnTaskRoot(token, false /* intercept */);
            mTaskViewTransitions.enqueueExternal(
                    mBubble.getTaskView().getController(),
                    () -> {
@@ -686,13 +692,16 @@ public class BubbleTransitions {
            mDropLocation = dropLocation;
            mTransactionProvider = transactionProvider;
            bubble.setPreparingTransition(this);
            WindowContainerToken token = bubble.getTaskView().getTaskInfo().getToken();
            WindowContainerTransaction wct = new WindowContainerTransaction();
            wct.setAlwaysOnTop(token, false);
            final WindowContainerToken token = bubble.getTaskView().getTaskInfo().getToken();
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            wct.setAlwaysOnTop(token, false /* alwaysOnTop */);
            if (com.android.window.flags.Flags.excludeTaskFromRecents()) {
                wct.setTaskForceExcludedFromRecents(token, false /* forceExcluded */);
            }
            wct.setWindowingMode(token, WINDOWING_MODE_UNDEFINED);
            wct.reorder(token, /* onTop= */ true);
            wct.setHidden(token, false);
            mTaskOrganizer.setInterceptBackPressedOnTaskRoot(token, false);
            mTaskOrganizer.setInterceptBackPressedOnTaskRoot(token, false /* intercept */);
            mTaskViewTransitions.enqueueExternal(bubble.getTaskView().getController(), () -> {
                mTransition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, this);
                return mTransition;
Loading