summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java536
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt491
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt16
6 files changed, 519 insertions, 563 deletions
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 5ffd883a7ceb..5d662b20ebb9 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
@@ -852,18 +852,19 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
*/
void createHandleMenu(SplitScreenController splitScreenController) {
loadAppInfoIfNeeded();
- mHandleMenu = new HandleMenu.Builder(this)
- .setAppIcon(mAppIconBitmap)
- .setAppName(mAppName)
- .setOnClickListener(mOnCaptionButtonClickListener)
- .setOnTouchListener(mOnCaptionTouchListener)
- .setLayoutId(mRelayoutParams.mLayoutResId)
- .setWindowingButtonsVisible(DesktopModeStatus.canEnterDesktopMode(mContext))
- .setCaptionHeight(mResult.mCaptionHeight)
- .setDisplayController(mDisplayController)
- .setSplitScreenController(splitScreenController)
- .setBrowserLinkAvailable(browserLinkAvailable())
- .build();
+ mHandleMenu = new HandleMenu(
+ this,
+ mRelayoutParams.mLayoutResId,
+ mOnCaptionButtonClickListener,
+ mOnCaptionTouchListener,
+ mAppIconBitmap,
+ mAppName,
+ mDisplayController,
+ splitScreenController,
+ DesktopModeStatus.canEnterDesktopMode(mContext),
+ browserLinkAvailable(),
+ mResult.mCaptionHeight
+ );
mWindowDecorViewHolder.onHandleMenuOpened();
mHandleMenu.show();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
deleted file mode 100644
index bf311499f8d2..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * 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 static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_UP;
-
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.view.MotionEvent;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.window.SurfaceSyncGroup;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.window.flags.Flags;
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
-import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
-
-/**
- * Handle menu opened when the appropriate button is clicked on.
- *
- * Displays up to 3 pills that show the following:
- * App Info: App name, app icon, and collapse button to close the menu.
- * Windowing Options(Proto 2 only): Buttons to change windowing modes.
- * Additional Options: Miscellaneous functions including screenshot and closing task.
- */
-class HandleMenu {
- private static final String TAG = "HandleMenu";
- private static final boolean SHOULD_SHOW_MORE_ACTIONS_PILL = false;
- private final Context mContext;
- private final DesktopModeWindowDecoration mParentDecor;
- @VisibleForTesting
- AdditionalViewContainer mHandleMenuViewContainer;
- // Position of the handle menu used for laying out the handle view.
- @VisibleForTesting
- final PointF mHandleMenuPosition = new PointF();
- // With the introduction of {@link AdditionalSystemViewContainer}, {@link mHandleMenuPosition}
- // may be in a different coordinate space than the input coordinates. Therefore, we still care
- // about the menu's coordinates relative to the display as a whole, so we need to maintain
- // those as well.
- final Point mGlobalMenuPosition = new Point();
- private final boolean mShouldShowWindowingPill;
- private final boolean mShouldShowBrowserPill;
- private final Bitmap mAppIconBitmap;
- private final CharSequence mAppName;
- private final View.OnClickListener mOnClickListener;
- private final View.OnTouchListener mOnTouchListener;
- private final RunningTaskInfo mTaskInfo;
- private final DisplayController mDisplayController;
- private final SplitScreenController mSplitScreenController;
- private final int mLayoutResId;
- private int mMarginMenuTop;
- private int mMarginMenuStart;
- private int mMenuHeight;
- private int mMenuWidth;
- private final int mCaptionHeight;
- private HandleMenuAnimator mHandleMenuAnimator;
-
-
- HandleMenu(DesktopModeWindowDecoration parentDecor, int layoutResId,
- View.OnClickListener onClickListener, View.OnTouchListener onTouchListener,
- Bitmap appIcon, CharSequence appName, DisplayController displayController,
- SplitScreenController splitScreenController, boolean shouldShowWindowingPill,
- boolean shouldShowBrowserPill, int captionHeight) {
- mParentDecor = parentDecor;
- mContext = mParentDecor.mDecorWindowContext;
- mTaskInfo = mParentDecor.mTaskInfo;
- mDisplayController = displayController;
- mSplitScreenController = splitScreenController;
- mLayoutResId = layoutResId;
- mOnClickListener = onClickListener;
- mOnTouchListener = onTouchListener;
- mAppIconBitmap = appIcon;
- mAppName = appName;
- mShouldShowWindowingPill = shouldShowWindowingPill;
- mShouldShowBrowserPill = shouldShowBrowserPill;
- mCaptionHeight = captionHeight;
- loadHandleMenuDimensions();
- updateHandleMenuPillPositions();
- }
-
- void show() {
- final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG);
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-
- createHandleMenuViewContainer(t, ssg);
- ssg.addTransaction(t);
- ssg.markSyncReady();
- setupHandleMenu();
- animateHandleMenu();
- }
-
- private void createHandleMenuViewContainer(SurfaceControl.Transaction t,
- SurfaceSyncGroup ssg) {
- final int x = (int) mHandleMenuPosition.x;
- final int y = (int) mHandleMenuPosition.y;
- if (!mTaskInfo.isFreeform() && Flags.enableAdditionalWindowsAboveStatusBar()) {
- mHandleMenuViewContainer = new AdditionalSystemViewContainer(mContext,
- R.layout.desktop_mode_window_decor_handle_menu, mTaskInfo.taskId,
- x, y, mMenuWidth, mMenuHeight);
- } else {
- mHandleMenuViewContainer = mParentDecor.addWindow(
- R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
- t, ssg, x, y, mMenuWidth, mMenuHeight);
- }
- final View handleMenuView = mHandleMenuViewContainer.getView();
- mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight);
- }
-
- /**
- * Animates the appearance of the handle menu and its three pills.
- */
- private void animateHandleMenu() {
- if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- mHandleMenuAnimator.animateCaptionHandleExpandToOpen();
- } else {
- mHandleMenuAnimator.animateOpen();
- }
- }
-
- /**
- * Set up all three pills of the handle menu: app info pill, windowing pill, & more actions
- * pill.
- */
- private void setupHandleMenu() {
- final View handleMenu = mHandleMenuViewContainer.getView();
- handleMenu.setOnTouchListener(mOnTouchListener);
- setupAppInfoPill(handleMenu);
- if (mShouldShowWindowingPill) {
- setupWindowingPill(handleMenu);
- }
- setupMoreActionsPill(handleMenu);
- setupOpenInBrowserPill(handleMenu);
- }
-
- /**
- * Set up interactive elements of handle menu's app info pill.
- */
- private void setupAppInfoPill(View handleMenu) {
- final HandleMenuImageButton collapseBtn =
- handleMenu.findViewById(R.id.collapse_menu_button);
- final ImageView appIcon = handleMenu.findViewById(R.id.application_icon);
- final TextView appName = handleMenu.findViewById(R.id.application_name);
- collapseBtn.setOnClickListener(mOnClickListener);
- collapseBtn.setTaskInfo(mTaskInfo);
- appIcon.setImageBitmap(mAppIconBitmap);
- appName.setText(mAppName);
- }
-
- /**
- * Set up interactive elements and color of handle menu's windowing pill.
- */
- private void setupWindowingPill(View handleMenu) {
- final ImageButton fullscreenBtn = handleMenu.findViewById(
- R.id.fullscreen_button);
- final ImageButton splitscreenBtn = handleMenu.findViewById(
- R.id.split_screen_button);
- final ImageButton floatingBtn = handleMenu.findViewById(R.id.floating_button);
- // TODO: Remove once implemented.
- floatingBtn.setVisibility(View.GONE);
-
- final ImageButton desktopBtn = handleMenu.findViewById(R.id.desktop_button);
- fullscreenBtn.setOnClickListener(mOnClickListener);
- splitscreenBtn.setOnClickListener(mOnClickListener);
- floatingBtn.setOnClickListener(mOnClickListener);
- desktopBtn.setOnClickListener(mOnClickListener);
- // The button corresponding to the windowing mode that the task is currently in uses a
- // different color than the others.
- final ColorStateList[] iconColors = getWindowingIconColor();
- final ColorStateList inActiveColorStateList = iconColors[0];
- final ColorStateList activeColorStateList = iconColors[1];
- final int windowingMode = mTaskInfo.getWindowingMode();
- fullscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_FULLSCREEN
- ? activeColorStateList : inActiveColorStateList);
- splitscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_MULTI_WINDOW
- ? activeColorStateList : inActiveColorStateList);
- floatingBtn.setImageTintList(windowingMode == WINDOWING_MODE_PINNED
- ? activeColorStateList : inActiveColorStateList);
- desktopBtn.setImageTintList(windowingMode == WINDOWING_MODE_FREEFORM
- ? activeColorStateList : inActiveColorStateList);
- }
-
- /**
- * Set up interactive elements & height of handle menu's more actions pill
- */
- private void setupMoreActionsPill(View handleMenu) {
- if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
- handleMenu.findViewById(R.id.more_actions_pill).setVisibility(View.GONE);
- }
- }
-
- private void setupOpenInBrowserPill(View handleMenu) {
- if (!mShouldShowBrowserPill) {
- handleMenu.findViewById(R.id.open_in_browser_pill).setVisibility(View.GONE);
- return;
- }
- final Button browserButton = handleMenu.findViewById(R.id.open_in_browser_button);
- browserButton.setOnClickListener(mOnClickListener);
- }
-
- /**
- * Returns array of windowing icon color based on current UI theme. First element of the
- * array is for inactive icons and the second is for active icons.
- */
- private ColorStateList[] getWindowingIconColor() {
- final int mode = mContext.getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK;
- final boolean isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES);
- final TypedArray typedArray = mContext.obtainStyledAttributes(new int[]{
- com.android.internal.R.attr.materialColorOnSurface,
- com.android.internal.R.attr.materialColorPrimary});
- final int inActiveColor = typedArray.getColor(0, isNightMode ? Color.WHITE : Color.BLACK);
- final int activeColor = typedArray.getColor(1, isNightMode ? Color.WHITE : Color.BLACK);
- typedArray.recycle();
- return new ColorStateList[]{ColorStateList.valueOf(inActiveColor),
- ColorStateList.valueOf(activeColor)};
- }
-
- /**
- * Updates handle menu's position variables to reflect its next position.
- */
- private void updateHandleMenuPillPositions() {
- int menuX;
- final int menuY;
- final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
- updateGlobalMenuPosition(taskBounds);
- if (mLayoutResId == R.layout.desktop_mode_app_header) {
- // Align the handle menu to the left side of the caption.
- menuX = mMarginMenuStart;
- menuY = mMarginMenuTop;
- } else {
- if (Flags.enableAdditionalWindowsAboveStatusBar()) {
- // In a focused decor, we use global coordinates for handle menu. Therefore we
- // need to account for other factors like split stage and menu/handle width to
- // center the menu.
- menuX = mGlobalMenuPosition.x;
- menuY = mGlobalMenuPosition.y;
- } else {
- menuX = (taskBounds.width() / 2) - (mMenuWidth / 2);
- menuY = mMarginMenuTop;
- }
- }
- // Handle Menu position setup.
- mHandleMenuPosition.set(menuX, menuY);
- }
-
- private void updateGlobalMenuPosition(Rect taskBounds) {
- if (mTaskInfo.isFreeform()) {
- mGlobalMenuPosition.set(taskBounds.left + mMarginMenuStart,
- taskBounds.top + mMarginMenuTop);
- } else if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- mGlobalMenuPosition.set(
- (taskBounds.width() / 2) - (mMenuWidth / 2),
- mMarginMenuTop
- );
- } else if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- final int splitPosition = mSplitScreenController.getSplitPosition(mTaskInfo.taskId);
- final Rect leftOrTopStageBounds = new Rect();
- final Rect rightOrBottomStageBounds = new Rect();
- mSplitScreenController.getStageBounds(leftOrTopStageBounds,
- rightOrBottomStageBounds);
- // TODO(b/343561161): This needs to be calculated differently if the task is in
- // top/bottom split.
- if (splitPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
- mGlobalMenuPosition.set(leftOrTopStageBounds.width()
- + (rightOrBottomStageBounds.width() / 2)
- - (mMenuWidth / 2),
- mMarginMenuTop);
- } else if (splitPosition == SPLIT_POSITION_TOP_OR_LEFT) {
- mGlobalMenuPosition.set((leftOrTopStageBounds.width() / 2)
- - (mMenuWidth / 2),
- mMarginMenuTop);
- }
- }
- }
-
- /**
- * Update pill layout, in case task changes have caused positioning to change.
- */
- void relayout(SurfaceControl.Transaction t) {
- if (mHandleMenuViewContainer != null) {
- updateHandleMenuPillPositions();
- mHandleMenuViewContainer.setPosition(t, mHandleMenuPosition.x, mHandleMenuPosition.y);
- }
- }
-
- /**
- * Check a passed MotionEvent if a click or hover has occurred on any button on this caption
- * Note this should only be called when a regular onClick/onHover is not possible
- * (i.e. the button was clicked through status bar layer)
- *
- * @param ev the MotionEvent to compare against.
- */
- void checkMotionEvent(MotionEvent ev) {
- // If the menu view is above status bar, we can let the views handle input directly.
- if (isViewAboveStatusBar()) return;
- final View handleMenu = mHandleMenuViewContainer.getView();
- final HandleMenuImageButton collapse = handleMenu.findViewById(R.id.collapse_menu_button);
- final PointF inputPoint = translateInputToLocalSpace(ev);
- final boolean inputInCollapseButton = pointInView(collapse, inputPoint.x, inputPoint.y);
- final int action = ev.getActionMasked();
- collapse.setHovered(inputInCollapseButton && action != ACTION_UP);
- collapse.setPressed(inputInCollapseButton && action == ACTION_DOWN);
- if (action == ACTION_UP && inputInCollapseButton) {
- collapse.performClick();
- }
- }
-
- private boolean isViewAboveStatusBar() {
- return Flags.enableAdditionalWindowsAboveStatusBar()
- && !mTaskInfo.isFreeform();
- }
-
- // Translate the input point from display coordinates to the same space as the handle menu.
- private PointF translateInputToLocalSpace(MotionEvent ev) {
- return new PointF(ev.getX() - mHandleMenuPosition.x,
- ev.getY() - mHandleMenuPosition.y);
- }
-
- /**
- * A valid menu input is one of the following:
- * An input that happens in the menu views.
- * Any input before the views have been laid out.
- *
- * @param inputPoint the input to compare against.
- */
- boolean isValidMenuInput(PointF inputPoint) {
- if (!viewsLaidOut()) return true;
- if (!isViewAboveStatusBar()) {
- return pointInView(
- mHandleMenuViewContainer.getView(),
- inputPoint.x - mHandleMenuPosition.x,
- inputPoint.y - mHandleMenuPosition.y);
- } else {
- // Handle menu exists in a different coordinate space when added to WindowManager.
- // Therefore we must compare the provided input coordinates to global menu coordinates.
- // This includes factoring for split stage as input coordinates are relative to split
- // stage position, not relative to the display as a whole.
- PointF inputRelativeToMenu = new PointF(
- inputPoint.x - mGlobalMenuPosition.x,
- inputPoint.y - mGlobalMenuPosition.y
- );
- if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId)
- == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
- // TODO(b/343561161): This also needs to be calculated differently if
- // the task is in top/bottom split.
- Rect leftStageBounds = new Rect();
- mSplitScreenController.getStageBounds(leftStageBounds, new Rect());
- inputRelativeToMenu.x += leftStageBounds.width();
- }
- return pointInView(
- mHandleMenuViewContainer.getView(),
- inputRelativeToMenu.x,
- inputRelativeToMenu.y);
- }
- }
-
- private boolean pointInView(View v, float x, float y) {
- return v != null && v.getLeft() <= x && v.getRight() >= x
- && v.getTop() <= y && v.getBottom() >= y;
- }
-
- /**
- * Check if the views for handle menu can be seen.
- */
- private boolean viewsLaidOut() {
- return mHandleMenuViewContainer.getView().isLaidOut();
- }
-
- private void loadHandleMenuDimensions() {
- final Resources resources = mContext.getResources();
- mMenuWidth = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_width);
- mMenuHeight = getHandleMenuHeight(resources);
- mMarginMenuTop = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_top);
- mMarginMenuStart = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_start);
- }
-
- /**
- * Determines handle menu height based on if windowing pill should be shown.
- */
- private int getHandleMenuHeight(Resources resources) {
- int menuHeight = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_height);
- if (!mShouldShowWindowingPill) {
- menuHeight -= loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_windowing_pill_height);
- }
- if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
- menuHeight -= loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
- }
- if (!mShouldShowBrowserPill) {
- menuHeight -= loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_open_in_browser_pill_height);
- }
- return menuHeight;
- }
-
- private int loadDimensionPixelSize(Resources resources, int resourceId) {
- if (resourceId == Resources.ID_NULL) {
- return 0;
- }
- return resources.getDimensionPixelSize(resourceId);
- }
-
- void close() {
- final Runnable after = () -> {
- mHandleMenuViewContainer.releaseView();
- mHandleMenuViewContainer = null;
- };
- if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- mHandleMenuAnimator.animateCollapseIntoHandleClose(after);
- } else {
- mHandleMenuAnimator.animateClose(after);
- }
- }
-
- static final class Builder {
- private final DesktopModeWindowDecoration mParent;
- private CharSequence mName;
- private Bitmap mAppIcon;
- private View.OnClickListener mOnClickListener;
- private View.OnTouchListener mOnTouchListener;
- private int mLayoutId;
- private boolean mShowWindowingPill;
- private int mCaptionHeight;
- private DisplayController mDisplayController;
- private SplitScreenController mSplitScreenController;
- private boolean mShowBrowserPill;
-
- Builder(@NonNull DesktopModeWindowDecoration parent) {
- mParent = parent;
- }
-
- Builder setAppName(@Nullable CharSequence name) {
- mName = name;
- return this;
- }
-
- Builder setAppIcon(@Nullable Bitmap appIcon) {
- mAppIcon = appIcon;
- return this;
- }
-
- Builder setOnClickListener(@Nullable View.OnClickListener onClickListener) {
- mOnClickListener = onClickListener;
- return this;
- }
-
- Builder setOnTouchListener(@Nullable View.OnTouchListener onTouchListener) {
- mOnTouchListener = onTouchListener;
- return this;
- }
-
- Builder setLayoutId(int layoutId) {
- mLayoutId = layoutId;
- return this;
- }
-
- Builder setWindowingButtonsVisible(boolean windowingButtonsVisible) {
- mShowWindowingPill = windowingButtonsVisible;
- return this;
- }
-
- Builder setCaptionHeight(int captionHeight) {
- mCaptionHeight = captionHeight;
- return this;
- }
-
- Builder setDisplayController(DisplayController displayController) {
- mDisplayController = displayController;
- return this;
- }
-
- Builder setSplitScreenController(SplitScreenController splitScreenController) {
- mSplitScreenController = splitScreenController;
- return this;
- }
-
- Builder setBrowserLinkAvailable(Boolean showBrowserPill) {
- mShowBrowserPill = showBrowserPill;
- return this;
- }
-
- HandleMenu build() {
- return new HandleMenu(mParent, mLayoutId, mOnClickListener,
- mOnTouchListener, mAppIcon, mName, mDisplayController, mSplitScreenController,
- mShowWindowingPill, mShowBrowserPill, mCaptionHeight);
- }
- }
-}
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
new file mode 100644
index 000000000000..39595cf77951
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -0,0 +1,491 @@
+/*
+ * 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
+import android.app.WindowConfiguration
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
+import android.content.Context
+import android.content.res.ColorStateList
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.view.MotionEvent
+import android.view.SurfaceControl
+import android.view.View
+import android.widget.Button
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.TextView
+import android.window.SurfaceSyncGroup
+import androidx.annotation.VisibleForTesting
+import com.android.window.flags.Flags
+import com.android.wm.shell.R
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.split.SplitScreenConstants
+import com.android.wm.shell.splitscreen.SplitScreenController
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
+import com.android.wm.shell.windowdecor.extension.isFullscreen
+
+/**
+ * Handle menu opened when the appropriate button is clicked on.
+ *
+ * Displays up to 3 pills that show the following:
+ * App Info: App name, app icon, and collapse button to close the menu.
+ * Windowing Options(Proto 2 only): Buttons to change windowing modes.
+ * Additional Options: Miscellaneous functions including screenshot and closing task.
+ */
+class HandleMenu(
+ private val parentDecor: DesktopModeWindowDecoration,
+ private val layoutResId: Int,
+ private val onClickListener: View.OnClickListener?,
+ private val onTouchListener: View.OnTouchListener?,
+ private val appIconBitmap: Bitmap?,
+ private val appName: CharSequence?,
+ private val displayController: DisplayController,
+ private val splitScreenController: SplitScreenController,
+ private val shouldShowWindowingPill: Boolean,
+ private val shouldShowBrowserPill: Boolean,
+ private val captionHeight: Int
+) {
+ private val context: Context = parentDecor.mDecorWindowContext
+ private val taskInfo: ActivityManager.RunningTaskInfo = parentDecor.mTaskInfo
+
+ private val isViewAboveStatusBar: Boolean
+ get() = (Flags.enableAdditionalWindowsAboveStatusBar() && !taskInfo.isFreeform)
+
+ private var marginMenuTop = 0
+ private var marginMenuStart = 0
+ private var menuHeight = 0
+ private var menuWidth = 0
+ private var handleMenuAnimator: HandleMenuAnimator? = null
+
+ @VisibleForTesting
+ var handleMenuViewContainer: AdditionalViewContainer? = null
+
+ // Position of the handle menu used for laying out the handle view.
+ @VisibleForTesting
+ val handleMenuPosition: PointF = PointF()
+
+ // With the introduction of {@link AdditionalSystemViewContainer}, {@link mHandleMenuPosition}
+ // may be in a different coordinate space than the input coordinates. Therefore, we still care
+ // about the menu's coordinates relative to the display as a whole, so we need to maintain
+ // those as well.
+ private val globalMenuPosition: Point = Point()
+
+ /**
+ * An a array of windowing icon color based on current UI theme. First element of the
+ * array is for inactive icons and the second is for active icons.
+ */
+ private val windowingIconColor: Array<ColorStateList>
+ get() {
+ val mode = (context.resources.configuration.uiMode
+ and Configuration.UI_MODE_NIGHT_MASK)
+ val isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES)
+ val typedArray = context.obtainStyledAttributes(
+ intArrayOf(
+ com.android.internal.R.attr.materialColorOnSurface,
+ com.android.internal.R.attr.materialColorPrimary
+ )
+ )
+ val inActiveColor =
+ typedArray.getColor(0, if (isNightMode) Color.WHITE else Color.BLACK)
+ val activeColor = typedArray.getColor(1, if (isNightMode) Color.WHITE else Color.BLACK)
+ typedArray.recycle()
+ return arrayOf(
+ ColorStateList.valueOf(inActiveColor),
+ ColorStateList.valueOf(activeColor)
+ )
+ }
+
+ init {
+ loadHandleMenuDimensions()
+ updateHandleMenuPillPositions()
+ }
+
+ fun show() {
+ val ssg = SurfaceSyncGroup(TAG)
+ val t = SurfaceControl.Transaction()
+
+ createHandleMenuViewContainer(t, ssg)
+ ssg.addTransaction(t)
+ ssg.markSyncReady()
+ setupHandleMenu()
+ animateHandleMenu()
+ }
+
+ private fun createHandleMenuViewContainer(
+ t: SurfaceControl.Transaction,
+ ssg: SurfaceSyncGroup
+ ) {
+ val x = handleMenuPosition.x.toInt()
+ val y = handleMenuPosition.y.toInt()
+ handleMenuViewContainer =
+ if (!taskInfo.isFreeform && Flags.enableAdditionalWindowsAboveStatusBar()) {
+ AdditionalSystemViewContainer(
+ context = context,
+ layoutId = R.layout.desktop_mode_window_decor_handle_menu,
+ taskId = taskInfo.taskId,
+ x = x,
+ y = y,
+ width = menuWidth,
+ height = menuHeight
+ )
+ } else {
+ parentDecor.addWindow(
+ R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
+ t, ssg, x, y, menuWidth, menuHeight
+ )
+ }
+ handleMenuViewContainer?.view?.let { view ->
+ handleMenuAnimator =
+ HandleMenuAnimator(view, menuWidth, captionHeight.toFloat())
+ }
+ }
+
+ /**
+ * Animates the appearance of the handle menu and its three pills.
+ */
+ private fun animateHandleMenu() {
+ when (taskInfo.windowingMode) {
+ WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ WINDOWING_MODE_MULTI_WINDOW -> {
+ handleMenuAnimator?.animateCaptionHandleExpandToOpen()
+ }
+ else -> {
+ handleMenuAnimator?.animateOpen()
+ }
+ }
+ }
+
+ /**
+ * Set up all three pills of the handle menu: app info pill, windowing pill, & more actions
+ * pill.
+ */
+ private fun setupHandleMenu() {
+ val handleMenu = handleMenuViewContainer?.view ?: return
+ handleMenu.setOnTouchListener(onTouchListener)
+ setupAppInfoPill(handleMenu)
+ if (shouldShowWindowingPill) {
+ setupWindowingPill(handleMenu)
+ }
+ setupMoreActionsPill(handleMenu)
+ setupOpenInBrowserPill(handleMenu)
+ }
+
+ /**
+ * Set up interactive elements of handle menu's app info pill.
+ */
+ private fun setupAppInfoPill(handleMenu: View) {
+ val collapseBtn = handleMenu.findViewById<HandleMenuImageButton>(R.id.collapse_menu_button)
+ val appIcon = handleMenu.findViewById<ImageView>(R.id.application_icon)
+ val appName = handleMenu.findViewById<TextView>(R.id.application_name)
+ collapseBtn.setOnClickListener(onClickListener)
+ collapseBtn.taskInfo = taskInfo
+ appIcon.setImageBitmap(appIconBitmap)
+ appName.text = this.appName
+ }
+
+ /**
+ * Set up interactive elements and color of handle menu's windowing pill.
+ */
+ private fun setupWindowingPill(handleMenu: View) {
+ val fullscreenBtn = handleMenu.findViewById<ImageButton>(R.id.fullscreen_button)
+ val splitscreenBtn = handleMenu.findViewById<ImageButton>(R.id.split_screen_button)
+ val floatingBtn = handleMenu.findViewById<ImageButton>(R.id.floating_button)
+ // TODO: Remove once implemented.
+ floatingBtn.visibility = View.GONE
+
+ val desktopBtn = handleMenu.findViewById<ImageButton>(R.id.desktop_button)
+ fullscreenBtn.setOnClickListener(onClickListener)
+ splitscreenBtn.setOnClickListener(onClickListener)
+ floatingBtn.setOnClickListener(onClickListener)
+ desktopBtn.setOnClickListener(onClickListener)
+ // The button corresponding to the windowing mode that the task is currently in uses a
+ // different color than the others.
+ val iconColors = windowingIconColor
+ val inActiveColorStateList = iconColors[0]
+ val activeColorStateList = iconColors[1]
+ fullscreenBtn.imageTintList = if (taskInfo.isFullscreen) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ splitscreenBtn.imageTintList = if (taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ floatingBtn.imageTintList = if (taskInfo.windowingMode == WINDOWING_MODE_PINNED) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ desktopBtn.imageTintList = if (taskInfo.isFreeform) {
+ activeColorStateList
+ } else {
+ inActiveColorStateList
+ }
+ }
+
+ /**
+ * Set up interactive elements & height of handle menu's more actions pill
+ */
+ private fun setupMoreActionsPill(handleMenu: View) {
+ if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
+ handleMenu.findViewById<View>(R.id.more_actions_pill).visibility = View.GONE
+ }
+ }
+
+ private fun setupOpenInBrowserPill(handleMenu: View) {
+ if (!shouldShowBrowserPill) {
+ handleMenu.findViewById<View>(R.id.open_in_browser_pill).visibility = View.GONE
+ return
+ }
+ val browserButton = handleMenu.findViewById<Button>(R.id.open_in_browser_button)
+ browserButton.setOnClickListener(onClickListener)
+ }
+
+ /**
+ * Updates handle menu's position variables to reflect its next position.
+ */
+ private fun updateHandleMenuPillPositions() {
+ val menuX: Int
+ val menuY: Int
+ val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds
+ updateGlobalMenuPosition(taskBounds)
+ if (layoutResId == R.layout.desktop_mode_app_header) {
+ // Align the handle menu to the left side of the caption.
+ menuX = marginMenuStart
+ menuY = marginMenuTop
+ } else {
+ if (Flags.enableAdditionalWindowsAboveStatusBar()) {
+ // In a focused decor, we use global coordinates for handle menu. Therefore we
+ // need to account for other factors like split stage and menu/handle width to
+ // center the menu.
+ menuX = globalMenuPosition.x
+ menuY = globalMenuPosition.y
+ } else {
+ menuX = (taskBounds.width() / 2) - (menuWidth / 2)
+ menuY = marginMenuTop
+ }
+ }
+ // Handle Menu position setup.
+ handleMenuPosition.set(menuX.toFloat(), menuY.toFloat())
+ }
+
+ private fun updateGlobalMenuPosition(taskBounds: Rect) {
+ when (taskInfo.windowingMode) {
+ WINDOWING_MODE_FREEFORM -> {
+ globalMenuPosition.set(
+ /* x = */ taskBounds.left + marginMenuStart,
+ /* y = */ taskBounds.top + marginMenuTop
+ )
+ }
+ WINDOWING_MODE_FULLSCREEN -> {
+ globalMenuPosition.set(
+ /* x = */ taskBounds.width() / 2 - (menuWidth / 2),
+ /* y = */ marginMenuTop
+ )
+ }
+ WINDOWING_MODE_MULTI_WINDOW -> {
+ val splitPosition = splitScreenController.getSplitPosition(taskInfo.taskId)
+ val leftOrTopStageBounds = Rect()
+ val rightOrBottomStageBounds = Rect()
+ splitScreenController.getStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds)
+ // TODO(b/343561161): This needs to be calculated differently if the task is in
+ // top/bottom split.
+ when (splitPosition) {
+ SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> {
+ globalMenuPosition.set(
+ /* x = */ leftOrTopStageBounds.width()
+ + (rightOrBottomStageBounds.width() / 2)
+ - (menuWidth / 2),
+ /* y = */ marginMenuTop
+ )
+ }
+ SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> {
+ globalMenuPosition.set(
+ /* x = */ (leftOrTopStageBounds.width() / 2)
+ - (menuWidth / 2),
+ /* y = */ marginMenuTop
+ )
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Update pill layout, in case task changes have caused positioning to change.
+ */
+ fun relayout(t: SurfaceControl.Transaction) {
+ handleMenuViewContainer?.let { container ->
+ updateHandleMenuPillPositions()
+ container.setPosition(t, handleMenuPosition.x, handleMenuPosition.y)
+ }
+ }
+
+ /**
+ * Check a passed MotionEvent if a click or hover has occurred on any button on this caption
+ * Note this should only be called when a regular onClick/onHover is not possible
+ * (i.e. the button was clicked through status bar layer)
+ *
+ * @param ev the MotionEvent to compare against.
+ */
+ fun checkMotionEvent(ev: MotionEvent) {
+ // If the menu view is above status bar, we can let the views handle input directly.
+ if (isViewAboveStatusBar) return
+ val handleMenu = handleMenuViewContainer?.view ?: return
+ val collapse = handleMenu.findViewById<HandleMenuImageButton>(R.id.collapse_menu_button)
+ val inputPoint = translateInputToLocalSpace(ev)
+ val inputInCollapseButton = pointInView(collapse, inputPoint.x, inputPoint.y)
+ val action = ev.actionMasked
+ collapse.isHovered = inputInCollapseButton && action != MotionEvent.ACTION_UP
+ collapse.isPressed = inputInCollapseButton && action == MotionEvent.ACTION_DOWN
+ if (action == MotionEvent.ACTION_UP && inputInCollapseButton) {
+ collapse.performClick()
+ }
+ }
+
+ // Translate the input point from display coordinates to the same space as the handle menu.
+ private fun translateInputToLocalSpace(ev: MotionEvent): PointF {
+ return PointF(
+ ev.x - handleMenuPosition.x,
+ ev.y - handleMenuPosition.y
+ )
+ }
+
+ /**
+ * A valid menu input is one of the following:
+ * An input that happens in the menu views.
+ * Any input before the views have been laid out.
+ *
+ * @param inputPoint the input to compare against.
+ */
+ fun isValidMenuInput(inputPoint: PointF): Boolean {
+ if (!viewsLaidOut()) return true
+ if (!isViewAboveStatusBar) {
+ return pointInView(
+ handleMenuViewContainer?.view,
+ inputPoint.x - handleMenuPosition.x,
+ inputPoint.y - handleMenuPosition.y
+ )
+ } else {
+ // Handle menu exists in a different coordinate space when added to WindowManager.
+ // Therefore we must compare the provided input coordinates to global menu coordinates.
+ // This includes factoring for split stage as input coordinates are relative to split
+ // stage position, not relative to the display as a whole.
+ val inputRelativeToMenu = PointF(
+ inputPoint.x - globalMenuPosition.x,
+ inputPoint.y - globalMenuPosition.y
+ )
+ if (splitScreenController.getSplitPosition(taskInfo.taskId)
+ == SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT) {
+ // TODO(b/343561161): This also needs to be calculated differently if
+ // the task is in top/bottom split.
+ val leftStageBounds = Rect()
+ splitScreenController.getStageBounds(leftStageBounds, Rect())
+ inputRelativeToMenu.x += leftStageBounds.width().toFloat()
+ }
+ return pointInView(
+ handleMenuViewContainer?.view,
+ inputRelativeToMenu.x,
+ inputRelativeToMenu.y
+ )
+ }
+ }
+
+ private fun pointInView(v: View?, x: Float, y: Float): Boolean {
+ return v != null && v.left <= x && v.right >= x && v.top <= y && v.bottom >= y
+ }
+
+ /**
+ * Check if the views for handle menu can be seen.
+ */
+ private fun viewsLaidOut(): Boolean = handleMenuViewContainer?.view?.isLaidOut ?: false
+
+ private fun loadHandleMenuDimensions() {
+ val resources = context.resources
+ menuWidth = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_width)
+ menuHeight = getHandleMenuHeight(resources)
+ marginMenuTop = loadDimensionPixelSize(
+ resources,
+ R.dimen.desktop_mode_handle_menu_margin_top
+ )
+ marginMenuStart = loadDimensionPixelSize(
+ resources,
+ R.dimen.desktop_mode_handle_menu_margin_start
+ )
+ }
+
+ /**
+ * Determines handle menu height based on if windowing pill should be shown.
+ */
+ private fun getHandleMenuHeight(resources: Resources): Int {
+ var menuHeight = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_height)
+ if (!shouldShowWindowingPill) {
+ menuHeight -= loadDimensionPixelSize(
+ resources,
+ R.dimen.desktop_mode_handle_menu_windowing_pill_height
+ )
+ }
+ if (!SHOULD_SHOW_MORE_ACTIONS_PILL) {
+ menuHeight -= loadDimensionPixelSize(
+ resources,
+ R.dimen.desktop_mode_handle_menu_more_actions_pill_height
+ )
+ }
+ if (!shouldShowBrowserPill) {
+ menuHeight -= loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_open_in_browser_pill_height)
+ }
+ return menuHeight
+ }
+
+ private fun loadDimensionPixelSize(resources: Resources, resourceId: Int): Int {
+ if (resourceId == Resources.ID_NULL) {
+ return 0
+ }
+ return resources.getDimensionPixelSize(resourceId)
+ }
+
+ fun close() {
+ val after = {
+ handleMenuViewContainer?.releaseView()
+ handleMenuViewContainer = null
+ }
+ if (taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN ||
+ taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ handleMenuAnimator?.animateCollapseIntoHandleClose(after)
+ } else {
+ handleMenuAnimator?.animateClose(after)
+ }
+ }
+
+ companion object {
+ private const val TAG = "HandleMenu"
+ private const val SHOULD_SHOW_MORE_ACTIONS_PILL = false
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
index 25a829b44448..e3d22342cc9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
@@ -108,7 +108,7 @@ class HandleMenuAnimator(
*
* @param after runs after the animation finishes.
*/
- fun animateCollapseIntoHandleClose(after: Runnable) {
+ fun animateCollapseIntoHandleClose(after: () -> Unit) {
appInfoCollapseToHandle()
animateAppInfoPillFadeOut()
windowingPillClose()
@@ -125,7 +125,7 @@ class HandleMenuAnimator(
* @param after runs after animation finishes.
*
*/
- fun animateClose(after: Runnable) {
+ fun animateClose(after: () -> Unit) {
appInfoPillCollapse()
animateAppInfoPillFadeOut()
windowingPillClose()
@@ -463,9 +463,9 @@ class HandleMenuAnimator(
*
* @param after runs after animation finishes.
*/
- private fun runAnimations(after: Runnable? = null) {
+ private fun runAnimations(after: (() -> Unit)? = null) {
runningAnimation?.apply {
- // Remove all listeners, so that after runnable isn't triggered upon cancel.
+ // Remove all listeners, so that the after function isn't triggered upon cancel.
removeAllListeners()
// If an animation runs while running animation is triggered, gracefully cancel.
cancel()
@@ -475,7 +475,7 @@ class HandleMenuAnimator(
playTogether(animators)
animators.clear()
doOnEnd {
- after?.run()
+ after?.invoke()
runningAnimation = null
}
start()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 03dbbb3bbb82..923c4dde5df7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -105,7 +105,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
* System-wide context. Only used to create context with overridden configurations.
*/
final Context mContext;
- final DisplayController mDisplayController;
+ final @NonNull DisplayController mDisplayController;
final ShellTaskOrganizer mTaskOrganizer;
final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
@@ -158,7 +158,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
WindowDecoration(
Context context,
- DisplayController displayController,
+ @NonNull DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
RunningTaskInfo taskInfo,
@NonNull SurfaceControl taskSurface,
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 cb73d1508281..e0e603ffb6f5 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
@@ -126,11 +126,11 @@ class HandleMenuTest : ShellTestCase() {
fun testFullscreenMenuUsesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_FULLSCREEN, SPLIT_POSITION_UNDEFINED)
val handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalSystemViewContainer)
// Verify menu is created at coordinates that, when added to WindowManager,
// show at the top-center of display.
val expected = Point(DISPLAY_BOUNDS.centerX() - MENU_WIDTH / 2, MENU_TOP_MARGIN)
- assertEquals(expected.toPointF(), handleMenu.mHandleMenuPosition)
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
@Test
@@ -138,10 +138,10 @@ class HandleMenuTest : ShellTestCase() {
fun testFreeformMenu_usesViewHostViewContainer() {
createTaskInfo(WINDOWING_MODE_FREEFORM, SPLIT_POSITION_UNDEFINED)
handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalViewHostViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalViewHostViewContainer)
// Verify menu is created near top-left of task.
val expected = Point(MENU_START_MARGIN, MENU_TOP_MARGIN)
- assertEquals(expected.toPointF(), handleMenu.mHandleMenuPosition)
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
@Test
@@ -149,11 +149,11 @@ class HandleMenuTest : ShellTestCase() {
fun testSplitLeftMenu_usesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_TOP_OR_LEFT)
handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalSystemViewContainer)
// Verify menu is created at coordinates that, when added to WindowManager,
// show at the top-center of split left task.
val expected = Point(SPLIT_LEFT_BOUNDS.centerX() - MENU_WIDTH / 2, MENU_TOP_MARGIN)
- assertEquals(expected.toPointF(), handleMenu.mHandleMenuPosition)
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
@Test
@@ -161,11 +161,11 @@ class HandleMenuTest : ShellTestCase() {
fun testSplitRightMenu_usesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_BOTTOM_OR_RIGHT)
handleMenu = createAndShowHandleMenu()
- assertTrue(handleMenu.mHandleMenuViewContainer is AdditionalSystemViewContainer)
+ assertTrue(handleMenu.handleMenuViewContainer is AdditionalSystemViewContainer)
// Verify menu is created at coordinates that, when added to WindowManager,
// show at the top-center of split right task.
val expected = Point(SPLIT_RIGHT_BOUNDS.centerX() - MENU_WIDTH / 2, MENU_TOP_MARGIN)
- assertEquals(expected.toPointF(), handleMenu.mHandleMenuPosition)
+ assertEquals(expected.toPointF(), handleMenu.handleMenuPosition)
}
private fun createTaskInfo(windowingMode: Int, splitPosition: Int) {