Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +1 −1 Original line number Diff line number Diff line Loading @@ -439,7 +439,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { if (!decoration.isHandleMenuActive()) { moveTaskToFront(decoration.mTaskInfo); decoration.createHandleMenu(); decoration.createHandleMenu(mSplitScreenController); } else { decoration.closeHandleMenu(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +13 −2 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ 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.shared.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; Loading Loading @@ -650,7 +651,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin /** * Create and display handle menu window. */ void createHandleMenu() { void createHandleMenu(SplitScreenController splitScreenController) { loadAppInfoIfNeeded(); mHandleMenu = new HandleMenu.Builder(this) .setAppIcon(mAppIconBitmap) Loading @@ -660,6 +661,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .setLayoutId(mRelayoutParams.mLayoutResId) .setWindowingButtonsVisible(DesktopModeStatus.canEnterDesktopMode(mContext)) .setCaptionHeight(mResult.mCaptionHeight) .setDisplayController(mDisplayController) .setSplitScreenController(splitScreenController) .build(); mWindowDecorViewHolder.onHandleMenuOpened(); mHandleMenu.show(); Loading Loading @@ -815,11 +818,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // We want handle to remain pressed if the pointer moves outside of it during a drag. handle.setPressed((inHandle && action == ACTION_DOWN) || (handle.isPressed() && action != ACTION_UP && action != ACTION_CANCEL)); if (isHandleMenuActive()) { if (isHandleMenuActive() && !isMenuAboveStatusBar()) { mHandleMenu.checkMotionEvent(ev); } } private boolean isMenuAboveStatusBar() { return Flags.enableAdditionalWindowsAboveStatusBar() && !mTaskInfo.isFreeform(); } private boolean pointInView(View v, float x, float y) { return v != null && v.getLeft() <= x && v.getRight() >= x && v.getTop() <= y && v.getBottom() >= y; Loading Loading @@ -868,6 +875,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return exclusionRegion; } int getCaptionX() { return mResult.mCaptionX; } @Override int getCaptionHeightId(@WindowingMode int windowingMode) { return getCaptionHeightIdStatic(windowingMode); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +97 −35 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ 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 android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; Loading @@ -34,6 +36,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PointF; import android.graphics.Rect; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; Loading @@ -42,7 +45,15 @@ 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.DisplayLayout; 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. Loading @@ -56,15 +67,19 @@ class HandleMenu { private static final String TAG = "HandleMenu"; private static final boolean SHOULD_SHOW_MORE_ACTIONS_PILL = false; private final Context mContext; private final WindowDecoration mParentDecor; private WindowDecoration.AdditionalWindow mHandleMenuWindow; private final PointF mHandleMenuPosition = new PointF(); private final DesktopModeWindowDecoration mParentDecor; @VisibleForTesting AdditionalViewContainer mHandleMenuViewContainer; @VisibleForTesting final PointF mHandleMenuPosition = new PointF(); private final boolean mShouldShowWindowingPill; 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; Loading @@ -74,12 +89,16 @@ class HandleMenu { private HandleMenuAnimator mHandleMenuAnimator; HandleMenu(WindowDecoration parentDecor, int layoutResId, View.OnClickListener onClickListener, View.OnTouchListener onTouchListener, Bitmap appIcon, CharSequence appName, boolean shouldShowWindowingPill, int captionHeight) { HandleMenu(DesktopModeWindowDecoration parentDecor, int layoutResId, View.OnClickListener onClickListener, View.OnTouchListener onTouchListener, Bitmap appIcon, CharSequence appName, DisplayController displayController, SplitScreenController splitScreenController, boolean shouldShowWindowingPill, int captionHeight) { mParentDecor = parentDecor; mContext = mParentDecor.mDecorWindowContext; mTaskInfo = mParentDecor.mTaskInfo; mDisplayController = displayController; mSplitScreenController = splitScreenController; mLayoutResId = layoutResId; mOnClickListener = onClickListener; mOnTouchListener = onTouchListener; Loading @@ -95,20 +114,27 @@ class HandleMenu { final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG); SurfaceControl.Transaction t = new SurfaceControl.Transaction(); createHandleMenuWindow(t, ssg); createHandleMenuViewContainer(t, ssg); ssg.addTransaction(t); ssg.markSyncReady(); setupHandleMenu(); animateHandleMenu(); } private void createHandleMenuWindow(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { private void createHandleMenuViewContainer(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { final int x = (int) mHandleMenuPosition.x; final int y = (int) mHandleMenuPosition.y; mHandleMenuWindow = mParentDecor.addWindow( 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 = mHandleMenuWindow.mWindowViewHost.getView(); } final View handleMenuView = mHandleMenuViewContainer.getView(); mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); } Loading @@ -129,7 +155,7 @@ class HandleMenu { * pill. */ private void setupHandleMenu() { final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); final View handleMenu = mHandleMenuViewContainer.getView(); handleMenu.setOnTouchListener(mOnTouchListener); setupAppInfoPill(handleMenu); if (mShouldShowWindowingPill) { Loading @@ -147,6 +173,7 @@ class HandleMenu { 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); } Loading Loading @@ -215,32 +242,55 @@ class HandleMenu { * Updates handle menu's position variables to reflect its next position. */ private void updateHandleMenuPillPositions() { final int menuX, menuY; final int captionWidth = mTaskInfo.getConfiguration() .windowConfiguration.getBounds().width(); int menuX; final int menuY; if (mLayoutResId == R.layout.desktop_mode_app_header) { // Align the handle menu to the left of the caption. // Align the handle menu to the left side of the caption. menuX = mMarginMenuStart; menuY = mMarginMenuTop; } else { // Position the handle menu at the center of the caption. final int handleWidth = loadDimensionPixelSize(mContext.getResources(), R.dimen.desktop_mode_fullscreen_decor_caption_width); final int handleOffset = (mMenuWidth / 2) - (handleWidth / 2); final int captionX = mParentDecor.getCaptionX(); // TODO(b/343561161): This needs to be calculated differently if the task is in // top/bottom split. if (Flags.enableAdditionalWindowsAboveStatusBar()) { final Rect leftOrTopStageBounds = new Rect(); if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT) { mSplitScreenController.getStageBounds(leftOrTopStageBounds, new Rect()); } // 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. final DisplayLayout layout = mDisplayController .getDisplayLayout(mTaskInfo.displayId); menuX = captionX + handleOffset - (layout.width() / 2); if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT && layout.isLandscape()) { // If this task in the right stage, we need to offset by left stage's width menuX += leftOrTopStageBounds.width(); } menuY = mMarginMenuStart - ((layout.height() - mMenuHeight) / 2); } else { final int captionWidth = mTaskInfo.getConfiguration() .windowConfiguration.getBounds().width(); menuX = (captionWidth / 2) - (mMenuWidth / 2); menuY = mMarginMenuStart; menuY = mMarginMenuTop; } } // Handle Menu position setup. mHandleMenuPosition.set(menuX, menuY); } /** * Update pill layout, in case task changes have caused positioning to change. */ void relayout(SurfaceControl.Transaction t) { if (mHandleMenuWindow != null) { if (mHandleMenuViewContainer != null) { updateHandleMenuPillPositions(); t.setPosition(mHandleMenuWindow.mWindowSurface, mHandleMenuPosition.x, mHandleMenuPosition.y); mHandleMenuViewContainer.setPosition(t, mHandleMenuPosition.x, mHandleMenuPosition.y); } } Loading @@ -252,7 +302,7 @@ class HandleMenu { * @param ev the MotionEvent to compare against. */ void checkMotionEvent(MotionEvent ev) { final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); 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); Loading Loading @@ -280,7 +330,7 @@ class HandleMenu { boolean isValidMenuInput(PointF inputPoint) { if (!viewsLaidOut()) return true; return pointInView( mHandleMenuWindow.mWindowViewHost.getView(), mHandleMenuViewContainer.getView(), inputPoint.x - mHandleMenuPosition.x, inputPoint.y - mHandleMenuPosition.y); } Loading @@ -294,7 +344,7 @@ class HandleMenu { * Check if the views for handle menu can be seen. */ private boolean viewsLaidOut() { return mHandleMenuWindow.mWindowViewHost.getView().isLaidOut(); return mHandleMenuViewContainer.getView().isLaidOut(); } private void loadHandleMenuDimensions() { Loading Loading @@ -333,8 +383,8 @@ class HandleMenu { void close() { final Runnable after = () -> { mHandleMenuWindow.releaseView(); mHandleMenuWindow = null; mHandleMenuViewContainer.releaseView(); mHandleMenuViewContainer = null; }; if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { Loading @@ -345,7 +395,7 @@ class HandleMenu { } static final class Builder { private final WindowDecoration mParent; private final DesktopModeWindowDecoration mParent; private CharSequence mName; private Bitmap mAppIcon; private View.OnClickListener mOnClickListener; Loading @@ -353,9 +403,10 @@ class HandleMenu { private int mLayoutId; private boolean mShowWindowingPill; private int mCaptionHeight; private DisplayController mDisplayController; private SplitScreenController mSplitScreenController; Builder(@NonNull WindowDecoration parent) { Builder(@NonNull DesktopModeWindowDecoration parent) { mParent = parent; } Loading Loading @@ -394,9 +445,20 @@ class HandleMenu { return this; } Builder setDisplayController(DisplayController displayController) { mDisplayController = displayController; return this; } Builder setSplitScreenController(SplitScreenController splitScreenController) { mSplitScreenController = splitScreenController; return this; } HandleMenu build() { return new HandleMenu(mParent, mLayoutId, mOnClickListener, mOnTouchListener, mAppIcon, mName, mShowWindowingPill, mCaptionHeight); return new HandleMenu(mParent, mLayoutId, mOnClickListener, mOnTouchListener, mAppIcon, mName, mDisplayController, mSplitScreenController, mShowWindowingPill, mCaptionHeight); } } } libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt +17 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ */ package com.android.wm.shell.windowdecor import android.app.ActivityManager.RunningTaskInfo import com.android.window.flags.Flags import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import android.content.Context import android.util.AttributeSet import android.view.MotionEvent Loading @@ -25,10 +29,20 @@ import android.widget.ImageButton * This is due to the hover events being handled by [DesktopModeWindowDecorViewModel] * in order to take the status bar layer into account. Handling it in both classes results in a * flicker when the hover moves from outside to inside status bar layer. * TODO(b/342229481): Remove this and all uses of it once [AdditionalSystemViewContainer] is no longer * guarded by a flag. */ class HandleMenuImageButton(context: Context?, attrs: AttributeSet?) : ImageButton(context, attrs) { class HandleMenuImageButton( context: Context?, attrs: AttributeSet? ) : ImageButton(context, attrs) { lateinit var taskInfo: RunningTaskInfo override fun onHoverEvent(motionEvent: MotionEvent): Boolean { if (Flags.enableAdditionalWindowsAboveStatusBar() || taskInfo.isFreeform) { return super.onHoverEvent(motionEvent) } else { return false } } } libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +7 −7 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.Interpolators.EMPHASIZED_DECELERATE import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.windowdecor.WindowDecoration.AdditionalWindow import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer import java.util.function.Supplier Loading @@ -70,7 +70,7 @@ class MaximizeMenu( private val menuPosition: PointF, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() } ) { private var maximizeMenu: AdditionalWindow? = null private var maximizeMenu: AdditionalViewHostViewContainer? = null private lateinit var viewHost: SurfaceControlViewHost private lateinit var leash: SurfaceControl private val openMenuAnimatorSet = AnimatorSet() Loading Loading @@ -145,7 +145,8 @@ class MaximizeMenu( .setPosition(leash, menuPosition.x, menuPosition.y) .setCornerRadius(leash, cornerRadius) .show(leash) maximizeMenu = AdditionalWindow(leash, viewHost, transactionSupplier) maximizeMenu = AdditionalViewHostViewContainer(leash, viewHost, transactionSupplier) syncQueue.runInSync { transaction -> transaction.merge(t) Loading @@ -154,8 +155,7 @@ class MaximizeMenu( } private fun animateOpenMenu() { val viewHost = maximizeMenu?.mWindowViewHost val maximizeMenuView = viewHost?.view ?: return val maximizeMenuView = maximizeMenu?.view ?: return val maximizeWindowText = maximizeMenuView.requireViewById<TextView>( R.id.maximize_menu_maximize_window_text) val snapWindowText = maximizeMenuView.requireViewById<TextView>( Loading Loading @@ -233,7 +233,7 @@ class MaximizeMenu( } private fun setupMaximizeMenu() { val maximizeMenuView = maximizeMenu?.mWindowViewHost?.view ?: return val maximizeMenuView = maximizeMenu?.view ?: return maximizeMenuView.setOnGenericMotionListener(onGenericMotionListener) maximizeMenuView.setOnTouchListener(onTouchListener) Loading Loading @@ -275,7 +275,7 @@ class MaximizeMenu( * Check if the views for maximize menu can be seen. */ private fun viewsLaidOut(): Boolean { return maximizeMenu?.mWindowViewHost?.view?.isLaidOut ?: false return maximizeMenu?.view?.isLaidOut ?: false } fun onMaximizeMenuHoverEnter(viewId: Int, ev: MotionEvent) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +1 −1 Original line number Diff line number Diff line Loading @@ -439,7 +439,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { if (!decoration.isHandleMenuActive()) { moveTaskToFront(decoration.mTaskInfo); decoration.createHandleMenu(); decoration.createHandleMenu(mSplitScreenController); } else { decoration.closeHandleMenu(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +13 −2 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ 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.shared.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; Loading Loading @@ -650,7 +651,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin /** * Create and display handle menu window. */ void createHandleMenu() { void createHandleMenu(SplitScreenController splitScreenController) { loadAppInfoIfNeeded(); mHandleMenu = new HandleMenu.Builder(this) .setAppIcon(mAppIconBitmap) Loading @@ -660,6 +661,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .setLayoutId(mRelayoutParams.mLayoutResId) .setWindowingButtonsVisible(DesktopModeStatus.canEnterDesktopMode(mContext)) .setCaptionHeight(mResult.mCaptionHeight) .setDisplayController(mDisplayController) .setSplitScreenController(splitScreenController) .build(); mWindowDecorViewHolder.onHandleMenuOpened(); mHandleMenu.show(); Loading Loading @@ -815,11 +818,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // We want handle to remain pressed if the pointer moves outside of it during a drag. handle.setPressed((inHandle && action == ACTION_DOWN) || (handle.isPressed() && action != ACTION_UP && action != ACTION_CANCEL)); if (isHandleMenuActive()) { if (isHandleMenuActive() && !isMenuAboveStatusBar()) { mHandleMenu.checkMotionEvent(ev); } } private boolean isMenuAboveStatusBar() { return Flags.enableAdditionalWindowsAboveStatusBar() && !mTaskInfo.isFreeform(); } private boolean pointInView(View v, float x, float y) { return v != null && v.getLeft() <= x && v.getRight() >= x && v.getTop() <= y && v.getBottom() >= y; Loading Loading @@ -868,6 +875,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return exclusionRegion; } int getCaptionX() { return mResult.mCaptionX; } @Override int getCaptionHeightId(@WindowingMode int windowingMode) { return getCaptionHeightIdStatic(windowingMode); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +97 −35 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ 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 android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; Loading @@ -34,6 +36,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PointF; import android.graphics.Rect; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; Loading @@ -42,7 +45,15 @@ 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.DisplayLayout; 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. Loading @@ -56,15 +67,19 @@ class HandleMenu { private static final String TAG = "HandleMenu"; private static final boolean SHOULD_SHOW_MORE_ACTIONS_PILL = false; private final Context mContext; private final WindowDecoration mParentDecor; private WindowDecoration.AdditionalWindow mHandleMenuWindow; private final PointF mHandleMenuPosition = new PointF(); private final DesktopModeWindowDecoration mParentDecor; @VisibleForTesting AdditionalViewContainer mHandleMenuViewContainer; @VisibleForTesting final PointF mHandleMenuPosition = new PointF(); private final boolean mShouldShowWindowingPill; 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; Loading @@ -74,12 +89,16 @@ class HandleMenu { private HandleMenuAnimator mHandleMenuAnimator; HandleMenu(WindowDecoration parentDecor, int layoutResId, View.OnClickListener onClickListener, View.OnTouchListener onTouchListener, Bitmap appIcon, CharSequence appName, boolean shouldShowWindowingPill, int captionHeight) { HandleMenu(DesktopModeWindowDecoration parentDecor, int layoutResId, View.OnClickListener onClickListener, View.OnTouchListener onTouchListener, Bitmap appIcon, CharSequence appName, DisplayController displayController, SplitScreenController splitScreenController, boolean shouldShowWindowingPill, int captionHeight) { mParentDecor = parentDecor; mContext = mParentDecor.mDecorWindowContext; mTaskInfo = mParentDecor.mTaskInfo; mDisplayController = displayController; mSplitScreenController = splitScreenController; mLayoutResId = layoutResId; mOnClickListener = onClickListener; mOnTouchListener = onTouchListener; Loading @@ -95,20 +114,27 @@ class HandleMenu { final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG); SurfaceControl.Transaction t = new SurfaceControl.Transaction(); createHandleMenuWindow(t, ssg); createHandleMenuViewContainer(t, ssg); ssg.addTransaction(t); ssg.markSyncReady(); setupHandleMenu(); animateHandleMenu(); } private void createHandleMenuWindow(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { private void createHandleMenuViewContainer(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { final int x = (int) mHandleMenuPosition.x; final int y = (int) mHandleMenuPosition.y; mHandleMenuWindow = mParentDecor.addWindow( 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 = mHandleMenuWindow.mWindowViewHost.getView(); } final View handleMenuView = mHandleMenuViewContainer.getView(); mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); } Loading @@ -129,7 +155,7 @@ class HandleMenu { * pill. */ private void setupHandleMenu() { final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); final View handleMenu = mHandleMenuViewContainer.getView(); handleMenu.setOnTouchListener(mOnTouchListener); setupAppInfoPill(handleMenu); if (mShouldShowWindowingPill) { Loading @@ -147,6 +173,7 @@ class HandleMenu { 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); } Loading Loading @@ -215,32 +242,55 @@ class HandleMenu { * Updates handle menu's position variables to reflect its next position. */ private void updateHandleMenuPillPositions() { final int menuX, menuY; final int captionWidth = mTaskInfo.getConfiguration() .windowConfiguration.getBounds().width(); int menuX; final int menuY; if (mLayoutResId == R.layout.desktop_mode_app_header) { // Align the handle menu to the left of the caption. // Align the handle menu to the left side of the caption. menuX = mMarginMenuStart; menuY = mMarginMenuTop; } else { // Position the handle menu at the center of the caption. final int handleWidth = loadDimensionPixelSize(mContext.getResources(), R.dimen.desktop_mode_fullscreen_decor_caption_width); final int handleOffset = (mMenuWidth / 2) - (handleWidth / 2); final int captionX = mParentDecor.getCaptionX(); // TODO(b/343561161): This needs to be calculated differently if the task is in // top/bottom split. if (Flags.enableAdditionalWindowsAboveStatusBar()) { final Rect leftOrTopStageBounds = new Rect(); if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT) { mSplitScreenController.getStageBounds(leftOrTopStageBounds, new Rect()); } // 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. final DisplayLayout layout = mDisplayController .getDisplayLayout(mTaskInfo.displayId); menuX = captionX + handleOffset - (layout.width() / 2); if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT && layout.isLandscape()) { // If this task in the right stage, we need to offset by left stage's width menuX += leftOrTopStageBounds.width(); } menuY = mMarginMenuStart - ((layout.height() - mMenuHeight) / 2); } else { final int captionWidth = mTaskInfo.getConfiguration() .windowConfiguration.getBounds().width(); menuX = (captionWidth / 2) - (mMenuWidth / 2); menuY = mMarginMenuStart; menuY = mMarginMenuTop; } } // Handle Menu position setup. mHandleMenuPosition.set(menuX, menuY); } /** * Update pill layout, in case task changes have caused positioning to change. */ void relayout(SurfaceControl.Transaction t) { if (mHandleMenuWindow != null) { if (mHandleMenuViewContainer != null) { updateHandleMenuPillPositions(); t.setPosition(mHandleMenuWindow.mWindowSurface, mHandleMenuPosition.x, mHandleMenuPosition.y); mHandleMenuViewContainer.setPosition(t, mHandleMenuPosition.x, mHandleMenuPosition.y); } } Loading @@ -252,7 +302,7 @@ class HandleMenu { * @param ev the MotionEvent to compare against. */ void checkMotionEvent(MotionEvent ev) { final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); 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); Loading Loading @@ -280,7 +330,7 @@ class HandleMenu { boolean isValidMenuInput(PointF inputPoint) { if (!viewsLaidOut()) return true; return pointInView( mHandleMenuWindow.mWindowViewHost.getView(), mHandleMenuViewContainer.getView(), inputPoint.x - mHandleMenuPosition.x, inputPoint.y - mHandleMenuPosition.y); } Loading @@ -294,7 +344,7 @@ class HandleMenu { * Check if the views for handle menu can be seen. */ private boolean viewsLaidOut() { return mHandleMenuWindow.mWindowViewHost.getView().isLaidOut(); return mHandleMenuViewContainer.getView().isLaidOut(); } private void loadHandleMenuDimensions() { Loading Loading @@ -333,8 +383,8 @@ class HandleMenu { void close() { final Runnable after = () -> { mHandleMenuWindow.releaseView(); mHandleMenuWindow = null; mHandleMenuViewContainer.releaseView(); mHandleMenuViewContainer = null; }; if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { Loading @@ -345,7 +395,7 @@ class HandleMenu { } static final class Builder { private final WindowDecoration mParent; private final DesktopModeWindowDecoration mParent; private CharSequence mName; private Bitmap mAppIcon; private View.OnClickListener mOnClickListener; Loading @@ -353,9 +403,10 @@ class HandleMenu { private int mLayoutId; private boolean mShowWindowingPill; private int mCaptionHeight; private DisplayController mDisplayController; private SplitScreenController mSplitScreenController; Builder(@NonNull WindowDecoration parent) { Builder(@NonNull DesktopModeWindowDecoration parent) { mParent = parent; } Loading Loading @@ -394,9 +445,20 @@ class HandleMenu { return this; } Builder setDisplayController(DisplayController displayController) { mDisplayController = displayController; return this; } Builder setSplitScreenController(SplitScreenController splitScreenController) { mSplitScreenController = splitScreenController; return this; } HandleMenu build() { return new HandleMenu(mParent, mLayoutId, mOnClickListener, mOnTouchListener, mAppIcon, mName, mShowWindowingPill, mCaptionHeight); return new HandleMenu(mParent, mLayoutId, mOnClickListener, mOnTouchListener, mAppIcon, mName, mDisplayController, mSplitScreenController, mShowWindowingPill, mCaptionHeight); } } }
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt +17 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ */ package com.android.wm.shell.windowdecor import android.app.ActivityManager.RunningTaskInfo import com.android.window.flags.Flags import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import android.content.Context import android.util.AttributeSet import android.view.MotionEvent Loading @@ -25,10 +29,20 @@ import android.widget.ImageButton * This is due to the hover events being handled by [DesktopModeWindowDecorViewModel] * in order to take the status bar layer into account. Handling it in both classes results in a * flicker when the hover moves from outside to inside status bar layer. * TODO(b/342229481): Remove this and all uses of it once [AdditionalSystemViewContainer] is no longer * guarded by a flag. */ class HandleMenuImageButton(context: Context?, attrs: AttributeSet?) : ImageButton(context, attrs) { class HandleMenuImageButton( context: Context?, attrs: AttributeSet? ) : ImageButton(context, attrs) { lateinit var taskInfo: RunningTaskInfo override fun onHoverEvent(motionEvent: MotionEvent): Boolean { if (Flags.enableAdditionalWindowsAboveStatusBar() || taskInfo.isFreeform) { return super.onHoverEvent(motionEvent) } else { return false } } }
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +7 −7 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.Interpolators.EMPHASIZED_DECELERATE import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.windowdecor.WindowDecoration.AdditionalWindow import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer import java.util.function.Supplier Loading @@ -70,7 +70,7 @@ class MaximizeMenu( private val menuPosition: PointF, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() } ) { private var maximizeMenu: AdditionalWindow? = null private var maximizeMenu: AdditionalViewHostViewContainer? = null private lateinit var viewHost: SurfaceControlViewHost private lateinit var leash: SurfaceControl private val openMenuAnimatorSet = AnimatorSet() Loading Loading @@ -145,7 +145,8 @@ class MaximizeMenu( .setPosition(leash, menuPosition.x, menuPosition.y) .setCornerRadius(leash, cornerRadius) .show(leash) maximizeMenu = AdditionalWindow(leash, viewHost, transactionSupplier) maximizeMenu = AdditionalViewHostViewContainer(leash, viewHost, transactionSupplier) syncQueue.runInSync { transaction -> transaction.merge(t) Loading @@ -154,8 +155,7 @@ class MaximizeMenu( } private fun animateOpenMenu() { val viewHost = maximizeMenu?.mWindowViewHost val maximizeMenuView = viewHost?.view ?: return val maximizeMenuView = maximizeMenu?.view ?: return val maximizeWindowText = maximizeMenuView.requireViewById<TextView>( R.id.maximize_menu_maximize_window_text) val snapWindowText = maximizeMenuView.requireViewById<TextView>( Loading Loading @@ -233,7 +233,7 @@ class MaximizeMenu( } private fun setupMaximizeMenu() { val maximizeMenuView = maximizeMenu?.mWindowViewHost?.view ?: return val maximizeMenuView = maximizeMenu?.view ?: return maximizeMenuView.setOnGenericMotionListener(onGenericMotionListener) maximizeMenuView.setOnTouchListener(onTouchListener) Loading Loading @@ -275,7 +275,7 @@ class MaximizeMenu( * Check if the views for maximize menu can be seen. */ private fun viewsLaidOut(): Boolean { return maximizeMenu?.mWindowViewHost?.view?.isLaidOut ?: false return maximizeMenu?.view?.isLaidOut ?: false } fun onMaximizeMenuHoverEnter(viewId: Int, ev: MotionEvent) { Loading