Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −4 Original line number Diff line number Diff line Loading @@ -267,7 +267,8 @@ public abstract class WMShellModule { AppHandleEducationController appHandleEducationController, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, Loading Loading @@ -295,7 +296,8 @@ public abstract class WMShellModule { appHandleEducationController, windowDecorCaptionHandleRepository, desktopActivityOrientationHandler, focusTransitionObserver); focusTransitionObserver, desktopModeEventLogger); } return new CaptionWindowDecorViewModel( context, Loading Loading @@ -647,7 +649,8 @@ public abstract class WMShellModule { Optional<RecentTasksController> recentTasksController, InteractionJankMonitor interactionJankMonitor, InputManager inputManager, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, keyguardManager, Loading @@ -659,7 +662,8 @@ public abstract class WMShellModule { desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter, recentTasksController.orElse(null), interactionJankMonitor, mainHandler, inputManager, focusTransitionObserver); inputManager, focusTransitionObserver, desktopModeEventLogger); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt +103 −9 Original line number Diff line number Diff line Loading @@ -16,11 +16,20 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.util.Size import android.view.InputDevice.SOURCE_MOUSE import android.view.InputDevice.SOURCE_TOUCHSCREEN import android.view.MotionEvent import android.view.MotionEvent.TOOL_TYPE_FINGER import android.view.MotionEvent.TOOL_TYPE_MOUSE import android.view.MotionEvent.TOOL_TYPE_STYLUS import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.internal.util.FrameworkStatsLog import com.android.window.flags.Flags import com.android.wm.shell.EventLogTags import com.android.wm.shell.common.DisplayController import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import java.security.SecureRandom import java.util.Random Loading Loading @@ -176,7 +185,13 @@ class DesktopModeEventLogger { * Logs that a task resize event is starting with [taskSizeUpdate] within a Desktop mode * session. */ fun logTaskResizingStarted(taskSizeUpdate: TaskSizeUpdate) { fun logTaskResizingStarted( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, taskInfo: RunningTaskInfo, displayController: DisplayController? = null, displayLayoutSize: Size? = null, ) { if (!Flags.enableResizingMetrics()) return val sessionId = currentSessionId.get() Loading @@ -188,11 +203,19 @@ class DesktopModeEventLogger { return } val taskSizeUpdate = createTaskSizeUpdate( resizeTrigger, motionEvent, taskInfo, displayController = displayController, displayLayoutSize = displayLayoutSize, ) ProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeLogger: Logging task resize is starting, session: %s taskId: %s", "DesktopModeLogger: Logging task resize is starting, session: %s, taskSizeUpdate: %s", sessionId, taskSizeUpdate.instanceId taskSizeUpdate ) logTaskSizeUpdated( FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZING_STAGE__START_RESIZING_STAGE, Loading @@ -203,7 +226,15 @@ class DesktopModeEventLogger { /** * Logs that a task resize event is ending with [taskSizeUpdate] within a Desktop mode session. */ fun logTaskResizingEnded(taskSizeUpdate: TaskSizeUpdate) { fun logTaskResizingEnded( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, taskInfo: RunningTaskInfo, taskHeight: Int? = null, taskWidth: Int? = null, displayController: DisplayController? = null, displayLayoutSize: Size? = null, ) { if (!Flags.enableResizingMetrics()) return val sessionId = currentSessionId.get() Loading @@ -215,18 +246,61 @@ class DesktopModeEventLogger { return } val taskSizeUpdate = createTaskSizeUpdate( resizeTrigger, motionEvent, taskInfo, taskHeight, taskWidth, displayController, displayLayoutSize, ) ProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeLogger: Logging task resize is ending, session: %s taskId: %s", "DesktopModeLogger: Logging task resize is ending, session: %s, taskSizeUpdate: %s", sessionId, taskSizeUpdate.instanceId taskSizeUpdate ) logTaskSizeUpdated( FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZING_STAGE__END_RESIZING_STAGE, sessionId, taskSizeUpdate ) } private fun createTaskSizeUpdate( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, taskInfo: RunningTaskInfo, taskHeight: Int? = null, taskWidth: Int? = null, displayController: DisplayController? = null, displayLayoutSize: Size? = null, ): TaskSizeUpdate { val taskBounds = taskInfo.configuration.windowConfiguration.bounds val height = taskHeight ?: taskBounds.height() val width = taskWidth ?: taskBounds.width() val displaySize = when { displayLayoutSize != null -> displayLayoutSize.height * displayLayoutSize.width displayController != null -> displayController.getDisplayLayout(taskInfo.displayId) ?.let { it.height() * it.width() } else -> null } return TaskSizeUpdate( resizeTrigger, getInputMethodFromMotionEvent(motionEvent), taskInfo.taskId, taskInfo.effectiveUid, height, width, displaySize, ) } fun logTaskInfoStateInit() { logTaskUpdate( FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INIT_STATSD, Loading @@ -238,7 +312,8 @@ class DesktopModeEventLogger { taskHeight = 0, taskWidth = 0, taskX = 0, taskY = 0) taskY = 0 ) ) } Loading Loading @@ -314,7 +389,7 @@ class DesktopModeEventLogger { /* task_width */ taskSizeUpdate.taskWidth, /* display_area */ taskSizeUpdate.displayArea taskSizeUpdate.displayArea ?: -1 ) } Loading Loading @@ -364,8 +439,23 @@ class DesktopModeEventLogger { val uid: Int, val taskHeight: Int, val taskWidth: Int, val displayArea: Int, val displayArea: Int?, ) private fun getInputMethodFromMotionEvent(e: MotionEvent?): InputMethod { if (e == null) return InputMethod.UNKNOWN_INPUT_METHOD val toolType = e.getToolType( e.findPointerIndex(e.getPointerId(0)) ) return when { toolType == TOOL_TYPE_STYLUS -> InputMethod.STYLUS toolType == TOOL_TYPE_MOUSE -> InputMethod.MOUSE toolType == TOOL_TYPE_FINGER && e.source == SOURCE_MOUSE -> InputMethod.TOUCHPAD toolType == TOOL_TYPE_FINGER && e.source == SOURCE_TOUCHSCREEN -> InputMethod.TOUCH else -> InputMethod.UNKNOWN_INPUT_METHOD } } // Default value used when the task was not minimized. @VisibleForTesting Loading Loading @@ -499,6 +589,10 @@ class DesktopModeEventLogger { FrameworkStatsLog .DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZE_TRIGGER__SNAP_RIGHT_MENU_RESIZE_TRIGGER ), MAXIMIZE_MENU( FrameworkStatsLog .DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZE_TRIGGER__MAXIMIZE_MENU_RESIZE_TRIGGER ), } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +54 −8 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.util.Size import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent import android.view.KeyEvent import android.view.MotionEvent import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_CLOSE Loading Loading @@ -125,7 +126,7 @@ import java.io.PrintWriter import java.util.Optional import java.util.concurrent.Executor import java.util.function.Consumer import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger /** Handles moving tasks in and out of desktop */ class DesktopTasksController( private val context: Context, Loading Loading @@ -158,6 +159,7 @@ class DesktopTasksController( @ShellMainThread private val handler: Handler, private val inputManager: InputManager, private val focusTransitionObserver: FocusTransitionObserver, private val desktopModeEventLogger: DesktopModeEventLogger, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, Loading Loading @@ -747,7 +749,11 @@ class DesktopTasksController( * bounds) and a free floating state (either the last saved bounds if available or the default * bounds otherwise). */ fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) { fun toggleDesktopTaskSize( taskInfo: RunningTaskInfo, resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, ) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val stableBounds = Rect().apply { displayLayout.getStableBounds(this) } Loading Loading @@ -794,7 +800,10 @@ class DesktopTasksController( taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding) val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) desktopModeEventLogger.logTaskResizingEnded( resizeTrigger, motionEvent, taskInfo, destinationBounds.height(), destinationBounds.width(), displayController ) toggleResizeDesktopTaskTransitionHandler.startTransition(wct) } Loading Loading @@ -884,9 +893,19 @@ class DesktopTasksController( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, currentDragBounds: Rect, position: SnapPosition position: SnapPosition, resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, ) { val destinationBounds = getSnapBounds(taskInfo, position) desktopModeEventLogger.logTaskResizingEnded( resizeTrigger, motionEvent, taskInfo, destinationBounds.height(), destinationBounds.width(), displayController, ) if (destinationBounds == taskInfo.configuration.windowConfiguration.bounds) { // Handle the case where we attempt to snap resize when already snap resized: the task // position won't need to change but we want to animate the surface going back to the Loading Loading @@ -915,7 +934,8 @@ class DesktopTasksController( position: SnapPosition, taskSurface: SurfaceControl, currentDragBounds: Rect, dragStartBounds: Rect dragStartBounds: Rect, motionEvent: MotionEvent, ) { releaseVisualIndicator() if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) { Loading @@ -932,10 +952,25 @@ class DesktopTasksController( isResizable = taskInfo.isResizeable, ) } else { val resizeTrigger = if (position == SnapPosition.LEFT) { ResizeTrigger.DRAG_LEFT } else { ResizeTrigger.DRAG_RIGHT } desktopModeEventLogger.logTaskResizingStarted( resizeTrigger, motionEvent, taskInfo, displayController ) interactionJankMonitor.begin( taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable" ) snapToHalfScreen(taskInfo, taskSurface, currentDragBounds, position) snapToHalfScreen( taskInfo, taskSurface, currentDragBounds, position, resizeTrigger, motionEvent, ) } } Loading Loading @@ -1735,6 +1770,7 @@ class DesktopTasksController( currentDragBounds: Rect, validDragArea: Rect, dragStartBounds: Rect, motionEvent: MotionEvent, ) { if (taskInfo.configuration.windowConfiguration.windowingMode != WINDOWING_MODE_FREEFORM) { return Loading @@ -1755,12 +1791,22 @@ class DesktopTasksController( } IndicatorType.TO_SPLIT_LEFT_INDICATOR -> { handleSnapResizingTask( taskInfo, SnapPosition.LEFT, taskSurface, currentDragBounds, dragStartBounds taskInfo, SnapPosition.LEFT, taskSurface, currentDragBounds, dragStartBounds, motionEvent, ) } IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> { handleSnapResizingTask( taskInfo, SnapPosition.RIGHT, taskSurface, currentDragBounds, dragStartBounds taskInfo, SnapPosition.RIGHT, taskSurface, currentDragBounds, dragStartBounds, motionEvent, ) } IndicatorType.NO_INDICATOR -> { Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +1 −0 Original line number Diff line number Diff line Loading @@ -274,6 +274,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL closeDragResizeListener(); mDragResizeListener = new DragResizeInputListener( mContext, mTaskInfo, mHandler, mChoreographer, mDisplay.getDisplayId(), Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +39 −14 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static android.view.WindowInsets.Type.statusBars; import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU; import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing; import static com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR; Loading Loading @@ -103,6 +104,7 @@ 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.desktopmode.DesktopActivityOrientationChangeHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; Loading Loading @@ -221,6 +223,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, }; private final TaskPositionerFactory mTaskPositionerFactory; private final FocusTransitionObserver mFocusTransitionObserver; private final DesktopModeEventLogger mDesktopModeEventLogger; public DesktopModeWindowDecorViewModel( Context context, Loading Loading @@ -248,7 +251,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, AppHandleEducationController appHandleEducationController, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { this( context, shellExecutor, Loading Loading @@ -281,7 +285,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, windowDecorCaptionHandleRepository, activityOrientationChangeHandler, new TaskPositionerFactory(), focusTransitionObserver); focusTransitionObserver, desktopModeEventLogger); } @VisibleForTesting Loading Loading @@ -317,7 +322,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, TaskPositionerFactory taskPositionerFactory, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; Loading Loading @@ -378,6 +384,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, }; mTaskPositionerFactory = taskPositionerFactory; mFocusTransitionObserver = focusTransitionObserver; mDesktopModeEventLogger = desktopModeEventLogger; shellInit.addInitCallback(this::onInit, this); } Loading Loading @@ -547,15 +554,20 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, >= MANAGE_WINDOWS_MINIMUM_INSTANCES); } private void onMaximizeOrRestore(int taskId, String source) { private void onMaximizeOrRestore(int taskId, String source, ResizeTrigger resizeTrigger, MotionEvent motionEvent) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent, decoration.mTaskInfo, mDisplayController, /* displayLayoutSize= */ null); mInteractionJankMonitor.begin( decoration.mTaskSurface, mContext, mMainHandler, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source); mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo); mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo, resizeTrigger, motionEvent); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); } Loading @@ -568,7 +580,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopTasksController.toggleDesktopTaskFullImmersiveState(decoration.mTaskInfo); } private void onSnapResize(int taskId, boolean left) { private void onSnapResize(int taskId, boolean left, MotionEvent motionEvent) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; Loading @@ -579,13 +591,20 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, Toast.makeText(mContext, R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show(); } else { ResizeTrigger resizeTrigger = left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU; mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent, decoration.mTaskInfo, mDisplayController, /* displayLayoutSize= */ null); mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler, Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable"); mDesktopTasksController.snapToHalfScreen( decoration.mTaskInfo, decoration.mTaskSurface, decoration.mTaskInfo.configuration.windowConfiguration.getBounds(), left ? SnapPosition.LEFT : SnapPosition.RIGHT); left ? SnapPosition.LEFT : SnapPosition.RIGHT, resizeTrigger, motionEvent); } decoration.closeHandleMenu(); Loading Loading @@ -737,6 +756,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private boolean mTouchscreenInUse; private boolean mHasLongClicked; private int mDragPointerId = -1; private MotionEvent mMotionEvent; private DesktopModeTouchEventListener( RunningTaskInfo taskInfo, Loading Loading @@ -798,7 +818,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } else { // Full immersive is disabled or task doesn't request/support it, so just // toggle between maximize/restore states. onMaximizeOrRestore(decoration.mTaskInfo.taskId, "caption_bar_button"); onMaximizeOrRestore(decoration.mTaskInfo.taskId, "caption_bar_button", ResizeTrigger.MAXIMIZE_BUTTON, mMotionEvent); } } else if (id == R.id.minimize_window) { mDesktopTasksController.minimizeTask(decoration.mTaskInfo); Loading @@ -807,6 +828,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, @Override public boolean onTouch(View v, MotionEvent e) { mMotionEvent = e; final int id = v.getId(); final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) { Loading Loading @@ -897,6 +919,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, */ @Override public boolean onGenericMotion(View v, MotionEvent ev) { mMotionEvent = ev; final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); final int id = v.getId(); if (ev.getAction() == ACTION_HOVER_ENTER && id == R.id.maximize_window) { Loading Loading @@ -1040,7 +1063,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, taskInfo, decoration.mTaskSurface, position, new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)), newTaskBounds, decoration.calculateValidDragArea(), new Rect(mOnDragStartInitialBounds)); new Rect(mOnDragStartInitialBounds), e); if (touchingButton && !mHasLongClicked) { // We need the input event to not be consumed here to end the ripple // effect on the touched button. We will reset drag state in the ensuing Loading Loading @@ -1087,7 +1110,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // Disallow double-tap to resize when in full immersive. return false; } onMaximizeOrRestore(mTaskId, "double_tap"); onMaximizeOrRestore(mTaskId, "double_tap", ResizeTrigger.DOUBLE_TAP_APP_HEADER, e); return true; } } Loading Loading @@ -1484,7 +1507,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mGenericLinksParser, mAssistContentRequester, mMultiInstanceHelper, mWindowDecorCaptionHandleRepository); mWindowDecorCaptionHandleRepository, mDesktopModeEventLogger); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final TaskPositioner taskPositioner = mTaskPositionerFactory.create( Loading @@ -1501,15 +1525,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(taskInfo, taskPositioner); windowDecoration.setOnMaximizeOrRestoreClickListener(() -> { onMaximizeOrRestore(taskInfo.taskId, "maximize_menu"); onMaximizeOrRestore(taskInfo.taskId, "maximize_menu", ResizeTrigger.MAXIMIZE_MENU, touchEventListener.mMotionEvent); return Unit.INSTANCE; }); windowDecoration.setOnLeftSnapClickListener(() -> { onSnapResize(taskInfo.taskId, true /* isLeft */); onSnapResize(taskInfo.taskId, /* isLeft= */ true, touchEventListener.mMotionEvent); return Unit.INSTANCE; }); windowDecoration.setOnRightSnapClickListener(() -> { onSnapResize(taskInfo.taskId, false /* isLeft */); onSnapResize(taskInfo.taskId, /* isLeft= */ false, touchEventListener.mMotionEvent); return Unit.INSTANCE; }); windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +8 −4 Original line number Diff line number Diff line Loading @@ -267,7 +267,8 @@ public abstract class WMShellModule { AppHandleEducationController appHandleEducationController, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, Loading Loading @@ -295,7 +296,8 @@ public abstract class WMShellModule { appHandleEducationController, windowDecorCaptionHandleRepository, desktopActivityOrientationHandler, focusTransitionObserver); focusTransitionObserver, desktopModeEventLogger); } return new CaptionWindowDecorViewModel( context, Loading Loading @@ -647,7 +649,8 @@ public abstract class WMShellModule { Optional<RecentTasksController> recentTasksController, InteractionJankMonitor interactionJankMonitor, InputManager inputManager, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, keyguardManager, Loading @@ -659,7 +662,8 @@ public abstract class WMShellModule { desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter, recentTasksController.orElse(null), interactionJankMonitor, mainHandler, inputManager, focusTransitionObserver); inputManager, focusTransitionObserver, desktopModeEventLogger); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt +103 −9 Original line number Diff line number Diff line Loading @@ -16,11 +16,20 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.util.Size import android.view.InputDevice.SOURCE_MOUSE import android.view.InputDevice.SOURCE_TOUCHSCREEN import android.view.MotionEvent import android.view.MotionEvent.TOOL_TYPE_FINGER import android.view.MotionEvent.TOOL_TYPE_MOUSE import android.view.MotionEvent.TOOL_TYPE_STYLUS import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.internal.util.FrameworkStatsLog import com.android.window.flags.Flags import com.android.wm.shell.EventLogTags import com.android.wm.shell.common.DisplayController import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import java.security.SecureRandom import java.util.Random Loading Loading @@ -176,7 +185,13 @@ class DesktopModeEventLogger { * Logs that a task resize event is starting with [taskSizeUpdate] within a Desktop mode * session. */ fun logTaskResizingStarted(taskSizeUpdate: TaskSizeUpdate) { fun logTaskResizingStarted( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, taskInfo: RunningTaskInfo, displayController: DisplayController? = null, displayLayoutSize: Size? = null, ) { if (!Flags.enableResizingMetrics()) return val sessionId = currentSessionId.get() Loading @@ -188,11 +203,19 @@ class DesktopModeEventLogger { return } val taskSizeUpdate = createTaskSizeUpdate( resizeTrigger, motionEvent, taskInfo, displayController = displayController, displayLayoutSize = displayLayoutSize, ) ProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeLogger: Logging task resize is starting, session: %s taskId: %s", "DesktopModeLogger: Logging task resize is starting, session: %s, taskSizeUpdate: %s", sessionId, taskSizeUpdate.instanceId taskSizeUpdate ) logTaskSizeUpdated( FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZING_STAGE__START_RESIZING_STAGE, Loading @@ -203,7 +226,15 @@ class DesktopModeEventLogger { /** * Logs that a task resize event is ending with [taskSizeUpdate] within a Desktop mode session. */ fun logTaskResizingEnded(taskSizeUpdate: TaskSizeUpdate) { fun logTaskResizingEnded( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, taskInfo: RunningTaskInfo, taskHeight: Int? = null, taskWidth: Int? = null, displayController: DisplayController? = null, displayLayoutSize: Size? = null, ) { if (!Flags.enableResizingMetrics()) return val sessionId = currentSessionId.get() Loading @@ -215,18 +246,61 @@ class DesktopModeEventLogger { return } val taskSizeUpdate = createTaskSizeUpdate( resizeTrigger, motionEvent, taskInfo, taskHeight, taskWidth, displayController, displayLayoutSize, ) ProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeLogger: Logging task resize is ending, session: %s taskId: %s", "DesktopModeLogger: Logging task resize is ending, session: %s, taskSizeUpdate: %s", sessionId, taskSizeUpdate.instanceId taskSizeUpdate ) logTaskSizeUpdated( FrameworkStatsLog.DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZING_STAGE__END_RESIZING_STAGE, sessionId, taskSizeUpdate ) } private fun createTaskSizeUpdate( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, taskInfo: RunningTaskInfo, taskHeight: Int? = null, taskWidth: Int? = null, displayController: DisplayController? = null, displayLayoutSize: Size? = null, ): TaskSizeUpdate { val taskBounds = taskInfo.configuration.windowConfiguration.bounds val height = taskHeight ?: taskBounds.height() val width = taskWidth ?: taskBounds.width() val displaySize = when { displayLayoutSize != null -> displayLayoutSize.height * displayLayoutSize.width displayController != null -> displayController.getDisplayLayout(taskInfo.displayId) ?.let { it.height() * it.width() } else -> null } return TaskSizeUpdate( resizeTrigger, getInputMethodFromMotionEvent(motionEvent), taskInfo.taskId, taskInfo.effectiveUid, height, width, displaySize, ) } fun logTaskInfoStateInit() { logTaskUpdate( FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INIT_STATSD, Loading @@ -238,7 +312,8 @@ class DesktopModeEventLogger { taskHeight = 0, taskWidth = 0, taskX = 0, taskY = 0) taskY = 0 ) ) } Loading Loading @@ -314,7 +389,7 @@ class DesktopModeEventLogger { /* task_width */ taskSizeUpdate.taskWidth, /* display_area */ taskSizeUpdate.displayArea taskSizeUpdate.displayArea ?: -1 ) } Loading Loading @@ -364,8 +439,23 @@ class DesktopModeEventLogger { val uid: Int, val taskHeight: Int, val taskWidth: Int, val displayArea: Int, val displayArea: Int?, ) private fun getInputMethodFromMotionEvent(e: MotionEvent?): InputMethod { if (e == null) return InputMethod.UNKNOWN_INPUT_METHOD val toolType = e.getToolType( e.findPointerIndex(e.getPointerId(0)) ) return when { toolType == TOOL_TYPE_STYLUS -> InputMethod.STYLUS toolType == TOOL_TYPE_MOUSE -> InputMethod.MOUSE toolType == TOOL_TYPE_FINGER && e.source == SOURCE_MOUSE -> InputMethod.TOUCHPAD toolType == TOOL_TYPE_FINGER && e.source == SOURCE_TOUCHSCREEN -> InputMethod.TOUCH else -> InputMethod.UNKNOWN_INPUT_METHOD } } // Default value used when the task was not minimized. @VisibleForTesting Loading Loading @@ -499,6 +589,10 @@ class DesktopModeEventLogger { FrameworkStatsLog .DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZE_TRIGGER__SNAP_RIGHT_MENU_RESIZE_TRIGGER ), MAXIMIZE_MENU( FrameworkStatsLog .DESKTOP_MODE_TASK_SIZE_UPDATED__RESIZE_TRIGGER__MAXIMIZE_MENU_RESIZE_TRIGGER ), } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +54 −8 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.util.Size import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent import android.view.KeyEvent import android.view.MotionEvent import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_CLOSE Loading Loading @@ -125,7 +126,7 @@ import java.io.PrintWriter import java.util.Optional import java.util.concurrent.Executor import java.util.function.Consumer import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger /** Handles moving tasks in and out of desktop */ class DesktopTasksController( private val context: Context, Loading Loading @@ -158,6 +159,7 @@ class DesktopTasksController( @ShellMainThread private val handler: Handler, private val inputManager: InputManager, private val focusTransitionObserver: FocusTransitionObserver, private val desktopModeEventLogger: DesktopModeEventLogger, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, Loading Loading @@ -747,7 +749,11 @@ class DesktopTasksController( * bounds) and a free floating state (either the last saved bounds if available or the default * bounds otherwise). */ fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) { fun toggleDesktopTaskSize( taskInfo: RunningTaskInfo, resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, ) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val stableBounds = Rect().apply { displayLayout.getStableBounds(this) } Loading Loading @@ -794,7 +800,10 @@ class DesktopTasksController( taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding) val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds) desktopModeEventLogger.logTaskResizingEnded( resizeTrigger, motionEvent, taskInfo, destinationBounds.height(), destinationBounds.width(), displayController ) toggleResizeDesktopTaskTransitionHandler.startTransition(wct) } Loading Loading @@ -884,9 +893,19 @@ class DesktopTasksController( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, currentDragBounds: Rect, position: SnapPosition position: SnapPosition, resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, ) { val destinationBounds = getSnapBounds(taskInfo, position) desktopModeEventLogger.logTaskResizingEnded( resizeTrigger, motionEvent, taskInfo, destinationBounds.height(), destinationBounds.width(), displayController, ) if (destinationBounds == taskInfo.configuration.windowConfiguration.bounds) { // Handle the case where we attempt to snap resize when already snap resized: the task // position won't need to change but we want to animate the surface going back to the Loading Loading @@ -915,7 +934,8 @@ class DesktopTasksController( position: SnapPosition, taskSurface: SurfaceControl, currentDragBounds: Rect, dragStartBounds: Rect dragStartBounds: Rect, motionEvent: MotionEvent, ) { releaseVisualIndicator() if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) { Loading @@ -932,10 +952,25 @@ class DesktopTasksController( isResizable = taskInfo.isResizeable, ) } else { val resizeTrigger = if (position == SnapPosition.LEFT) { ResizeTrigger.DRAG_LEFT } else { ResizeTrigger.DRAG_RIGHT } desktopModeEventLogger.logTaskResizingStarted( resizeTrigger, motionEvent, taskInfo, displayController ) interactionJankMonitor.begin( taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable" ) snapToHalfScreen(taskInfo, taskSurface, currentDragBounds, position) snapToHalfScreen( taskInfo, taskSurface, currentDragBounds, position, resizeTrigger, motionEvent, ) } } Loading Loading @@ -1735,6 +1770,7 @@ class DesktopTasksController( currentDragBounds: Rect, validDragArea: Rect, dragStartBounds: Rect, motionEvent: MotionEvent, ) { if (taskInfo.configuration.windowConfiguration.windowingMode != WINDOWING_MODE_FREEFORM) { return Loading @@ -1755,12 +1791,22 @@ class DesktopTasksController( } IndicatorType.TO_SPLIT_LEFT_INDICATOR -> { handleSnapResizingTask( taskInfo, SnapPosition.LEFT, taskSurface, currentDragBounds, dragStartBounds taskInfo, SnapPosition.LEFT, taskSurface, currentDragBounds, dragStartBounds, motionEvent, ) } IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> { handleSnapResizingTask( taskInfo, SnapPosition.RIGHT, taskSurface, currentDragBounds, dragStartBounds taskInfo, SnapPosition.RIGHT, taskSurface, currentDragBounds, dragStartBounds, motionEvent, ) } IndicatorType.NO_INDICATOR -> { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +1 −0 Original line number Diff line number Diff line Loading @@ -274,6 +274,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL closeDragResizeListener(); mDragResizeListener = new DragResizeInputListener( mContext, mTaskInfo, mHandler, mChoreographer, mDisplay.getDisplayId(), Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +39 −14 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static android.view.WindowInsets.Type.statusBars; import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU; import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing; import static com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR; Loading Loading @@ -103,6 +104,7 @@ 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.desktopmode.DesktopActivityOrientationChangeHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; Loading Loading @@ -221,6 +223,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, }; private final TaskPositionerFactory mTaskPositionerFactory; private final FocusTransitionObserver mFocusTransitionObserver; private final DesktopModeEventLogger mDesktopModeEventLogger; public DesktopModeWindowDecorViewModel( Context context, Loading Loading @@ -248,7 +251,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, AppHandleEducationController appHandleEducationController, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { this( context, shellExecutor, Loading Loading @@ -281,7 +285,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, windowDecorCaptionHandleRepository, activityOrientationChangeHandler, new TaskPositionerFactory(), focusTransitionObserver); focusTransitionObserver, desktopModeEventLogger); } @VisibleForTesting Loading Loading @@ -317,7 +322,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, TaskPositionerFactory taskPositionerFactory, FocusTransitionObserver focusTransitionObserver) { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; Loading Loading @@ -378,6 +384,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, }; mTaskPositionerFactory = taskPositionerFactory; mFocusTransitionObserver = focusTransitionObserver; mDesktopModeEventLogger = desktopModeEventLogger; shellInit.addInitCallback(this::onInit, this); } Loading Loading @@ -547,15 +554,20 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, >= MANAGE_WINDOWS_MINIMUM_INSTANCES); } private void onMaximizeOrRestore(int taskId, String source) { private void onMaximizeOrRestore(int taskId, String source, ResizeTrigger resizeTrigger, MotionEvent motionEvent) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent, decoration.mTaskInfo, mDisplayController, /* displayLayoutSize= */ null); mInteractionJankMonitor.begin( decoration.mTaskSurface, mContext, mMainHandler, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source); mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo); mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo, resizeTrigger, motionEvent); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); } Loading @@ -568,7 +580,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopTasksController.toggleDesktopTaskFullImmersiveState(decoration.mTaskInfo); } private void onSnapResize(int taskId, boolean left) { private void onSnapResize(int taskId, boolean left, MotionEvent motionEvent) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; Loading @@ -579,13 +591,20 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, Toast.makeText(mContext, R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show(); } else { ResizeTrigger resizeTrigger = left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU; mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent, decoration.mTaskInfo, mDisplayController, /* displayLayoutSize= */ null); mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler, Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable"); mDesktopTasksController.snapToHalfScreen( decoration.mTaskInfo, decoration.mTaskSurface, decoration.mTaskInfo.configuration.windowConfiguration.getBounds(), left ? SnapPosition.LEFT : SnapPosition.RIGHT); left ? SnapPosition.LEFT : SnapPosition.RIGHT, resizeTrigger, motionEvent); } decoration.closeHandleMenu(); Loading Loading @@ -737,6 +756,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private boolean mTouchscreenInUse; private boolean mHasLongClicked; private int mDragPointerId = -1; private MotionEvent mMotionEvent; private DesktopModeTouchEventListener( RunningTaskInfo taskInfo, Loading Loading @@ -798,7 +818,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } else { // Full immersive is disabled or task doesn't request/support it, so just // toggle between maximize/restore states. onMaximizeOrRestore(decoration.mTaskInfo.taskId, "caption_bar_button"); onMaximizeOrRestore(decoration.mTaskInfo.taskId, "caption_bar_button", ResizeTrigger.MAXIMIZE_BUTTON, mMotionEvent); } } else if (id == R.id.minimize_window) { mDesktopTasksController.minimizeTask(decoration.mTaskInfo); Loading @@ -807,6 +828,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, @Override public boolean onTouch(View v, MotionEvent e) { mMotionEvent = e; final int id = v.getId(); final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) { Loading Loading @@ -897,6 +919,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, */ @Override public boolean onGenericMotion(View v, MotionEvent ev) { mMotionEvent = ev; final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); final int id = v.getId(); if (ev.getAction() == ACTION_HOVER_ENTER && id == R.id.maximize_window) { Loading Loading @@ -1040,7 +1063,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, taskInfo, decoration.mTaskSurface, position, new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)), newTaskBounds, decoration.calculateValidDragArea(), new Rect(mOnDragStartInitialBounds)); new Rect(mOnDragStartInitialBounds), e); if (touchingButton && !mHasLongClicked) { // We need the input event to not be consumed here to end the ripple // effect on the touched button. We will reset drag state in the ensuing Loading Loading @@ -1087,7 +1110,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // Disallow double-tap to resize when in full immersive. return false; } onMaximizeOrRestore(mTaskId, "double_tap"); onMaximizeOrRestore(mTaskId, "double_tap", ResizeTrigger.DOUBLE_TAP_APP_HEADER, e); return true; } } Loading Loading @@ -1484,7 +1507,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mGenericLinksParser, mAssistContentRequester, mMultiInstanceHelper, mWindowDecorCaptionHandleRepository); mWindowDecorCaptionHandleRepository, mDesktopModeEventLogger); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final TaskPositioner taskPositioner = mTaskPositionerFactory.create( Loading @@ -1501,15 +1525,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(taskInfo, taskPositioner); windowDecoration.setOnMaximizeOrRestoreClickListener(() -> { onMaximizeOrRestore(taskInfo.taskId, "maximize_menu"); onMaximizeOrRestore(taskInfo.taskId, "maximize_menu", ResizeTrigger.MAXIMIZE_MENU, touchEventListener.mMotionEvent); return Unit.INSTANCE; }); windowDecoration.setOnLeftSnapClickListener(() -> { onSnapResize(taskInfo.taskId, true /* isLeft */); onSnapResize(taskInfo.taskId, /* isLeft= */ true, touchEventListener.mMotionEvent); return Unit.INSTANCE; }); windowDecoration.setOnRightSnapClickListener(() -> { onSnapResize(taskInfo.taskId, false /* isLeft */); onSnapResize(taskInfo.taskId, /* isLeft= */ false, touchEventListener.mMotionEvent); return Unit.INSTANCE; }); windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> { Loading