Loading libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/handle_menu" android:layout_width="@dimen/desktop_mode_handle_menu_width" android:layout_height="wrap_content" android:clipChildren="false" Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +13 −14 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_HOVER_ENTER; import static android.view.MotionEvent.ACTION_HOVER_EXIT; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_OUTSIDE; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowInsets.Type.statusBars; Loading Loading @@ -502,8 +503,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (!decoration.isHandleMenuActive()) { moveTaskToFront(decoration.mTaskInfo); decoration.createHandleMenu(mSplitScreenController); } else { decoration.closeHandleMenu(); } } else if (id == R.id.desktop_button) { final WindowContainerTransaction wct = new WindowContainerTransaction(); Loading Loading @@ -549,6 +548,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public boolean onTouch(View v, MotionEvent e) { final int id = v.getId(); final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); if (e.getActionMasked() == ACTION_OUTSIDE) { if (id == R.id.handle_menu) { // Close handle menu on outside touch if menu is directly touchable; if not, // it will be handled by handleEventOutsideCaption. if (decoration.mTaskInfo.isFreeform() || Flags.enableAdditionalWindowsAboveStatusBar()) { decoration.closeHandleMenu(); } } } if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) { mTouchscreenInUse = e.getActionMasked() != ACTION_UP && e.getActionMasked() != ACTION_CANCEL; Loading @@ -558,7 +568,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && id != R.id.maximize_window) { return false; } final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); moveTaskToFront(decoration.mTaskInfo); final int actionMasked = e.getActionMasked(); Loading Loading @@ -587,7 +596,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mShouldPilferCaptionEvents = !(downInCustomizableCaptionRegion && downInExclusionRegion && isTransparentCaption) && !isResizeEvent; } if (!mShouldPilferCaptionEvents) { // The event will be handled by a window below or pilfered by resize handler. return false; Loading @@ -601,9 +609,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { // Gesture is finished, reset state. mShouldPilferCaptionEvents = false; } if (!mHasLongClicked && id != R.id.maximize_window) { decoration.closeMaximizeMenuIfNeeded(e); } return mDragDetector.onMotionEvent(v, e); } Loading Loading @@ -896,10 +901,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { * * @param relevantDecor the window decoration of the focused task's caption. This method only * handles motion events outside this caption's bounds. * TODO(b/349135068): Outside-touch detection no longer works with the * enableAdditionalWindowsAboveStatusBar flag enabled. This * will be fixed once we can add FLAG_WATCH_OUTSIDE_TOUCH to relevant menus, * at which point, all EventReceivers and external touch logic should be removed. */ private void handleEventOutsideCaption(MotionEvent ev, DesktopModeWindowDecoration relevantDecor) { Loading @@ -910,9 +911,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { relevantDecor.updateHoverAndPressStatus(ev); final int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (!mTransitionDragActive) { if (!mTransitionDragActive && !Flags.enableAdditionalWindowsAboveStatusBar()) { relevantDecor.closeHandleMenuIfNeeded(ev); relevantDecor.closeMaximizeMenuIfNeeded(ev); } } } Loading Loading @@ -1250,7 +1250,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } private class DragStartListenerImpl implements DragPositioningCallbackUtility.DragStartListener { @Override Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +11 −2 Original line number Diff line number Diff line Loading @@ -908,6 +908,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mIsMaximizeMenuHovered = hovered; onMaximizeHoverStateChanged(); return null; }, () -> { closeMaximizeMenu(); return null; } ); } Loading Loading @@ -1118,10 +1122,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin handle.performClick(); } if (isHandleMenuActive()) { // If the whole handle menu can be touched directly, rely on FLAG_WATCH_OUTSIDE_TOUCH. // This is for the case that some of the handle menu is underneath the status bar. if (isAppHandle(mWindowDecorViewHolder) && !Flags.enableAdditionalWindowsAboveStatusBar()) { mHandleMenu.checkMotionEvent(ev); closeHandleMenuIfNeeded(ev); } } } /** * Updates hover and pressed status of views in this decoration. Should only be called Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +4 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.net.Uri import android.view.MotionEvent import android.view.SurfaceControl import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.ImageButton import android.widget.ImageView Loading Loading @@ -140,7 +141,9 @@ class HandleMenu( x = x, y = y, width = menuWidth, height = menuHeight height = menuHeight, flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH ) } else { parentDecor.addWindow( Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +19 −4 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.MotionEvent import android.view.MotionEvent.ACTION_HOVER_ENTER import android.view.MotionEvent.ACTION_HOVER_EXIT import android.view.MotionEvent.ACTION_HOVER_MOVE import android.view.MotionEvent.ACTION_OUTSIDE import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import android.view.SurfaceControlViewHost Loading Loading @@ -104,14 +105,16 @@ class MaximizeMenu( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onHoverListener: (Boolean) -> Unit onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit, ) { if (maximizeMenu != null) return createMaximizeMenu( onMaximizeClickListener = onMaximizeClickListener, onLeftSnapClickListener = onLeftSnapClickListener, onRightSnapClickListener = onRightSnapClickListener, onHoverListener = onHoverListener onHoverListener = onHoverListener, onOutsideTouchListener = onOutsideTouchListener ) maximizeMenuView?.animateOpenMenu() } Loading @@ -129,7 +132,8 @@ class MaximizeMenu( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onHoverListener: (Boolean) -> Unit onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit ) { val t = transactionSupplier.get() val builder = SurfaceControl.Builder() Loading @@ -142,7 +146,8 @@ class MaximizeMenu( menuWidth, menuHeight, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSPARENT ) lp.title = "Maximize Menu for Task=" + taskInfo.taskId Loading Loading @@ -172,6 +177,7 @@ class MaximizeMenu( onRightSnapClickListener.onClick(taskId, "right_snap_option") } menuView.onMenuHoverListener = onHoverListener menuView.onOutsideTouchListener = onOutsideTouchListener viewHost.setView(menuView.rootView, lp) } Loading Loading @@ -268,6 +274,8 @@ class MaximizeMenu( var onRightSnapClickListener: (() -> Unit)? = null /** Invoked whenever the hover state of the menu changes. */ var onMenuHoverListener: ((Boolean) -> Unit)? = null /** Invoked whenever a click occurs outside the menu */ var onOutsideTouchListener: (() -> Unit)? = null init { overlay.setOnHoverListener { _, event -> Loading Loading @@ -312,6 +320,13 @@ class MaximizeMenu( maximizeButton.setOnClickListener { onMaximizeClickListener?.invoke() } snapRightButton.setOnClickListener { onRightSnapClickListener?.invoke() } snapLeftButton.setOnClickListener { onLeftSnapClickListener?.invoke() } rootView.setOnTouchListener { _, event -> if (event.actionMasked == ACTION_OUTSIDE) { onOutsideTouchListener?.invoke() false } true } // To prevent aliasing. maximizeButton.setLayerType(View.LAYER_TYPE_SOFTWARE, null) Loading Loading
libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/handle_menu" android:layout_width="@dimen/desktop_mode_handle_menu_width" android:layout_height="wrap_content" android:clipChildren="false" Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +13 −14 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_HOVER_ENTER; import static android.view.MotionEvent.ACTION_HOVER_EXIT; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_OUTSIDE; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowInsets.Type.statusBars; Loading Loading @@ -502,8 +503,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (!decoration.isHandleMenuActive()) { moveTaskToFront(decoration.mTaskInfo); decoration.createHandleMenu(mSplitScreenController); } else { decoration.closeHandleMenu(); } } else if (id == R.id.desktop_button) { final WindowContainerTransaction wct = new WindowContainerTransaction(); Loading Loading @@ -549,6 +548,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public boolean onTouch(View v, MotionEvent e) { final int id = v.getId(); final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); if (e.getActionMasked() == ACTION_OUTSIDE) { if (id == R.id.handle_menu) { // Close handle menu on outside touch if menu is directly touchable; if not, // it will be handled by handleEventOutsideCaption. if (decoration.mTaskInfo.isFreeform() || Flags.enableAdditionalWindowsAboveStatusBar()) { decoration.closeHandleMenu(); } } } if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) { mTouchscreenInUse = e.getActionMasked() != ACTION_UP && e.getActionMasked() != ACTION_CANCEL; Loading @@ -558,7 +568,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && id != R.id.maximize_window) { return false; } final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); moveTaskToFront(decoration.mTaskInfo); final int actionMasked = e.getActionMasked(); Loading Loading @@ -587,7 +596,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mShouldPilferCaptionEvents = !(downInCustomizableCaptionRegion && downInExclusionRegion && isTransparentCaption) && !isResizeEvent; } if (!mShouldPilferCaptionEvents) { // The event will be handled by a window below or pilfered by resize handler. return false; Loading @@ -601,9 +609,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { // Gesture is finished, reset state. mShouldPilferCaptionEvents = false; } if (!mHasLongClicked && id != R.id.maximize_window) { decoration.closeMaximizeMenuIfNeeded(e); } return mDragDetector.onMotionEvent(v, e); } Loading Loading @@ -896,10 +901,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { * * @param relevantDecor the window decoration of the focused task's caption. This method only * handles motion events outside this caption's bounds. * TODO(b/349135068): Outside-touch detection no longer works with the * enableAdditionalWindowsAboveStatusBar flag enabled. This * will be fixed once we can add FLAG_WATCH_OUTSIDE_TOUCH to relevant menus, * at which point, all EventReceivers and external touch logic should be removed. */ private void handleEventOutsideCaption(MotionEvent ev, DesktopModeWindowDecoration relevantDecor) { Loading @@ -910,9 +911,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { relevantDecor.updateHoverAndPressStatus(ev); final int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (!mTransitionDragActive) { if (!mTransitionDragActive && !Flags.enableAdditionalWindowsAboveStatusBar()) { relevantDecor.closeHandleMenuIfNeeded(ev); relevantDecor.closeMaximizeMenuIfNeeded(ev); } } } Loading Loading @@ -1250,7 +1250,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } private class DragStartListenerImpl implements DragPositioningCallbackUtility.DragStartListener { @Override Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +11 −2 Original line number Diff line number Diff line Loading @@ -908,6 +908,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mIsMaximizeMenuHovered = hovered; onMaximizeHoverStateChanged(); return null; }, () -> { closeMaximizeMenu(); return null; } ); } Loading Loading @@ -1118,10 +1122,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin handle.performClick(); } if (isHandleMenuActive()) { // If the whole handle menu can be touched directly, rely on FLAG_WATCH_OUTSIDE_TOUCH. // This is for the case that some of the handle menu is underneath the status bar. if (isAppHandle(mWindowDecorViewHolder) && !Flags.enableAdditionalWindowsAboveStatusBar()) { mHandleMenu.checkMotionEvent(ev); closeHandleMenuIfNeeded(ev); } } } /** * Updates hover and pressed status of views in this decoration. Should only be called Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +4 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.net.Uri import android.view.MotionEvent import android.view.SurfaceControl import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.ImageButton import android.widget.ImageView Loading Loading @@ -140,7 +141,9 @@ class HandleMenu( x = x, y = y, width = menuWidth, height = menuHeight height = menuHeight, flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH ) } else { parentDecor.addWindow( Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +19 −4 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.MotionEvent import android.view.MotionEvent.ACTION_HOVER_ENTER import android.view.MotionEvent.ACTION_HOVER_EXIT import android.view.MotionEvent.ACTION_HOVER_MOVE import android.view.MotionEvent.ACTION_OUTSIDE import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import android.view.SurfaceControlViewHost Loading Loading @@ -104,14 +105,16 @@ class MaximizeMenu( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onHoverListener: (Boolean) -> Unit onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit, ) { if (maximizeMenu != null) return createMaximizeMenu( onMaximizeClickListener = onMaximizeClickListener, onLeftSnapClickListener = onLeftSnapClickListener, onRightSnapClickListener = onRightSnapClickListener, onHoverListener = onHoverListener onHoverListener = onHoverListener, onOutsideTouchListener = onOutsideTouchListener ) maximizeMenuView?.animateOpenMenu() } Loading @@ -129,7 +132,8 @@ class MaximizeMenu( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onHoverListener: (Boolean) -> Unit onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit ) { val t = transactionSupplier.get() val builder = SurfaceControl.Builder() Loading @@ -142,7 +146,8 @@ class MaximizeMenu( menuWidth, menuHeight, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSPARENT ) lp.title = "Maximize Menu for Task=" + taskInfo.taskId Loading Loading @@ -172,6 +177,7 @@ class MaximizeMenu( onRightSnapClickListener.onClick(taskId, "right_snap_option") } menuView.onMenuHoverListener = onHoverListener menuView.onOutsideTouchListener = onOutsideTouchListener viewHost.setView(menuView.rootView, lp) } Loading Loading @@ -268,6 +274,8 @@ class MaximizeMenu( var onRightSnapClickListener: (() -> Unit)? = null /** Invoked whenever the hover state of the menu changes. */ var onMenuHoverListener: ((Boolean) -> Unit)? = null /** Invoked whenever a click occurs outside the menu */ var onOutsideTouchListener: (() -> Unit)? = null init { overlay.setOnHoverListener { _, event -> Loading Loading @@ -312,6 +320,13 @@ class MaximizeMenu( maximizeButton.setOnClickListener { onMaximizeClickListener?.invoke() } snapRightButton.setOnClickListener { onRightSnapClickListener?.invoke() } snapLeftButton.setOnClickListener { onLeftSnapClickListener?.invoke() } rootView.setOnTouchListener { _, event -> if (event.actionMasked == ACTION_OUTSIDE) { onOutsideTouchListener?.invoke() false } true } // To prevent aliasing. maximizeButton.setLayerType(View.LAYER_TYPE_SOFTWARE, null) Loading