diff options
14 files changed, 196 insertions, 36 deletions
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_new_window.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_new_window.xml new file mode 100644 index 000000000000..c154059f11a5 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_new_window.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M15 16V14H13V12.5H15V10.5H16.5V12.5H18.5V14H16.5V16H15ZM3.5 17C3.09722 17 2.74306 16.8542 2.4375 16.5625C2.14583 16.2569 2 15.9028 2 15.5V4.5C2 4.08333 2.14583 3.72917 2.4375 3.4375C2.74306 3.14583 3.09722 3 3.5 3H14.5C14.9167 3 15.2708 3.14583 15.5625 3.4375C15.8542 3.72917 16 4.08333 16 4.5V9H14.5V7H3.5V15.5H13.625V17H3.5ZM3.5 5.5H14.5V4.5H3.5V5.5ZM3.5 5.5V4.5V5.5Z" + android:fillColor="#1C1C14"/> +</vector> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index 49d9029f14d6..eea3de8e30ca 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -125,7 +125,7 @@ <LinearLayout android:id="@+id/more_actions_pill" android:layout_width="match_parent" - android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height" + android:layout_height="wrap_content" android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin" android:layout_marginStart="1dp" android:orientation="vertical" @@ -139,6 +139,14 @@ android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot" android:drawableTint="?androidprv:attr/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton"/> + + <Button + android:id="@+id/new_window_button" + android:contentDescription="@string/new_window_text" + android:text="@string/new_window_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_new_window" + android:drawableTint="?androidprv:attr/materialColorOnSurface" + style="@style/DesktopModeHandleMenuActionButton" /> </LinearLayout> <LinearLayout diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 1eb24580a582..e6807ac5ea94 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -497,7 +497,7 @@ <!-- The maximum height of the handle menu in desktop mode. Four pills (52dp each) plus 2dp spacing between them plus 4dp top padding. --> - <dimen name="desktop_mode_handle_menu_height">218dp</dimen> + <dimen name="desktop_mode_handle_menu_height">270dp</dimen> <!-- The elevation set on the handle menu pills. --> <dimen name="desktop_mode_handle_menu_pill_elevation">1dp</dimen> @@ -508,8 +508,11 @@ <!-- The height of the handle menu's "Windowing" pill in desktop mode. --> <dimen name="desktop_mode_handle_menu_windowing_pill_height">52dp</dimen> - <!-- The height of the handle menu's "More Actions" pill in desktop mode. --> - <dimen name="desktop_mode_handle_menu_more_actions_pill_height">52dp</dimen> + <!-- The maximum height of the handle menu's "New Window" button in desktop mode. --> + <dimen name="desktop_mode_handle_menu_new_window_height">52dp</dimen> + + <!-- The maximum height of the handle menu's "Screenshot" button in desktop mode. --> + <dimen name="desktop_mode_handle_menu_screenshot_height">52dp</dimen> <!-- The height of the handle menu's "Open in browser" pill in desktop mode. --> <dimen name="desktop_mode_handle_menu_open_in_browser_pill_height">52dp</dimen> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index 8669af39747d..0a8166fb1a8d 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -282,6 +282,8 @@ <string name="screenshot_text">Screenshot</string> <!-- Accessibility text for the handle menu open in browser button [CHAR LIMIT=NONE] --> <string name="open_in_browser_text">Open in browser</string> + <!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] --> + <string name="new_window_text">New Window</string> <!-- Accessibility text for the handle menu close button [CHAR LIMIT=NONE] --> <string name="close_text">Close</string> <!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] --> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt index a6be64070ac1..4cd2fd04d3cf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt @@ -22,7 +22,6 @@ import android.content.pm.LauncherApps import android.content.pm.PackageManager import android.os.UserHandle import android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI -import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.wm.shell.R import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL @@ -41,7 +40,6 @@ class MultiInstanceHelper @JvmOverloads constructor( /** * Returns whether a specific component desires to be launched in multiple instances. */ - @VisibleForTesting fun supportsMultiInstanceSplit(componentName: ComponentName?): Boolean { if (componentName == null || componentName.packageName == null) { // TODO(b/262864589): Handle empty component case @@ -60,7 +58,7 @@ class MultiInstanceHelper @JvmOverloads constructor( if (!supportsMultiInstanceProperty) { // If not checking the multi-instance properties, then return early - return false; + return false } // Check the activity property first diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index da1af0d40a96..9cfbde4bad41 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -226,7 +226,8 @@ public abstract class WMShellModule { Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor, - AppToWebGenericLinksParser genericLinksParser) { + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, @@ -246,7 +247,8 @@ public abstract class WMShellModule { desktopTasksController, rootTaskDisplayAreaOrganizer, interactionJankMonitor, - genericLinksParser); + genericLinksParser, + multiInstanceHelper); } return new CaptionWindowDecorViewModel( context, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 7175ec45c4ab..2bb172fc53ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -98,6 +98,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallbackUtility import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import com.android.wm.shell.windowdecor.extension.isFullscreen +import com.android.wm.shell.windowdecor.extension.isMultiWindow import java.io.PrintWriter import java.util.Optional import java.util.concurrent.Executor @@ -902,6 +903,60 @@ class DesktopTasksController( request.triggerTask != null } + fun openNewWindow( + taskInfo: RunningTaskInfo + ) { + // TODO(b/337915660): Add a transition handler for these; animations + // need updates in some cases. + val newTaskWindowingMode = when { + taskInfo.isFreeform -> { + WINDOWING_MODE_FREEFORM + } + taskInfo.isFullscreen || taskInfo.isMultiWindow -> { + WINDOWING_MODE_MULTI_WINDOW + } + else -> { + error("Invalid windowing mode: ${taskInfo.windowingMode}") + } + } + + val baseActivity = taskInfo.baseActivity ?: return + val fillIn: Intent = context.packageManager + .getLaunchIntentForPackage( + baseActivity.packageName + ) ?: return + fillIn + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + val options = + ActivityOptions.makeBasic().apply { + launchWindowingMode = newTaskWindowingMode + isPendingIntentBackgroundActivityLaunchAllowedByPermission = true + pendingIntentBackgroundActivityStartMode = + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + } + val launchIntent = PendingIntent.getActivity( + context, + /* requestCode= */ 0, + fillIn, + PendingIntent.FLAG_IMMUTABLE + ) + when (newTaskWindowingMode) { + WINDOWING_MODE_MULTI_WINDOW -> { + val splitPosition = splitScreenController.determineNewInstancePosition(taskInfo) + splitScreenController.startIntent( + launchIntent, context.userId, fillIn, splitPosition, + options.toBundle(), null /* hideTaskToken */ + ) + } + WINDOWING_MODE_FREEFORM -> { + // TODO(b/336289597): This currently does not respect the desktop window limit. + val wct = WindowContainerTransaction() + wct.sendPendingIntent(launchIntent, fillIn, options.toBundle()) + transitions.startTransition(TRANSIT_OPEN, wct, null) + } + } + } + private fun handleFreeformTaskLaunch( task: RunningTaskInfo, transition: IBinder diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index b8575565ef8a..c4af14882a34 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -19,6 +19,7 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; import static android.view.Display.DEFAULT_DISPLAY; @@ -431,6 +432,20 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mStageCoordinator.clearSplitPairedInRecents(reason); } + /** + * Determines which split position a new instance of a task should take. + * @param callingTask The task requesting a new instance. + * @return the split position of the new instance + */ + public int determineNewInstancePosition(@NonNull ActivityManager.RunningTaskInfo callingTask) { + if (callingTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + || getSplitPosition(callingTask.taskId) == SPLIT_POSITION_TOP_OR_LEFT) { + return SPLIT_POSITION_BOTTOM_OR_RIGHT; + } else { + return SPLIT_POSITION_TOP_OR_LEFT; + } + } + public void enterSplitScreen(int taskId, boolean leftOrTop) { enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index ecd5edae1662..633067d767dd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -93,6 +93,7 @@ import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource; @@ -145,6 +146,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DesktopTasksController mDesktopTasksController; private final InputManager mInputManager; private final InteractionJankMonitor mInteractionJankMonitor; + private final MultiInstanceHelper mMultiInstanceHelper; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); @@ -204,7 +206,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor, - AppToWebGenericLinksParser genericLinksParser + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper ) { this( context, @@ -223,6 +226,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { transitions, desktopTasksController, genericLinksParser, + multiInstanceHelper, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, @@ -249,6 +253,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Transitions transitions, Optional<DesktopTasksController> desktopTasksController, AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, @@ -268,6 +273,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSyncQueue = syncQueue; mTransitions = transitions; mDesktopTasksController = desktopTasksController.get(); + mMultiInstanceHelper = multiInstanceHelper; mShellCommandHandler = shellCommandHandler; mWindowManager = windowManager; mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory; @@ -536,6 +542,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { decoration.onOpenInBrowserClick(); } else if (id == R.id.collapse_menu_button) { decoration.closeHandleMenu(); + } else if (id == R.id.new_window_button) { + decoration.closeHandleMenu(); + mDesktopTasksController.openNewWindow(decoration.mTaskInfo); } else if (id == R.id.maximize_window) { // TODO(b/346441962): move click detection logic into the decor's // {@link AppHeaderViewHolder}. Let it encapsulate the that and have it report @@ -1161,7 +1170,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mMainChoreographer, mSyncQueue, mRootTaskDisplayAreaOrganizer, - mGenericLinksParser); + mGenericLinksParser, + mMultiInstanceHelper); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final DragPositioningCallback dragPositioningCallback; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index df41d315fe5f..b8883443e5ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -74,6 +74,7 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; @@ -157,6 +158,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // to cancel the close. private final Runnable mCloseMaximizeWindowRunnable = this::closeMaximizeMenu; private final Runnable mCapturedLinkExpiredRunnable = this::onCapturedLinkExpired; + private final MultiInstanceHelper mMultiInstanceHelper; DesktopModeWindowDecoration( Context context, @@ -171,13 +173,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Choreographer choreographer, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - AppToWebGenericLinksParser genericLinksParser) { + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper) { this (context, userContext, displayController, splitScreenController, taskOrganizer, taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue, rootTaskDisplayAreaOrganizer, genericLinksParser, SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, new SurfaceControlViewHostFactory() {}, - DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE); + DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE, + multiInstanceHelper); } DesktopModeWindowDecoration( @@ -200,7 +204,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Supplier<SurfaceControl> surfaceControlSupplier, SurfaceControlViewHostFactory surfaceControlViewHostFactory, MaximizeMenuFactory maximizeMenuFactory, - HandleMenuFactory handleMenuFactory) { + HandleMenuFactory handleMenuFactory, + MultiInstanceHelper multiInstanceHelper) { super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, windowContainerTransactionSupplier, surfaceControlSupplier, @@ -214,6 +219,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mGenericLinksParser = genericLinksParser; mMaximizeMenuFactory = maximizeMenuFactory; mHandleMenuFactory = handleMenuFactory; + mMultiInstanceHelper = multiInstanceHelper; } /** @@ -966,6 +972,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mDisplayController, splitScreenController, DesktopModeStatus.canEnterDesktopMode(mContext), + Flags.enableDesktopWindowingMultiInstanceFeatures() + && mMultiInstanceHelper + .supportsMultiInstanceSplit(mTaskInfo.baseActivity), getBrowserLink(), mResult.mCaptionWidth, mResult.mCaptionHeight, @@ -1274,7 +1283,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Choreographer choreographer, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - AppToWebGenericLinksParser genericLinksParser) { + AppToWebGenericLinksParser genericLinksParser, + MultiInstanceHelper multiInstanceHelper) { return new DesktopModeWindowDecoration( context, userContext, @@ -1288,7 +1298,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin choreographer, syncQueue, rootTaskDisplayAreaOrganizer, - genericLinksParser); + genericLinksParser, + multiInstanceHelper); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 7a81d4c00c5e..74a640766dd0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -70,6 +70,7 @@ class HandleMenu( private val displayController: DisplayController, private val splitScreenController: SplitScreenController, private val shouldShowWindowingPill: Boolean, + private val shouldShowNewWindowButton: Boolean, val openInBrowserLink: Uri?, private val captionWidth: Int, private val captionHeight: Int, @@ -245,13 +246,24 @@ class HandleMenu( * Set up interactive elements & height of handle menu's more actions pill */ private fun setupMoreActionsPill(handleMenu: View, style: MenuStyle) { - val pill = handleMenu.requireViewById<View>(R.id.more_actions_pill).apply { - isGone = !SHOULD_SHOW_MORE_ACTIONS_PILL - background.colorFilter = BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) - } - pill.requireViewById<Button>(R.id.screenshot_button).let { screenshotBtn -> - screenshotBtn.setTextColor(style.textColor) - screenshotBtn.compoundDrawableTintList = ColorStateList.valueOf(style.textColor) + val moreActionsPill = handleMenu.findViewById<View>(R.id.more_actions_pill) + moreActionsPill.isGone = !shouldShowNewWindowButton && !SHOULD_SHOW_SCREENSHOT_BUTTON + if (!moreActionsPill.isGone) { + handleMenu.requireViewById<Button>(R.id.screenshot_button).apply { + isGone = !SHOULD_SHOW_SCREENSHOT_BUTTON + background.colorFilter = + BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) + setTextColor(style.textColor) + compoundDrawableTintList = ColorStateList.valueOf(style.textColor) + } + handleMenu.findViewById<Button>(R.id.new_window_button).apply { + isGone = !shouldShowNewWindowButton + background.colorFilter = + BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) + setTextColor(style.textColor) + compoundDrawableTintList = ColorStateList.valueOf(style.textColor) + if (!isGone) setOnClickListener(onClickListener) + } } } @@ -439,9 +451,17 @@ class HandleMenu( R.dimen.desktop_mode_handle_menu_windowing_pill_height) menuHeight -= pillTopMargin } - if (!SHOULD_SHOW_MORE_ACTIONS_PILL) { + if (!SHOULD_SHOW_SCREENSHOT_BUTTON) { menuHeight -= loadDimensionPixelSize( - R.dimen.desktop_mode_handle_menu_more_actions_pill_height) + R.dimen.desktop_mode_handle_menu_screenshot_height + ) + } + if (!shouldShowNewWindowButton) { + menuHeight -= loadDimensionPixelSize( + R.dimen.desktop_mode_handle_menu_new_window_height + ) + } + if (!SHOULD_SHOW_SCREENSHOT_BUTTON && !shouldShowNewWindowButton) { menuHeight -= pillTopMargin } if (!shouldShowBrowserPill) { @@ -501,7 +521,7 @@ class HandleMenu( companion object { private const val TAG = "HandleMenu" - private const val SHOULD_SHOW_MORE_ACTIONS_PILL = false + private const val SHOULD_SHOW_SCREENSHOT_BUTTON = false } } @@ -517,6 +537,7 @@ interface HandleMenuFactory { displayController: DisplayController, splitScreenController: SplitScreenController, shouldShowWindowingPill: Boolean, + shouldShowNewWindowButton: Boolean, openInBrowserLink: Uri?, captionWidth: Int, captionHeight: Int, @@ -536,6 +557,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { displayController: DisplayController, splitScreenController: SplitScreenController, shouldShowWindowingPill: Boolean, + shouldShowNewWindowButton: Boolean, openInBrowserLink: Uri?, captionWidth: Int, captionHeight: Int, @@ -551,6 +573,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { displayController, splitScreenController, shouldShowWindowingPill, + shouldShowNewWindowButton, openInBrowserLink, captionWidth, captionHeight, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index e26416047c56..c3a0bd94d7c0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -68,6 +68,7 @@ import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayInsetsController import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.desktopmode.DesktopTasksController @@ -145,6 +146,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor @Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser private val bgExecutor = TestShellExecutor() + @Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper private val transactionFactory = Supplier<SurfaceControl.Transaction> { SurfaceControl.Transaction() @@ -176,6 +178,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockTransitions, Optional.of(mockDesktopTasksController), mockGenericLinksParser, + mockMultiInstanceHelper, mockDesktopModeWindowDecorFactory, mockInputMonitorFactory, transactionFactory, @@ -659,8 +662,9 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { private fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration { val decoration = mock(DesktopModeWindowDecoration::class.java) whenever( - mockDesktopModeWindowDecorFactory.create(any(), any(), any(), any(), any(), eq(task), - any(), any(), any(), any(), any(), any(), any()) + mockDesktopModeWindowDecorFactory.create( + any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), + any(), any(), any()) ).thenReturn(decoration) decoration.mTaskInfo = task whenever(decoration.isFocused).thenReturn(task.isFocused) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 04b1eed02950..e60eb77ff16f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -89,6 +89,7 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; @@ -174,6 +175,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private HandleMenu mMockHandleMenu; @Mock private HandleMenuFactory mMockHandleMenuFactory; + private MultiInstanceHelper mMockMultiInstanceHelper; @Captor private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener; @Captor @@ -218,7 +220,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY); doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt()); doReturn(mMockHandleMenu).when(mMockHandleMenuFactory).create(any(), anyInt(), any(), any(), - any(), any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()); + any(), any(), any(), any(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), + anyInt()); } @After @@ -775,7 +778,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private void verifyHandleMenuCreated(@Nullable Uri uri) { verify(mMockHandleMenuFactory).create(any(), anyInt(), any(), any(), any(), any(), any(), - any(), anyBoolean(), eq(uri), anyInt(), anyInt(), anyInt()); + any(), anyBoolean(), anyBoolean(), eq(uri), anyInt(), anyInt(), anyInt()); } private void createMaximizeMenu(DesktopModeWindowDecoration decoration, MaximizeMenu menu) { @@ -831,7 +834,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer, mMockGenericLinksParser, SurfaceControl.Builder::new, mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new, - mMockSurfaceControlViewHostFactory, maximizeMenuFactory, mMockHandleMenuFactory); + mMockSurfaceControlViewHostFactory, maximizeMenuFactory, mMockHandleMenuFactory, + mMockMultiInstanceHelper); windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener, mMockTouchEventListener, mMockTouchEventListener); windowDecor.setExclusionRegionListener(mMockExclusionRegionListener); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt index ed43aa3f1301..cca83dd031f7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt @@ -227,11 +227,11 @@ class HandleMenuTest : ShellTestCase() { else -> error("Invalid windowing mode") } val handleMenu = HandleMenu(mockDesktopWindowDecoration, layoutId, - onClickListener, onTouchListener, appIcon, appName, displayController, - splitScreenController, shouldShowWindowingPill = true, - null /* openInBrowserLink */, captionWidth = HANDLE_WIDTH, captionHeight = 50, - captionX = captionX - ) + onClickListener, onTouchListener, appIcon, appName, displayController, + splitScreenController, shouldShowWindowingPill = true, + shouldShowNewWindowButton = true, + openInBrowserLink = null, captionWidth = HANDLE_WIDTH, captionHeight = 50, + captionX = captionX) handleMenu.show() return handleMenu } |