diff options
21 files changed, 638 insertions, 44 deletions
diff --git a/core/java/android/window/TaskConstants.java b/core/java/android/window/TaskConstants.java index 69d79b449615..44bb33db6347 100644 --- a/core/java/android/window/TaskConstants.java +++ b/core/java/android/window/TaskConstants.java @@ -81,6 +81,12 @@ public class TaskConstants {      public static final int TASK_CHILD_LAYER_RESIZE_VEIL = 6 * TASK_CHILD_LAYER_REGION_SIZE;      /** +     * Floating menus belonging to a task (e.g. maximize menu). +     * @hide +     */ +    public  static final int TASK_CHILD_LAYER_FLOATING_MENU = 7 * TASK_CHILD_LAYER_REGION_SIZE; + +    /**       * Z-orders of task child layers other than activities, task fragments and layers interleaved       * with them, e.g. IME windows. [-10000, 10000) is reserved for these layers.       * @hide diff --git a/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml b/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml new file mode 100644 index 000000000000..65f5239737b2 --- /dev/null +++ b/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2023 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 +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> +    <item android:state_pressed="true" +        android:color="@color/desktop_mode_maximize_menu_button_on_hover"/> +    <item android:state_hovered="true" +        android:color="@color/desktop_mode_maximize_menu_button_on_hover"/> +    <item android:state_focused="true" +        android:color="@color/desktop_mode_maximize_menu_button_on_hover"/> +    <item android:state_selected="true" +        android:color="@color/desktop_mode_maximize_menu_button_on_hover"/> +    <item android:color="@color/desktop_mode_maximize_menu_button"/> +</selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_outline_color_selector.xml b/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_outline_color_selector.xml new file mode 100644 index 000000000000..86679af5428b --- /dev/null +++ b/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_outline_color_selector.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2023 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 +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> +    <item android:state_pressed="true" +        android:color="@color/desktop_mode_maximize_menu_button_outline_on_hover"/> +    <item android:state_hovered="true" +        android:color="@color/desktop_mode_maximize_menu_button_outline_on_hover"/> +    <item android:state_focused="true" +        android:color="@color/desktop_mode_maximize_menu_button_outline_on_hover"/> +    <item android:state_selected="true" +        android:color="@color/desktop_mode_maximize_menu_button_outline_on_hover"/> +    <item android:color="@color/desktop_mode_maximize_menu_button_outline"/> +</selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_handle_menu_background.xml index 4ee10f429b37..4ee10f429b37 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_handle_menu_background.xml diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml new file mode 100644 index 000000000000..5d9fe67e8bee --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2023 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. +  --> +<shape android:shape="rectangle" +    xmlns:android="http://schemas.android.com/apk/res/android"> +    <solid android:color="@android:color/white" /> +    <corners android:radius="@dimen/desktop_mode_maximize_menu_corner_radius" /> +</shape> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_maximize_button_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_maximize_button_background.xml new file mode 100644 index 000000000000..bfb0dd7f3100 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_maximize_button_background.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2023 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 +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" +    android:shape="rectangle"> +    <solid android:color="@color/desktop_mode_maximize_menu_button_color_selector"/> +    <corners +        android:radius="@dimen/desktop_mode_maximize_menu_buttons_large_corner_radius"/> +    <stroke android:width="1dp" android:color="@color/desktop_mode_maximize_menu_button_outline_color_selector"/> +</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_snap_left_button_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_snap_left_button_background.xml new file mode 100644 index 000000000000..6630fcab4794 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_snap_left_button_background.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- +  ~ Copyright (C) 2023 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 +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" +    android:shape="rectangle"> +    <solid android:color="@color/desktop_mode_maximize_menu_button_color_selector"/> +    <corners +        android:topLeftRadius="@dimen/desktop_mode_maximize_menu_buttons_large_corner_radius" +        android:topRightRadius="@dimen/desktop_mode_maximize_menu_buttons_small_corner_radius" +        android:bottomLeftRadius="@dimen/desktop_mode_maximize_menu_buttons_large_corner_radius" +        android:bottomRightRadius="@dimen/desktop_mode_maximize_menu_buttons_small_corner_radius"/> +    <stroke android:width="1dp" android:color="@color/desktop_mode_maximize_menu_button_outline_color_selector"/> +</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_snap_right_button_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_snap_right_button_background.xml new file mode 100644 index 000000000000..7bd6e9981c12 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_snap_right_button_background.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- +  ~ Copyright (C) 2023 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 +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" +    android:shape="rectangle"> +    <solid android:color="@color/desktop_mode_maximize_menu_button_color_selector"/> +    <corners +        android:topLeftRadius="@dimen/desktop_mode_maximize_menu_buttons_small_corner_radius" +        android:topRightRadius="@dimen/desktop_mode_maximize_menu_buttons_large_corner_radius" +        android:bottomLeftRadius="@dimen/desktop_mode_maximize_menu_buttons_small_corner_radius" +        android:bottomRightRadius="@dimen/desktop_mode_maximize_menu_buttons_large_corner_radius"/> +    <stroke android:width="1dp" android:color="@color/desktop_mode_maximize_menu_button_outline_color_selector"/> +</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml index 167a003932d6..c03d240d59f2 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml @@ -19,7 +19,7 @@      android:layout_width="@dimen/desktop_mode_handle_menu_width"      android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height"      android:orientation="horizontal" -    android:background="@drawable/desktop_mode_decor_menu_background" +    android:background="@drawable/desktop_mode_decor_handle_menu_background"      android:gravity="center_vertical">      <ImageView diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml index 40a4b53f3e1d..cdf4937599c9 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml @@ -18,7 +18,7 @@      android:layout_width="@dimen/desktop_mode_handle_menu_width"      android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height"      android:orientation="vertical" -    android:background="@drawable/desktop_mode_decor_menu_background"> +    android:background="@drawable/desktop_mode_decor_handle_menu_background">      <Button          android:id="@+id/screenshot_button" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml index 95283b9e214a..08d91498b338 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml @@ -18,7 +18,7 @@      android:layout_width="@dimen/desktop_mode_handle_menu_width"      android:layout_height="@dimen/desktop_mode_handle_menu_windowing_pill_height"      android:orientation="horizontal" -    android:background="@drawable/desktop_mode_decor_menu_background" +    android:background="@drawable/desktop_mode_decor_handle_menu_background"      android:gravity="center_vertical">      <ImageButton diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml new file mode 100644 index 000000000000..0db72f7be8e6 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2023 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. +  --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +    style="?android:attr/buttonBarStyle" +    android:layout_width="@dimen/desktop_mode_maximize_menu_width" +    android:layout_height="@dimen/desktop_mode_maximize_menu_height" +    android:orientation="horizontal" +    android:gravity="center" +    android:background="@drawable/desktop_mode_maximize_menu_background"> + + +    <Button +        android:id="@+id/maximize_menu_maximize_button" +        style="?android:attr/buttonBarButtonStyle" +        android:layout_width="120dp" +        android:layout_height="80dp" +        android:layout_marginRight="15dp" +        android:color="@color/desktop_mode_maximize_menu_button" +        android:background="@drawable/desktop_mode_maximize_menu_maximize_button_background" +        android:stateListAnimator="@null"/> + +    <Button +        android:id="@+id/maximize_menu_snap_left_button" +        style="?android:attr/buttonBarButtonStyle" +        android:layout_width="58dp" +        android:layout_height="80dp" +        android:layout_marginRight="6dp" +        android:color="@color/desktop_mode_maximize_menu_button" +        android:background="@drawable/desktop_mode_maximize_menu_snap_left_button_background" +        android:stateListAnimator="@null"/> + +    <Button +        android:id="@+id/maximize_menu_snap_right_button" +        style="?android:attr/buttonBarButtonStyle" +        android:layout_width="58dp" +        android:layout_height="80dp" +        android:color="@color/desktop_mode_maximize_menu_button" +        android:background="@drawable/desktop_mode_maximize_menu_snap_right_button_background" +        android:stateListAnimator="@null"/> +</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index b2ec98bc1b15..f76a346a8f5d 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -73,4 +73,8 @@      <color name="desktop_mode_caption_menu_buttons_color_active">#00677E</color>      <color name="desktop_mode_resize_veil_light">#EFF1F2</color>      <color name="desktop_mode_resize_veil_dark">#1C1C17</color> +    <color name="desktop_mode_maximize_menu_button">#DDDACD</color> +    <color name="desktop_mode_maximize_menu_button_outline">#797869</color> +    <color name="desktop_mode_maximize_menu_button_outline_on_hover">#606219</color> +    <color name="desktop_mode_maximize_menu_button_on_hover">#E7E790</color>  </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 20bf81da5561..d0c0c0296935 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -401,6 +401,24 @@      <!-- Height of button (32dp)  + 2 * margin (5dp each). -->      <dimen name="freeform_decor_caption_height">42dp</dimen> +    <!-- The width of the maximize menu in desktop mode. --> +    <dimen name="desktop_mode_maximize_menu_width">287dp</dimen> + +    <!-- The height of the maximize menu in desktop mode. --> +    <dimen name="desktop_mode_maximize_menu_height">112dp</dimen> + +    <!-- The larger of the two corner radii of the maximize menu buttons. --> +    <dimen name="desktop_mode_maximize_menu_buttons_large_corner_radius">4dp</dimen> + +    <!-- The smaller of the two corner radii of the maximize menu buttons. --> +    <dimen name="desktop_mode_maximize_menu_buttons_small_corner_radius">2dp</dimen> + +    <!-- The corner radius of the maximize menu. --> +    <dimen name="desktop_mode_maximize_menu_corner_radius">8dp</dimen> + +    <!-- The radius of the Maximize menu shadow. --> +    <dimen name="desktop_mode_maximize_menu_shadow_radius">8dp</dimen> +      <!-- The width of the handle menu in desktop mode. -->      <dimen name="desktop_mode_handle_menu_width">216dp</dimen> 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 36d2a706b88b..93ce91fa2d9c 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 @@ -196,7 +196,8 @@ public abstract class WMShellModule {              SyncTransactionQueue syncQueue,              Transitions transitions,              Optional<DesktopModeController> desktopModeController, -            Optional<DesktopTasksController> desktopTasksController) { +            Optional<DesktopTasksController> desktopTasksController, +            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {          if (DesktopModeStatus.isAnyEnabled()) {              return new DesktopModeWindowDecorViewModel(                      context, @@ -209,7 +210,8 @@ public abstract class WMShellModule {                      syncQueue,                      transitions,                      desktopModeController, -                    desktopTasksController); +                    desktopTasksController, +                    rootTaskDisplayAreaOrganizer);          }          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 b0f75c6a1e6d..4740a9d2e030 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 @@ -105,7 +105,8 @@ class DesktopTasksController(      private val transitionAreaHeight          get() = context.resources.getDimensionPixelSize( -                com.android.wm.shell.R.dimen.desktop_mode_transition_area_height) +                com.android.wm.shell.R.dimen.desktop_mode_transition_area_height +        )      // This is public to avoid cyclic dependency; it is set by SplitScreenController      lateinit var splitScreenController: SplitScreenController @@ -485,6 +486,55 @@ class DesktopTasksController(          }      } +    /** +     * Quick-resize to the right or left half of the stable bounds. +     * +     * @param position the portion of the screen (RIGHT or LEFT) we want to snap the task to. +     */ +    fun snapToHalfScreen( +            taskInfo: RunningTaskInfo, +            windowDecor: DesktopModeWindowDecoration, +            position: SnapPosition +    ) { +        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return + +        val stableBounds = Rect() +        displayLayout.getStableBounds(stableBounds) + +        val destinationWidth = stableBounds.width() / 2 +        val destinationBounds = when (position) { +            SnapPosition.LEFT -> { +                Rect( +                        stableBounds.left, +                        stableBounds.top, +                        stableBounds.left + destinationWidth, +                        stableBounds.bottom +                ) +            } +            SnapPosition.RIGHT -> { +                Rect( +                        stableBounds.right - destinationWidth, +                        stableBounds.top, +                        stableBounds.right, +                        stableBounds.bottom +                ) +            } +        } + +        if (destinationBounds == taskInfo.configuration.windowConfiguration.bounds) return + +        val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) +        if (Transitions.ENABLE_SHELL_TRANSITIONS) { +            toggleResizeDesktopTaskTransitionHandler.startTransition( +                    wct, +                    taskInfo.taskId, +                    windowDecor +            ) +        } else { +            shellTaskOrganizer.applyTransaction(wct) +        } +    } +      private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) {          val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt()          val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt() @@ -1077,4 +1127,7 @@ class DesktopTasksController(              return DESKTOP_DENSITY_OVERRIDE in DESKTOP_DENSITY_ALLOWED_RANGE          }      } + +    /** The positions on a screen that a task can snap to. */ +    enum class SnapPosition { RIGHT, LEFT }  } 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 29fff03500a5..026e973f881a 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 @@ -63,6 +63,7 @@ import androidx.annotation.Nullable;  import com.android.internal.annotations.VisibleForTesting;  import com.android.wm.shell.R; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer;  import com.android.wm.shell.ShellTaskOrganizer;  import com.android.wm.shell.common.DisplayController;  import com.android.wm.shell.common.DisplayLayout; @@ -70,6 +71,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;  import com.android.wm.shell.desktopmode.DesktopModeController;  import com.android.wm.shell.desktopmode.DesktopModeStatus;  import com.android.wm.shell.desktopmode.DesktopTasksController; +import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;  import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;  import com.android.wm.shell.splitscreen.SplitScreen;  import com.android.wm.shell.splitscreen.SplitScreenController; @@ -120,6 +122,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {      private MoveToDesktopAnimator mMoveToDesktopAnimator;      private final Rect mDragToDesktopAnimationStartBounds = new Rect();      private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener; +    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;      public DesktopModeWindowDecorViewModel(              Context context, @@ -132,7 +135,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {              SyncTransactionQueue syncQueue,              Transitions transitions,              Optional<DesktopModeController> desktopModeController, -            Optional<DesktopTasksController> desktopTasksController +            Optional<DesktopTasksController> desktopTasksController, +            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer      ) {          this(                  context, @@ -149,7 +153,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {                  new DesktopModeWindowDecoration.Factory(),                  new InputMonitorFactory(),                  SurfaceControl.Transaction::new, -                new DesktopModeKeyguardChangeListener()); +                new DesktopModeKeyguardChangeListener(), +                rootTaskDisplayAreaOrganizer);      }      @VisibleForTesting @@ -168,7 +173,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {              DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,              InputMonitorFactory inputMonitorFactory,              Supplier<SurfaceControl.Transaction> transactionFactory, -            DesktopModeKeyguardChangeListener desktopModeKeyguardChangeListener) { +            DesktopModeKeyguardChangeListener desktopModeKeyguardChangeListener, +            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {          mContext = context;          mMainHandler = mainHandler;          mMainChoreographer = mainChoreographer; @@ -185,6 +191,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {          mInputMonitorFactory = inputMonitorFactory;          mTransactionFactory = transactionFactory;          mDesktopModeKeyguardChangeListener = desktopModeKeyguardChangeListener; +        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;          shellInit.addInitCallback(this::onInit, this);      } @@ -318,7 +325,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {      }      private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener -            implements View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler { +            implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener, +            DragDetector.MotionEventHandler{          private final int mTaskId;          private final WindowContainerToken mTaskToken; @@ -355,9 +363,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {                              .getTaskInfo(remainingTaskPosition);                      mSplitScreenController.moveTaskToFullscreen(remainingTask.taskId);                  } +                decoration.closeMaximizeMenu();              } else if (id == R.id.back_button) {                  mTaskOperations.injectBackKey();              } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { +                decoration.closeMaximizeMenu();                  if (!decoration.isHandleMenuActive()) {                      moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));                      decoration.createHandleMenu(); @@ -391,13 +401,35 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {                      // TODO(b/278084491): dev option to enable display switching                      //  remove when select is implemented                      mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId)); -                    decoration.closeHandleMenu();                  }              } else if (id == R.id.maximize_window) { +                moveTaskToFront(decoration.mTaskInfo); +                if (decoration.isMaximizeMenuActive()) { +                    decoration.closeMaximizeMenu(); +                    return; +                }                  final RunningTaskInfo taskInfo = decoration.mTaskInfo;                  mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(                          taskInfo, decoration));                  decoration.closeHandleMenu(); +            } else if (id == R.id.maximize_menu_maximize_button) { +                final RunningTaskInfo taskInfo = decoration.mTaskInfo; +                mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize( +                        taskInfo, mWindowDecorByTaskId.get(taskInfo.taskId))); +                decoration.closeHandleMenu(); +                decoration.closeMaximizeMenu(); +            } else if (id == R.id.maximize_menu_snap_left_button) { +                final RunningTaskInfo taskInfo = decoration.mTaskInfo; +                mDesktopTasksController.ifPresent(c -> c.snapToHalfScreen( +                        taskInfo, mWindowDecorByTaskId.get(taskInfo.taskId), SnapPosition.LEFT)); +                decoration.closeHandleMenu(); +                decoration.closeMaximizeMenu(); +            } else if (id == R.id.maximize_menu_snap_right_button) { +                final RunningTaskInfo taskInfo = decoration.mTaskInfo; +                mDesktopTasksController.ifPresent(c -> c.snapToHalfScreen( +                        taskInfo, mWindowDecorByTaskId.get(taskInfo.taskId), SnapPosition.RIGHT)); +                decoration.closeHandleMenu(); +                decoration.closeMaximizeMenu();              }          } @@ -412,6 +444,23 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {              return mDragDetector.onMotionEvent(v, e);          } +        @Override +        public boolean onLongClick(View v) { +            final int id = v.getId(); +            if (id == R.id.maximize_window) { +                final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); +                moveTaskToFront(decoration.mTaskInfo); +                if (decoration.isMaximizeMenuActive()) { +                    decoration.closeMaximizeMenu(); +                } else { +                    decoration.closeHandleMenu(); +                    decoration.createMaximizeMenu(); +                } +                return true; +            } +            return false; +        } +          private void moveTaskToFront(RunningTaskInfo taskInfo) {              if (!taskInfo.isFocused) {                  mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo)); @@ -875,7 +924,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {                          taskSurface,                          mMainHandler,                          mMainChoreographer, -                        mSyncQueue); +                        mSyncQueue, +                        mRootTaskDisplayAreaOrganizer);          mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);          windowDecoration.createResizeVeil(); @@ -884,7 +934,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {          final DesktopModeTouchEventListener touchEventListener =                  new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback); -        windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); +        windowDecoration.setCaptionListeners( +                touchEventListener, touchEventListener, touchEventListener);          windowDecoration.setCornersListener(mCornersListener);          windowDecoration.setDragPositioningCallback(dragPositioningCallback);          windowDecoration.setDragDetector(touchEventListener.mDragDetector); @@ -911,7 +962,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {              implements DragPositioningCallbackUtility.DragStartListener {          @Override          public void onDragStart(int taskId) { -            mWindowDecorByTaskId.get(taskId).closeHandleMenu(); +            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); +            decoration.closeHandleMenu(); +            decoration.closeMaximizeMenu();          }      } 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 a359395711e3..a75dce225624 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 @@ -23,6 +23,7 @@ import android.content.Context;  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManager;  import android.content.res.Configuration; +import android.content.res.Resources;  import android.graphics.Point;  import android.graphics.PointF;  import android.graphics.Rect; @@ -36,13 +37,16 @@ import android.view.MotionEvent;  import android.view.SurfaceControl;  import android.view.View;  import android.view.ViewConfiguration; +import android.widget.ImageButton;  import android.window.WindowContainerTransaction;  import com.android.internal.policy.ScreenDecorationsUtils;  import com.android.launcher3.icons.IconProvider;  import com.android.wm.shell.R; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer;  import com.android.wm.shell.ShellTaskOrganizer;  import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout;  import com.android.wm.shell.common.SyncTransactionQueue;  import com.android.wm.shell.desktopmode.DesktopModeStatus;  import com.android.wm.shell.desktopmode.DesktopTasksController; @@ -69,6 +73,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin      private DesktopModeWindowDecorationViewHolder mWindowDecorViewHolder;      private View.OnClickListener mOnCaptionButtonClickListener;      private View.OnTouchListener mOnCaptionTouchListener; +    private View.OnLongClickListener mOnCaptionLongClickListener;      private DragPositioningCallback mDragPositioningCallback;      private DragResizeInputListener mDragResizeListener;      private DragDetector mDragDetector; @@ -80,6 +85,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin      private final Point mPositionInParent = new Point();      private HandleMenu mHandleMenu; +    private MaximizeMenu mMaximizeMenu; +      private ResizeVeil mResizeVeil;      private Drawable mAppIcon; @@ -89,6 +96,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin      private final Set<IBinder> mTransitionsPausingRelayout = new HashSet<>();      private int mRelayoutBlock; +    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;      DesktopModeWindowDecoration(              Context context, @@ -98,12 +106,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin              SurfaceControl taskSurface,              Handler handler,              Choreographer choreographer, -            SyncTransactionQueue syncQueue) { +            SyncTransactionQueue syncQueue, +            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {          super(context, displayController, taskOrganizer, taskInfo, taskSurface);          mHandler = handler;          mChoreographer = choreographer;          mSyncQueue = syncQueue; +        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;          loadAppInfo();      } @@ -121,9 +131,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin      void setCaptionListeners(              View.OnClickListener onCaptionButtonClickListener, -            View.OnTouchListener onCaptionTouchListener) { +            View.OnTouchListener onCaptionTouchListener, +            View.OnLongClickListener onLongClickListener) {          mOnCaptionButtonClickListener = onCaptionButtonClickListener;          mOnCaptionTouchListener = onCaptionTouchListener; +        mOnCaptionLongClickListener = onLongClickListener;      }      void setCornersListener(TaskCornersListener cornersListener) { @@ -207,6 +219,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin                          mResult.mRootView,                          mOnCaptionTouchListener,                          mOnCaptionButtonClickListener, +                        mOnCaptionLongClickListener,                          mAppName,                          mAppIcon                  ); @@ -218,6 +231,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin          if (!mTaskInfo.isFocused) {              closeHandleMenu(); +            closeMaximizeMenu();          }          if (!isDragResizeable) { @@ -255,6 +269,52 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin              mCornersListener.onTaskCornersChanged(mTaskInfo.taskId, getGlobalCornersRegion());          }          mPositionInParent.set(mTaskInfo.positionInParent); + +        if (isMaximizeMenuActive()) { +            if (!mTaskInfo.isVisible()) { +                closeMaximizeMenu(); +            } else { +                mMaximizeMenu.positionMenu(calculateMaximizeMenuPosition(), startT); +            } +        } +    } + +    private PointF calculateMaximizeMenuPosition() { +        final PointF position = new PointF(); +        final Resources resources = mContext.getResources(); +        final DisplayLayout displayLayout = +                mDisplayController.getDisplayLayout(mTaskInfo.displayId); +        if (displayLayout == null) return position; + +        final int displayWidth = displayLayout.width(); +        final int displayHeight = displayLayout.height(); +        final int captionHeight = loadDimensionPixelSize( +                resources, R.dimen.freeform_decor_caption_height); + +        final ImageButton maximizeWindowButton = +                mResult.mRootView.findViewById(R.id.maximize_window); +        final int[] maximizeButtonLocation = new int[2]; +        maximizeWindowButton.getLocationInWindow(maximizeButtonLocation); + +        final int menuWidth = loadDimensionPixelSize( +                resources, R.dimen.desktop_mode_maximize_menu_width); +        final int menuHeight = loadDimensionPixelSize( +                resources, R.dimen.desktop_mode_maximize_menu_height); + +        float menuLeft = (mPositionInParent.x + maximizeButtonLocation[0]); +        float menuTop = (mPositionInParent.y + captionHeight); +        final float menuRight = menuLeft + menuWidth; +        final float menuBottom = menuTop + menuHeight; + +        // If the menu is out of screen bounds, shift it up/left as needed +        if (menuRight > displayWidth) { +            menuLeft = (displayWidth - menuWidth); +        } +        if (menuBottom > displayHeight) { +            menuTop = (displayHeight - menuHeight); +        } + +        return new PointF(menuLeft, menuTop);      }      boolean isHandleMenuActive() { @@ -335,6 +395,29 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin      }      /** +     * Create and display maximize menu window +     */ +    void createMaximizeMenu() { +        mMaximizeMenu = new MaximizeMenu(mSyncQueue, mRootTaskDisplayAreaOrganizer, +                mDisplayController, mTaskInfo, mOnCaptionButtonClickListener, mContext, +                calculateMaximizeMenuPosition(), mSurfaceControlTransactionSupplier); +        mMaximizeMenu.show(); +    } + +    /** +     * Close the maximize menu window +     */ +    void closeMaximizeMenu() { +        if (!isMaximizeMenuActive()) return; +        mMaximizeMenu.close(); +        mMaximizeMenu = null; +    } + +    boolean isMaximizeMenuActive() { +        return mMaximizeMenu != null; +    } + +    /**       * Create and display handle menu window       */      void createHandleMenu() { @@ -532,7 +615,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin                  SurfaceControl taskSurface,                  Handler handler,                  Choreographer choreographer, -                SyncTransactionQueue syncQueue) { +                SyncTransactionQueue syncQueue, +                RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {              return new DesktopModeWindowDecoration(                      context,                      displayController, @@ -541,7 +625,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin                      taskSurface,                      handler,                      choreographer, -                    syncQueue); +                    syncQueue, +                    rootTaskDisplayAreaOrganizer);          }      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt new file mode 100644 index 000000000000..4dc98e47ab45 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2023 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.wm.shell.windowdecor + +import android.app.ActivityManager.RunningTaskInfo +import android.content.Context +import android.content.res.Resources +import android.graphics.PixelFormat +import android.graphics.PointF +import android.view.LayoutInflater +import android.view.SurfaceControl +import android.view.SurfaceControl.Transaction +import android.view.SurfaceControlViewHost +import android.view.View.OnClickListener +import android.view.WindowManager +import android.view.WindowlessWindowManager +import android.widget.Button +import android.window.TaskConstants +import com.android.wm.shell.R +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.windowdecor.WindowDecoration.AdditionalWindow +import java.util.function.Supplier + + +/** + *  Menu that appears when user long clicks the maximize button. Gives the user the option to + *  maximize the task or snap the task to the right or left half of the screen. + */ +class MaximizeMenu( +        private val syncQueue: SyncTransactionQueue, +        private val rootTdaOrganizer: RootTaskDisplayAreaOrganizer, +        private val displayController: DisplayController, +        private val taskInfo: RunningTaskInfo, +        private val onClickListener: OnClickListener, +        private val decorWindowContext: Context, +        private val menuPosition: PointF, +        private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() } +) { +    private var maximizeMenu: AdditionalWindow? = null +    private lateinit var viewHost: SurfaceControlViewHost +    private lateinit var leash: SurfaceControl +    private val shadowRadius = loadDimensionPixelSize( +            R.dimen.desktop_mode_maximize_menu_shadow_radius +    ).toFloat() +    private val cornerRadius = loadDimensionPixelSize( +            R.dimen.desktop_mode_maximize_menu_corner_radius +    ).toFloat() + +    /** Position the menu relative to the caption's position. */ +    fun positionMenu(position: PointF, t: Transaction) { +        menuPosition.set(position) +        t.setPosition(leash, menuPosition.x, menuPosition.y) +    } + +    /** Creates and shows the maximize window. */ +    fun show() { +        if (maximizeMenu != null) return +        createMaximizeMenu() +        setupMaximizeMenu() +    } + +    /** Closes the maximize window and releases its view. */ +    fun close() { +        maximizeMenu?.releaseView() +        maximizeMenu = null +    } + +    /** Create a maximize menu that is attached to the display area. */ +    private fun createMaximizeMenu() { +        val t = transactionSupplier.get() +        val v = LayoutInflater.from(decorWindowContext).inflate( +                R.layout.desktop_mode_window_decor_maximize_menu, +                null // Root +        ) +        val builder = SurfaceControl.Builder() +        rootTdaOrganizer.attachToDisplayArea(taskInfo.displayId, builder) +        leash = builder +                .setName("Maximize Menu") +                .setContainerLayer() +                .build() +        val menuWidth = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_width) +        val menuHeight = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_height) +        val lp = WindowManager.LayoutParams( +                menuWidth, +                menuHeight, +                WindowManager.LayoutParams.TYPE_APPLICATION, +                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, +                PixelFormat.TRANSPARENT +        ) +        lp.title = "Maximize Menu for Task=" + taskInfo.taskId +        lp.setTrustedOverlay() +        val windowManager = WindowlessWindowManager( +                taskInfo.configuration, +                leash, +                null // HostInputToken +        ) +        viewHost = SurfaceControlViewHost(decorWindowContext, +                displayController.getDisplay(taskInfo.displayId), windowManager, +                "MaximizeMenu") +        viewHost.setView(v, lp) + +        // Bring menu to front when open +        t.setLayer(leash, TaskConstants.TASK_CHILD_LAYER_FLOATING_MENU) +                .setPosition(leash, menuPosition.x, menuPosition.y) +                .setWindowCrop(leash, menuWidth, menuHeight) +                .setShadowRadius(leash, shadowRadius) +                .setCornerRadius(leash, cornerRadius) +                .show(leash) +        maximizeMenu = AdditionalWindow(leash, viewHost, transactionSupplier) + +        syncQueue.runInSync { transaction -> +            transaction.merge(t) +            t.close() +        } +    } + +    private fun loadDimensionPixelSize(resourceId: Int): Int { +        return if (resourceId == Resources.ID_NULL) { +            0 +        } else { +            decorWindowContext.resources.getDimensionPixelSize(resourceId) +        } +    } + +    private fun setupMaximizeMenu() { +        val maximizeMenuView = maximizeMenu?.mWindowViewHost?.view ?: return + +        maximizeMenuView.findViewById<Button>( +                R.id.maximize_menu_maximize_button +        ).setOnClickListener(onClickListener) +        maximizeMenuView.findViewById<Button>( +                R.id.maximize_menu_snap_right_button +        ).setOnClickListener(onClickListener) +        maximizeMenuView.findViewById<Button>( +                R.id.maximize_menu_snap_left_button +        ).setOnClickListener(onClickListener) +    } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt index a9eb8829bd2c..6b59ccec5148 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt @@ -5,6 +5,7 @@ import android.content.res.ColorStateList  import android.graphics.drawable.Drawable  import android.graphics.drawable.GradientDrawable  import android.view.View +import android.view.View.OnLongClickListener  import android.widget.ImageButton  import android.widget.ImageView  import android.widget.TextView @@ -19,6 +20,7 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(          rootView: View,          onCaptionTouchListener: View.OnTouchListener,          onCaptionButtonClickListener: View.OnClickListener, +        onLongClickListener: OnLongClickListener,          appName: CharSequence,          appIcon: Drawable  ) : DesktopModeWindowDecorationViewHolder(rootView) { @@ -39,6 +41,7 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(          openMenuButton.setOnTouchListener(onCaptionTouchListener)          closeWindowButton.setOnClickListener(onCaptionButtonClickListener)          maximizeWindowButton.setOnClickListener(onCaptionButtonClickListener) +        maximizeWindowButton.onLongClickListener = onLongClickListener          closeWindowButton.setOnTouchListener(onCaptionTouchListener)          appNameTextView.text = appName          appIconImageView.setImageDrawable(appIcon) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java index 596d6dd3a3d2..7f0465a24a18 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java @@ -48,6 +48,7 @@ import android.view.SurfaceView;  import androidx.test.filters.SmallTest; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer;  import com.android.wm.shell.ShellTaskOrganizer;  import com.android.wm.shell.ShellTestCase;  import com.android.wm.shell.TestRunningTaskInfoBuilder; @@ -100,6 +101,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {      @Mock private ShellInit mShellInit;      @Mock private DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener              mDesktopModeKeyguardChangeListener; +    @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;      private final List<InputManager> mMockInputManagers = new ArrayList<>();      private DesktopModeWindowDecorViewModel mDesktopModeWindowDecorViewModel; @@ -109,27 +111,28 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {          mMockInputManagers.add(mInputManager);          mDesktopModeWindowDecorViewModel = -            new DesktopModeWindowDecorViewModel( -                mContext, -                mMainHandler, -                mMainChoreographer, -                mShellInit, -                mTaskOrganizer, -                mDisplayController, -                mShellController, -                mSyncQueue, -                mTransitions, -                Optional.of(mDesktopModeController), -                Optional.of(mDesktopTasksController), -                mDesktopModeWindowDecorFactory, -                mMockInputMonitorFactory, -                mTransactionFactory, -                mDesktopModeKeyguardChangeListener -            ); +                new DesktopModeWindowDecorViewModel( +                        mContext, +                        mMainHandler, +                        mMainChoreographer, +                        mShellInit, +                        mTaskOrganizer, +                        mDisplayController, +                        mShellController, +                        mSyncQueue, +                        mTransitions, +                        Optional.of(mDesktopModeController), +                        Optional.of(mDesktopTasksController), +                        mDesktopModeWindowDecorFactory, +                        mMockInputMonitorFactory, +                        mTransactionFactory, +                        mDesktopModeKeyguardChangeListener, +                        mRootTaskDisplayAreaOrganizer +                );          doReturn(mDesktopModeWindowDecoration) -            .when(mDesktopModeWindowDecorFactory) -            .create(any(), any(), any(), any(), any(), any(), any(), any()); +                .when(mDesktopModeWindowDecorFactory) +                .create(any(), any(), any(), any(), any(), any(), any(), any(), any());          doReturn(mTransaction).when(mTransactionFactory).get();          doReturn(mDisplayLayout).when(mDisplayController).getDisplayLayout(anyInt());          doReturn(STABLE_INSETS).when(mDisplayLayout).stableInsets(); @@ -172,7 +175,8 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {                          surfaceControl,                          mMainHandler,                          mMainChoreographer, -                        mSyncQueue); +                        mSyncQueue, +                        mRootTaskDisplayAreaOrganizer);          verify(mDesktopModeWindowDecoration).close();      } @@ -205,7 +209,8 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {                          surfaceControl,                          mMainHandler,                          mMainChoreographer, -                        mSyncQueue); +                        mSyncQueue, +                        mRootTaskDisplayAreaOrganizer);      }      @Test @@ -291,7 +296,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {                      taskInfo, surfaceControl, startT, finishT);          });          verify(mDesktopModeWindowDecorFactory, never()) -                .create(any(), any(), any(), any(), any(), any(), any(), any()); +                .create(any(), any(), any(), any(), any(), any(), any(), any(), any());      }      private void runOnMainThread(Runnable r) throws Exception { @@ -307,10 +312,10 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {      private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId,              int displayId, @WindowConfiguration.WindowingMode int windowingMode) {          ActivityManager.RunningTaskInfo taskInfo = -                 new TestRunningTaskInfoBuilder() -                .setDisplayId(displayId) -                .setVisible(true) -                .build(); +                new TestRunningTaskInfoBuilder() +                        .setDisplayId(displayId) +                        .setVisible(true) +                        .build();          taskInfo.taskId = taskId;          taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);          return taskInfo;  |