Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +90 −56 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ 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 @@ -118,6 +117,8 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; import kotlin.Unit; import java.io.PrintWriter; import java.util.Optional; import java.util.function.Supplier; Loading Loading @@ -418,13 +419,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mWindowDecorByTaskId.remove(taskInfo.taskId); } private void onMaximizeOrRestore(int taskId, String tag) { private void onMaximizeOrRestore(int taskId, String source) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } mInteractionJankMonitor.begin( decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, tag); decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source); mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); Loading @@ -441,10 +442,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { decoration.closeMaximizeMenu(); } private void onOpenInBrowser(@NonNull DesktopModeWindowDecoration decor, @NonNull Uri uri) { private void onOpenInBrowser(int taskId, @NonNull Uri uri) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } openInBrowser(uri); decor.closeHandleMenu(); decor.closeMaximizeMenu(); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); } private void openInBrowser(Uri uri) { Loading @@ -454,6 +459,57 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mContext.startActivity(intent); } private void onToDesktop(int taskId, DesktopModeTransitionSource source) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } final WindowContainerTransaction wct = new WindowContainerTransaction(); mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU); // App sometimes draws before the insets from WindowDecoration#relayout have // been added, so they must be added here decoration.addCaptionInset(wct); mDesktopTasksController.moveTaskToDesktop(taskId, wct, source); decoration.closeHandleMenu(); } private void onToFullscreen(int taskId) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } decoration.closeHandleMenu(); if (isTaskInSplitScreen(taskId)) { mSplitScreenController.moveTaskToFullscreen(taskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { mDesktopTasksController.moveToFullscreen(taskId, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON); } } private void onToSplitScreen(int taskId) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } decoration.closeHandleMenu(); // When the app enters split-select, the handle will no longer be visible, meaning // we shouldn't receive input for it any longer. decoration.disposeStatusBarInputLayer(); mDesktopTasksController.requestSplit(decoration.mTaskInfo, false /* leftOrTop */); } private void onNewWindow(int taskId) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } decoration.closeHandleMenu(); mDesktopTasksController.openNewWindow(decoration.mTaskInfo); } private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener, View.OnGenericMotionListener, DragDetector.MotionEventHandler { Loading Loading @@ -511,40 +567,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { moveTaskToFront(decoration.mTaskInfo); decoration.createHandleMenu(mSplitScreenController); } } else if (id == R.id.desktop_button) { final WindowContainerTransaction wct = new WindowContainerTransaction(); // App sometimes draws before the insets from WindowDecoration#relayout have // been added, so they must be added here mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU); mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct); mDesktopTasksController.moveTaskToDesktop(mTaskId, wct, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON); decoration.closeHandleMenu(); } else if (id == R.id.fullscreen_button) { decoration.closeHandleMenu(); if (isTaskInSplitScreen(mTaskId)) { mSplitScreenController.moveTaskToFullscreen(mTaskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { mDesktopTasksController.moveToFullscreen(mTaskId, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON); } } else if (id == R.id.split_screen_button) { decoration.closeHandleMenu(); // When the app enters split-select, the handle will no longer be visible, meaning // we shouldn't receive input for it any longer. decoration.disposeStatusBarInputLayer(); mDesktopTasksController.requestSplit(decoration.mTaskInfo); } else if (id == R.id.open_in_browser_button) { // TODO(b/346441962): let the decoration handle the click gesture and only call back // to the ViewModel via #setOpenInBrowserClickListener decoration.onOpenInBrowserClick(); } else if (id == R.id.collapse_menu_button) { decoration.closeHandleMenu(); } else if (id == R.id.new_window_button) { decoration.closeHandleMenu(); mDesktopTasksController.openNewWindow(decoration.mTaskInfo); } else if (id == R.id.maximize_window) { // TODO(b/346441962): move click detection logic into the decor's // {@link AppHeaderViewHolder}. Let it encapsulate the that and have it report Loading @@ -559,16 +581,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 Loading @@ -1191,14 +1203,36 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback); windowDecoration.setOnMaximizeOrRestoreClickListener(this::onMaximizeOrRestore); windowDecoration.setOnLeftSnapClickListener((taskId, tag) -> { onSnapResize(taskId, true /* isLeft */); windowDecoration.setOnMaximizeOrRestoreClickListener(() -> { onMaximizeOrRestore(taskInfo.taskId, "maximize_menu"); return Unit.INSTANCE; }); windowDecoration.setOnLeftSnapClickListener(() -> { onSnapResize(taskInfo.taskId, true /* isLeft */); return Unit.INSTANCE; }); windowDecoration.setOnRightSnapClickListener(() -> { onSnapResize(taskInfo.taskId, false /* isLeft */); return Unit.INSTANCE; }); windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> { onToDesktop(taskInfo.taskId, desktopModeTransitionSource); }); windowDecoration.setOnToFullscreenClickListener(() -> { onToFullscreen(taskInfo.taskId); return Unit.INSTANCE; }); windowDecoration.setOnToSplitScreenClickListener(() -> { onToSplitScreen(taskInfo.taskId); return Unit.INSTANCE; }); windowDecoration.setOpenInBrowserClickListener((uri) -> { onOpenInBrowser(taskInfo.taskId, uri); }); windowDecoration.setOnRightSnapClickListener((taskId, tag) -> { onSnapResize(taskId, false /* isLeft */); windowDecoration.setOnNewWindowClickListener(() -> { onNewWindow(taskInfo.taskId); return Unit.INSTANCE; }); windowDecoration.setOpenInBrowserClickListener(this::onOpenInBrowser); windowDecoration.setCaptionListeners( touchEventListener, touchEventListener, touchEventListener, touchEventListener); windowDecoration.setExclusionRegionListener(mExclusionRegionListener); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +61 −34 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT; import static com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize; Loading Loading @@ -77,18 +78,20 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; import com.android.wm.shell.shared.desktopmode.DesktopModeFlags; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.windowdecor.common.OnTaskActionClickListener; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder; import kotlin.Unit; import kotlin.jvm.functions.Function0; import java.util.function.Consumer; import java.util.function.Supplier; /** Loading @@ -115,9 +118,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private View.OnTouchListener mOnCaptionTouchListener; private View.OnLongClickListener mOnCaptionLongClickListener; private View.OnGenericMotionListener mOnCaptionGenericMotionListener; private OnTaskActionClickListener mOnMaximizeOrRestoreClickListener; private OnTaskActionClickListener mOnLeftSnapClickListener; private OnTaskActionClickListener mOnRightSnapClickListener; private Function0<Unit> mOnMaximizeOrRestoreClickListener; private Function0<Unit> mOnLeftSnapClickListener; private Function0<Unit> mOnRightSnapClickListener; private Consumer<DesktopModeTransitionSource> mOnToDesktopClickListener; private Function0<Unit> mOnToFullscreenClickListener; private Function0<Unit> mOnToSplitscreenClickListener; private Function0<Unit> mOnNewWindowClickListener; private DragPositioningCallback mDragPositioningCallback; private DragResizeInputListener mDragResizeListener; private DragDetector mDragDetector; Loading @@ -140,7 +147,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private CharSequence mAppName; private CapturedLink mCapturedLink; private Uri mGenericLink; private OpenInBrowserClickListener mOpenInBrowserClickListener; private Consumer<Uri> mOpenInBrowserClickListener; private ExclusionRegionListener mExclusionRegionListener; Loading Loading @@ -228,22 +235,40 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * TODO(b/346441962): hook this up to double-tap and the header's maximize button, instead of * having the ViewModel deal with parsing motion events. */ void setOnMaximizeOrRestoreClickListener(OnTaskActionClickListener listener) { void setOnMaximizeOrRestoreClickListener(Function0<Unit> listener) { mOnMaximizeOrRestoreClickListener = listener; } /** * Register a listener to be called back when one of the tasks snap-left action is triggered. */ void setOnLeftSnapClickListener(OnTaskActionClickListener listener) { /** Registers a listener to be called when the decoration's snap-left action is triggered.*/ void setOnLeftSnapClickListener(Function0<Unit> listener) { mOnLeftSnapClickListener = listener; } /** Registers a listener to be called when the decoration's snap-right action is triggered. */ void setOnRightSnapClickListener(Function0<Unit> listener) { mOnRightSnapClickListener = listener; } /** Registers a listener to be called when the decoration's to-desktop action is triggered. */ void setOnToDesktopClickListener(Consumer<DesktopModeTransitionSource> listener) { mOnToDesktopClickListener = listener; } /** * Register a listener to be called back when one of the tasks' snap-right action is triggered. * Registers a listener to be called when the decoration's to-fullscreen action is triggered. */ void setOnRightSnapClickListener(OnTaskActionClickListener listener) { mOnRightSnapClickListener = listener; void setOnToFullscreenClickListener(Function0<Unit> listener) { mOnToFullscreenClickListener = listener; } /** Registers a listener to be called when the decoration's to-split action is triggered. */ void setOnToSplitScreenClickListener(Function0<Unit> listener) { mOnToSplitscreenClickListener = listener; } /** Registers a listener to be called when the decoration's new window action is triggered. */ void setOnNewWindowClickListener(Function0<Unit> listener) { mOnNewWindowClickListener = listener; } void setCaptionListeners( Loading @@ -270,7 +295,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop()); } void setOpenInBrowserClickListener(OpenInBrowserClickListener listener) { void setOpenInBrowserClickListener(Consumer<Uri> listener) { mOpenInBrowserClickListener = listener; } Loading Loading @@ -445,14 +470,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } void onOpenInBrowserClick() { if (mOpenInBrowserClickListener == null || mHandleMenu == null) { return; } mOpenInBrowserClickListener.onClick(this, mHandleMenu.getOpenInBrowserLink()); onCapturedLinkExpired(); } @Nullable private Uri getBrowserLink() { // If the captured link is available and has not expired, return the captured link. Loading Loading @@ -965,11 +982,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mHandleMenu = mHandleMenuFactory.create( this, mRelayoutParams.mLayoutResId, mOnCaptionButtonClickListener, mOnCaptionTouchListener, mAppIconBitmap, mAppName, mDisplayController, splitScreenController, DesktopModeStatus.canEnterDesktopMode(mContext), Flags.enableDesktopWindowingMultiInstanceFeatures() Loading @@ -981,7 +995,28 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mResult.mCaptionX ); mWindowDecorViewHolder.onHandleMenuOpened(); mHandleMenu.show(); mHandleMenu.show( /* onToDesktopClickListener= */ () -> { mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON); return Unit.INSTANCE; }, /* onToFullscreenClickListener= */ mOnToFullscreenClickListener, /* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener, /* onNewWindowClickListener= */ mOnNewWindowClickListener, /* openInBrowserClickListener= */ (uri) -> { mOpenInBrowserClickListener.accept(uri); onCapturedLinkExpired(); return Unit.INSTANCE; }, /* onCloseMenuClickListener= */ () -> { closeHandleMenu(); return Unit.INSTANCE; }, /* onOutsideTouchListener= */ () -> { closeHandleMenu(); return Unit.INSTANCE; } ); } private void updateGenericLink() { Loading Loading @@ -1320,14 +1355,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } /** Listener for the handle menu's "Open in browser" button */ interface OpenInBrowserClickListener { /** Inform the implementing class that the "Open in browser" button has been clicked */ void onClick(DesktopModeWindowDecoration decoration, Uri uri); } interface ExclusionRegionListener { /** Inform the implementing class of this task's change in region resize handles */ void onExclusionRegionChanged(int taskId, Region region); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +288 −192 File changed.Preview size limit exceeded, changes collapsed. Show changes libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +10 −18 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHo import com.android.wm.shell.windowdecor.common.DecorThemeUtil import com.android.wm.shell.windowdecor.common.OPACITY_12 import com.android.wm.shell.windowdecor.common.OPACITY_40 import com.android.wm.shell.windowdecor.common.OnTaskActionClickListener import com.android.wm.shell.windowdecor.common.withAlpha import java.util.function.Supplier Loading Loading @@ -102,15 +101,15 @@ class MaximizeMenu( /** Creates and shows the maximize window. */ fun show( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onMaximizeOrRestoreClickListener: () -> Unit, onLeftSnapClickListener: () -> Unit, onRightSnapClickListener: () -> Unit, onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit, ) { if (maximizeMenu != null) return createMaximizeMenu( onMaximizeClickListener = onMaximizeClickListener, onMaximizeClickListener = onMaximizeOrRestoreClickListener, onLeftSnapClickListener = onLeftSnapClickListener, onRightSnapClickListener = onRightSnapClickListener, onHoverListener = onHoverListener, Loading @@ -129,9 +128,9 @@ class MaximizeMenu( /** Create a maximize menu that is attached to the display area. */ private fun createMaximizeMenu( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onMaximizeClickListener: () -> Unit, onLeftSnapClickListener: () -> Unit, onRightSnapClickListener: () -> Unit, onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit ) { Loading Loading @@ -165,17 +164,10 @@ class MaximizeMenu( menuHeight = menuHeight, menuPadding = menuPadding, ).also { menuView -> val taskId = taskInfo.taskId menuView.bind(taskInfo) menuView.onMaximizeClickListener = { onMaximizeClickListener.onClick(taskId, "maximize_menu_option") } menuView.onLeftSnapClickListener = { onLeftSnapClickListener.onClick(taskId, "left_snap_option") } menuView.onRightSnapClickListener = { onRightSnapClickListener.onClick(taskId, "right_snap_option") } menuView.onMaximizeClickListener = onMaximizeClickListener menuView.onLeftSnapClickListener = onLeftSnapClickListener menuView.onRightSnapClickListener = onRightSnapClickListener menuView.onMenuHoverListener = onHoverListener menuView.onOutsideTouchListener = onOutsideTouchListener viewHost.setView(menuView.rootView, lp) Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +23 −6 Original line number Diff line number Diff line Loading @@ -613,7 +613,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * Create a window associated with this WindowDecoration. * Note that subclass must dispose of this when the task is hidden/closed. * * @param layoutId layout to make the window from * @param v View to attach to the window * @param t the transaction to apply * @param xPos x position of new window * @param yPos y position of new window Loading @@ -621,9 +621,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param height height of new window * @return the {@link AdditionalViewHostViewContainer} that was added. */ AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { AdditionalViewHostViewContainer addWindow(@NonNull View v, @NonNull String namePrefix, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) Loading @@ -631,8 +631,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setParent(mDecorationContainerSurface) .setCallsite("WindowDecoration.addWindow") .build(); View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); t.setPosition(windowSurfaceControl, xPos, yPos) .setWindowCrop(windowSurfaceControl, width, height) .show(windowSurfaceControl); Loading @@ -652,6 +650,25 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mSurfaceControlTransactionSupplier); } /** * Create a window associated with this WindowDecoration. * Note that subclass must dispose of this when the task is hidden/closed. * * @param layoutId layout to make the window from * @param t the transaction to apply * @param xPos x position of new window * @param yPos y position of new window * @param width width of new window * @param height height of new window * @return the {@link AdditionalViewHostViewContainer} that was added. */ AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { final View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); return addWindow(v, namePrefix, t, ssg, xPos, yPos, width, height); } /** * Adds caption inset source to a WCT */ Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +90 −56 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ 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 @@ -118,6 +117,8 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; import kotlin.Unit; import java.io.PrintWriter; import java.util.Optional; import java.util.function.Supplier; Loading Loading @@ -418,13 +419,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mWindowDecorByTaskId.remove(taskInfo.taskId); } private void onMaximizeOrRestore(int taskId, String tag) { private void onMaximizeOrRestore(int taskId, String source) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } mInteractionJankMonitor.begin( decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, tag); decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source); mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); Loading @@ -441,10 +442,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { decoration.closeMaximizeMenu(); } private void onOpenInBrowser(@NonNull DesktopModeWindowDecoration decor, @NonNull Uri uri) { private void onOpenInBrowser(int taskId, @NonNull Uri uri) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } openInBrowser(uri); decor.closeHandleMenu(); decor.closeMaximizeMenu(); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); } private void openInBrowser(Uri uri) { Loading @@ -454,6 +459,57 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mContext.startActivity(intent); } private void onToDesktop(int taskId, DesktopModeTransitionSource source) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } final WindowContainerTransaction wct = new WindowContainerTransaction(); mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU); // App sometimes draws before the insets from WindowDecoration#relayout have // been added, so they must be added here decoration.addCaptionInset(wct); mDesktopTasksController.moveTaskToDesktop(taskId, wct, source); decoration.closeHandleMenu(); } private void onToFullscreen(int taskId) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } decoration.closeHandleMenu(); if (isTaskInSplitScreen(taskId)) { mSplitScreenController.moveTaskToFullscreen(taskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { mDesktopTasksController.moveToFullscreen(taskId, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON); } } private void onToSplitScreen(int taskId) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } decoration.closeHandleMenu(); // When the app enters split-select, the handle will no longer be visible, meaning // we shouldn't receive input for it any longer. decoration.disposeStatusBarInputLayer(); mDesktopTasksController.requestSplit(decoration.mTaskInfo, false /* leftOrTop */); } private void onNewWindow(int taskId) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } decoration.closeHandleMenu(); mDesktopTasksController.openNewWindow(decoration.mTaskInfo); } private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener, View.OnGenericMotionListener, DragDetector.MotionEventHandler { Loading Loading @@ -511,40 +567,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { moveTaskToFront(decoration.mTaskInfo); decoration.createHandleMenu(mSplitScreenController); } } else if (id == R.id.desktop_button) { final WindowContainerTransaction wct = new WindowContainerTransaction(); // App sometimes draws before the insets from WindowDecoration#relayout have // been added, so they must be added here mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU); mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct); mDesktopTasksController.moveTaskToDesktop(mTaskId, wct, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON); decoration.closeHandleMenu(); } else if (id == R.id.fullscreen_button) { decoration.closeHandleMenu(); if (isTaskInSplitScreen(mTaskId)) { mSplitScreenController.moveTaskToFullscreen(mTaskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { mDesktopTasksController.moveToFullscreen(mTaskId, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON); } } else if (id == R.id.split_screen_button) { decoration.closeHandleMenu(); // When the app enters split-select, the handle will no longer be visible, meaning // we shouldn't receive input for it any longer. decoration.disposeStatusBarInputLayer(); mDesktopTasksController.requestSplit(decoration.mTaskInfo); } else if (id == R.id.open_in_browser_button) { // TODO(b/346441962): let the decoration handle the click gesture and only call back // to the ViewModel via #setOpenInBrowserClickListener decoration.onOpenInBrowserClick(); } else if (id == R.id.collapse_menu_button) { decoration.closeHandleMenu(); } else if (id == R.id.new_window_button) { decoration.closeHandleMenu(); mDesktopTasksController.openNewWindow(decoration.mTaskInfo); } else if (id == R.id.maximize_window) { // TODO(b/346441962): move click detection logic into the decor's // {@link AppHeaderViewHolder}. Let it encapsulate the that and have it report Loading @@ -559,16 +581,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 Loading @@ -1191,14 +1203,36 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback); windowDecoration.setOnMaximizeOrRestoreClickListener(this::onMaximizeOrRestore); windowDecoration.setOnLeftSnapClickListener((taskId, tag) -> { onSnapResize(taskId, true /* isLeft */); windowDecoration.setOnMaximizeOrRestoreClickListener(() -> { onMaximizeOrRestore(taskInfo.taskId, "maximize_menu"); return Unit.INSTANCE; }); windowDecoration.setOnLeftSnapClickListener(() -> { onSnapResize(taskInfo.taskId, true /* isLeft */); return Unit.INSTANCE; }); windowDecoration.setOnRightSnapClickListener(() -> { onSnapResize(taskInfo.taskId, false /* isLeft */); return Unit.INSTANCE; }); windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> { onToDesktop(taskInfo.taskId, desktopModeTransitionSource); }); windowDecoration.setOnToFullscreenClickListener(() -> { onToFullscreen(taskInfo.taskId); return Unit.INSTANCE; }); windowDecoration.setOnToSplitScreenClickListener(() -> { onToSplitScreen(taskInfo.taskId); return Unit.INSTANCE; }); windowDecoration.setOpenInBrowserClickListener((uri) -> { onOpenInBrowser(taskInfo.taskId, uri); }); windowDecoration.setOnRightSnapClickListener((taskId, tag) -> { onSnapResize(taskId, false /* isLeft */); windowDecoration.setOnNewWindowClickListener(() -> { onNewWindow(taskInfo.taskId); return Unit.INSTANCE; }); windowDecoration.setOpenInBrowserClickListener(this::onOpenInBrowser); windowDecoration.setCaptionListeners( touchEventListener, touchEventListener, touchEventListener, touchEventListener); windowDecoration.setExclusionRegionListener(mExclusionRegionListener); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +61 −34 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT; import static com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize; Loading Loading @@ -77,18 +78,20 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; import com.android.wm.shell.shared.desktopmode.DesktopModeFlags; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.windowdecor.common.OnTaskActionClickListener; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder; import kotlin.Unit; import kotlin.jvm.functions.Function0; import java.util.function.Consumer; import java.util.function.Supplier; /** Loading @@ -115,9 +118,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private View.OnTouchListener mOnCaptionTouchListener; private View.OnLongClickListener mOnCaptionLongClickListener; private View.OnGenericMotionListener mOnCaptionGenericMotionListener; private OnTaskActionClickListener mOnMaximizeOrRestoreClickListener; private OnTaskActionClickListener mOnLeftSnapClickListener; private OnTaskActionClickListener mOnRightSnapClickListener; private Function0<Unit> mOnMaximizeOrRestoreClickListener; private Function0<Unit> mOnLeftSnapClickListener; private Function0<Unit> mOnRightSnapClickListener; private Consumer<DesktopModeTransitionSource> mOnToDesktopClickListener; private Function0<Unit> mOnToFullscreenClickListener; private Function0<Unit> mOnToSplitscreenClickListener; private Function0<Unit> mOnNewWindowClickListener; private DragPositioningCallback mDragPositioningCallback; private DragResizeInputListener mDragResizeListener; private DragDetector mDragDetector; Loading @@ -140,7 +147,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private CharSequence mAppName; private CapturedLink mCapturedLink; private Uri mGenericLink; private OpenInBrowserClickListener mOpenInBrowserClickListener; private Consumer<Uri> mOpenInBrowserClickListener; private ExclusionRegionListener mExclusionRegionListener; Loading Loading @@ -228,22 +235,40 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * TODO(b/346441962): hook this up to double-tap and the header's maximize button, instead of * having the ViewModel deal with parsing motion events. */ void setOnMaximizeOrRestoreClickListener(OnTaskActionClickListener listener) { void setOnMaximizeOrRestoreClickListener(Function0<Unit> listener) { mOnMaximizeOrRestoreClickListener = listener; } /** * Register a listener to be called back when one of the tasks snap-left action is triggered. */ void setOnLeftSnapClickListener(OnTaskActionClickListener listener) { /** Registers a listener to be called when the decoration's snap-left action is triggered.*/ void setOnLeftSnapClickListener(Function0<Unit> listener) { mOnLeftSnapClickListener = listener; } /** Registers a listener to be called when the decoration's snap-right action is triggered. */ void setOnRightSnapClickListener(Function0<Unit> listener) { mOnRightSnapClickListener = listener; } /** Registers a listener to be called when the decoration's to-desktop action is triggered. */ void setOnToDesktopClickListener(Consumer<DesktopModeTransitionSource> listener) { mOnToDesktopClickListener = listener; } /** * Register a listener to be called back when one of the tasks' snap-right action is triggered. * Registers a listener to be called when the decoration's to-fullscreen action is triggered. */ void setOnRightSnapClickListener(OnTaskActionClickListener listener) { mOnRightSnapClickListener = listener; void setOnToFullscreenClickListener(Function0<Unit> listener) { mOnToFullscreenClickListener = listener; } /** Registers a listener to be called when the decoration's to-split action is triggered. */ void setOnToSplitScreenClickListener(Function0<Unit> listener) { mOnToSplitscreenClickListener = listener; } /** Registers a listener to be called when the decoration's new window action is triggered. */ void setOnNewWindowClickListener(Function0<Unit> listener) { mOnNewWindowClickListener = listener; } void setCaptionListeners( Loading @@ -270,7 +295,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop()); } void setOpenInBrowserClickListener(OpenInBrowserClickListener listener) { void setOpenInBrowserClickListener(Consumer<Uri> listener) { mOpenInBrowserClickListener = listener; } Loading Loading @@ -445,14 +470,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } void onOpenInBrowserClick() { if (mOpenInBrowserClickListener == null || mHandleMenu == null) { return; } mOpenInBrowserClickListener.onClick(this, mHandleMenu.getOpenInBrowserLink()); onCapturedLinkExpired(); } @Nullable private Uri getBrowserLink() { // If the captured link is available and has not expired, return the captured link. Loading Loading @@ -965,11 +982,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mHandleMenu = mHandleMenuFactory.create( this, mRelayoutParams.mLayoutResId, mOnCaptionButtonClickListener, mOnCaptionTouchListener, mAppIconBitmap, mAppName, mDisplayController, splitScreenController, DesktopModeStatus.canEnterDesktopMode(mContext), Flags.enableDesktopWindowingMultiInstanceFeatures() Loading @@ -981,7 +995,28 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mResult.mCaptionX ); mWindowDecorViewHolder.onHandleMenuOpened(); mHandleMenu.show(); mHandleMenu.show( /* onToDesktopClickListener= */ () -> { mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON); return Unit.INSTANCE; }, /* onToFullscreenClickListener= */ mOnToFullscreenClickListener, /* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener, /* onNewWindowClickListener= */ mOnNewWindowClickListener, /* openInBrowserClickListener= */ (uri) -> { mOpenInBrowserClickListener.accept(uri); onCapturedLinkExpired(); return Unit.INSTANCE; }, /* onCloseMenuClickListener= */ () -> { closeHandleMenu(); return Unit.INSTANCE; }, /* onOutsideTouchListener= */ () -> { closeHandleMenu(); return Unit.INSTANCE; } ); } private void updateGenericLink() { Loading Loading @@ -1320,14 +1355,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } /** Listener for the handle menu's "Open in browser" button */ interface OpenInBrowserClickListener { /** Inform the implementing class that the "Open in browser" button has been clicked */ void onClick(DesktopModeWindowDecoration decoration, Uri uri); } interface ExclusionRegionListener { /** Inform the implementing class of this task's change in region resize handles */ void onExclusionRegionChanged(int taskId, Region region); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +288 −192 File changed.Preview size limit exceeded, changes collapsed. Show changes
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +10 −18 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHo import com.android.wm.shell.windowdecor.common.DecorThemeUtil import com.android.wm.shell.windowdecor.common.OPACITY_12 import com.android.wm.shell.windowdecor.common.OPACITY_40 import com.android.wm.shell.windowdecor.common.OnTaskActionClickListener import com.android.wm.shell.windowdecor.common.withAlpha import java.util.function.Supplier Loading Loading @@ -102,15 +101,15 @@ class MaximizeMenu( /** Creates and shows the maximize window. */ fun show( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onMaximizeOrRestoreClickListener: () -> Unit, onLeftSnapClickListener: () -> Unit, onRightSnapClickListener: () -> Unit, onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit, ) { if (maximizeMenu != null) return createMaximizeMenu( onMaximizeClickListener = onMaximizeClickListener, onMaximizeClickListener = onMaximizeOrRestoreClickListener, onLeftSnapClickListener = onLeftSnapClickListener, onRightSnapClickListener = onRightSnapClickListener, onHoverListener = onHoverListener, Loading @@ -129,9 +128,9 @@ class MaximizeMenu( /** Create a maximize menu that is attached to the display area. */ private fun createMaximizeMenu( onMaximizeClickListener: OnTaskActionClickListener, onLeftSnapClickListener: OnTaskActionClickListener, onRightSnapClickListener: OnTaskActionClickListener, onMaximizeClickListener: () -> Unit, onLeftSnapClickListener: () -> Unit, onRightSnapClickListener: () -> Unit, onHoverListener: (Boolean) -> Unit, onOutsideTouchListener: () -> Unit ) { Loading Loading @@ -165,17 +164,10 @@ class MaximizeMenu( menuHeight = menuHeight, menuPadding = menuPadding, ).also { menuView -> val taskId = taskInfo.taskId menuView.bind(taskInfo) menuView.onMaximizeClickListener = { onMaximizeClickListener.onClick(taskId, "maximize_menu_option") } menuView.onLeftSnapClickListener = { onLeftSnapClickListener.onClick(taskId, "left_snap_option") } menuView.onRightSnapClickListener = { onRightSnapClickListener.onClick(taskId, "right_snap_option") } menuView.onMaximizeClickListener = onMaximizeClickListener menuView.onLeftSnapClickListener = onLeftSnapClickListener menuView.onRightSnapClickListener = onRightSnapClickListener menuView.onMenuHoverListener = onHoverListener menuView.onOutsideTouchListener = onOutsideTouchListener viewHost.setView(menuView.rootView, lp) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +23 −6 Original line number Diff line number Diff line Loading @@ -613,7 +613,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * Create a window associated with this WindowDecoration. * Note that subclass must dispose of this when the task is hidden/closed. * * @param layoutId layout to make the window from * @param v View to attach to the window * @param t the transaction to apply * @param xPos x position of new window * @param yPos y position of new window Loading @@ -621,9 +621,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param height height of new window * @return the {@link AdditionalViewHostViewContainer} that was added. */ AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { AdditionalViewHostViewContainer addWindow(@NonNull View v, @NonNull String namePrefix, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) Loading @@ -631,8 +631,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setParent(mDecorationContainerSurface) .setCallsite("WindowDecoration.addWindow") .build(); View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); t.setPosition(windowSurfaceControl, xPos, yPos) .setWindowCrop(windowSurfaceControl, width, height) .show(windowSurfaceControl); Loading @@ -652,6 +650,25 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mSurfaceControlTransactionSupplier); } /** * Create a window associated with this WindowDecoration. * Note that subclass must dispose of this when the task is hidden/closed. * * @param layoutId layout to make the window from * @param t the transaction to apply * @param xPos x position of new window * @param yPos y position of new window * @param width width of new window * @param height height of new window * @return the {@link AdditionalViewHostViewContainer} that was added. */ AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { final View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); return addWindow(v, namePrefix, t, ssg, xPos, yPos, width, height); } /** * Adds caption inset source to a WCT */ Loading