Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +12 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.DefaultDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; Loading Loading @@ -558,6 +559,7 @@ public abstract class WMShellModule { ReturnToDragStartAnimator returnToDragStartAnimator, EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler, ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler, DesktopModeDragAndDropTransitionHandler desktopModeDragAndDropTransitionHandler, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, DragToDesktopTransitionHandler dragToDesktopTransitionHandler, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, Loading @@ -573,7 +575,8 @@ public abstract class WMShellModule { displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, keyguardManager, returnToDragStartAnimator, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, exitDesktopTransitionHandler, desktopModeDragAndDropTransitionHandler, toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, desktopModeTaskRepository, desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter, Loading Loading @@ -653,6 +656,14 @@ public abstract class WMShellModule { transitions, context, interactionJankMonitor); } @WMSingleton @Provides static DesktopModeDragAndDropTransitionHandler provideDesktopModeDragAndDropTransitionHandler( Transitions transitions ) { return new DesktopModeDragAndDropTransitionHandler(transitions); } @WMSingleton @Provides @DynamicOverride Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeDragAndDropTransitionHandler.kt 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_OPEN import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TransitionFinishCallback /** * Transition handler for drag-and-drop (i.e., tab tear) transitions that occur in desktop mode. */ class DesktopModeDragAndDropTransitionHandler(private val transitions: Transitions) : Transitions.TransitionHandler { private val pendingTransitionTokens: MutableList<IBinder> = mutableListOf() /** * Begin a transition when a [android.app.PendingIntent] is dropped without a window to * accept it. */ fun handleDropEvent(wct: WindowContainerTransaction): IBinder { val token = transitions.startTransition(TRANSIT_OPEN, wct, this) pendingTransitionTokens.add(token) return token } override fun startAnimation( transition: IBinder, info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: TransitionFinishCallback ): Boolean { if (!pendingTransitionTokens.contains(transition)) return false val change = findRelevantChange(info) val leash = change.leash val endBounds = change.endAbsBounds startTransaction.hide(leash) .setWindowCrop(leash, endBounds.width(), endBounds.height()) .apply() val animator = ValueAnimator() animator.setFloatValues(0f, 1f) animator.setDuration(FADE_IN_ANIMATION_DURATION) val t = SurfaceControl.Transaction() animator.addListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator) { t.show(leash) t.apply() } override fun onAnimationEnd(animation: Animator) { finishCallback.onTransitionFinished(null) } }) animator.addUpdateListener { animation: ValueAnimator -> t.setAlpha(leash, animation.animatedFraction) t.apply() } animator.start() pendingTransitionTokens.remove(transition) return true } private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change { val matchingChanges = info.changes.filter { c -> isValidTaskChange(c) && c.mode == TRANSIT_OPEN } if (matchingChanges.size != 1) { throw IllegalStateException( "Expected 1 relevant change but found: ${matchingChanges.size}" ) } return matchingChanges.first() } private fun isValidTaskChange(change: TransitionInfo.Change): Boolean { return change.taskInfo != null && change.taskInfo?.taskId != -1 } override fun handleRequest( transition: IBinder, request: TransitionRequestInfo ): WindowContainerTransaction? { return null } companion object { const val FADE_IN_ANIMATION_DURATION = 300L } } libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +57 −25 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; Loading @@ -29,7 +28,6 @@ import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.WindowConfiguration; import android.content.Context; import android.content.res.Resources; import android.graphics.PixelFormat; Loading Loading @@ -70,6 +68,37 @@ public class DesktopModeVisualIndicator { TO_SPLIT_RIGHT_INDICATOR } /** * The conditions surrounding the drag event that led to the indicator's creation. */ public enum DragStartState { /** The indicator is resulting from a freeform task drag. */ FROM_FREEFORM, /** The indicator is resulting from a split screen task drag */ FROM_SPLIT, /** The indicator is resulting from a fullscreen task drag */ FROM_FULLSCREEN, /** The indicator is resulting from an Intent generated during a drag-and-drop event */ DRAGGED_INTENT; /** * Get the {@link DragStartState} of a drag event based on the windowing mode of the task. * Note that DRAGGED_INTENT will be specified by the caller if needed and not returned * here. */ public static DesktopModeVisualIndicator.DragStartState getDragStartState( ActivityManager.RunningTaskInfo taskInfo ) { if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { return FROM_FULLSCREEN; } else if (taskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { return FROM_SPLIT; } else if (taskInfo.isFreeform()) { return FROM_FREEFORM; } else return null; } } private final Context mContext; private final DisplayController mDisplayController; private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer; Loading @@ -82,11 +111,13 @@ public class DesktopModeVisualIndicator { private View mView; private IndicatorType mCurrentType; private DragStartState mDragStartState; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) { RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, DragStartState dragStartState) { mSyncQueue = syncQueue; mTaskInfo = taskInfo; mDisplayController = displayController; Loading @@ -94,6 +125,7 @@ public class DesktopModeVisualIndicator { mTaskSurface = taskSurface; mRootTdaOrganizer = taskDisplayAreaOrganizer; mCurrentType = IndicatorType.NO_INDICATOR; mDragStartState = dragStartState; } /** Loading @@ -101,7 +133,7 @@ public class DesktopModeVisualIndicator { * display, including no visible indicator. */ @NonNull IndicatorType updateIndicatorType(PointF inputCoordinates, int windowingMode) { IndicatorType updateIndicatorType(PointF inputCoordinates) { final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone. IndicatorType result = IndicatorType.NO_INDICATOR; Loading @@ -111,14 +143,13 @@ public class DesktopModeVisualIndicator { // account for the possibility of the task going off the top of the screen by captionHeight final int captionHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_freeform_decor_caption_height); final Region fullscreenRegion = calculateFullscreenRegion(layout, windowingMode, final Region fullscreenRegion = calculateFullscreenRegion(layout, captionHeight); final Region splitLeftRegion = calculateSplitLeftRegion(layout, transitionAreaWidth, captionHeight); final Region splitLeftRegion = calculateSplitLeftRegion(layout, windowingMode, transitionAreaWidth, captionHeight); final Region splitRightRegion = calculateSplitRightRegion(layout, windowingMode, transitionAreaWidth, captionHeight); final Region toDesktopRegion = calculateToDesktopRegion(layout, windowingMode, splitLeftRegion, splitRightRegion, fullscreenRegion); final Region splitRightRegion = calculateSplitRightRegion(layout, transitionAreaWidth, captionHeight); final Region toDesktopRegion = calculateToDesktopRegion(layout, splitLeftRegion, splitRightRegion, fullscreenRegion); if (fullscreenRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) { result = IndicatorType.TO_FULLSCREEN_INDICATOR; } Loading @@ -131,20 +162,22 @@ public class DesktopModeVisualIndicator { if (toDesktopRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) { result = IndicatorType.TO_DESKTOP_INDICATOR; } if (mDragStartState != DragStartState.DRAGGED_INTENT) { transitionIndicator(result); } return result; } @VisibleForTesting Region calculateFullscreenRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, int captionHeight) { Region calculateFullscreenRegion(DisplayLayout layout, int captionHeight) { final Region region = new Region(); int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM || mDragStartState == DragStartState.DRAGGED_INTENT ? mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness) : 2 * layout.stableInsets().top; // A Rect at the top of the screen that takes up the center 40%. if (windowingMode == WINDOWING_MODE_FREEFORM) { if (mDragStartState == DragStartState.FROM_FREEFORM) { final float toFullscreenScale = mContext.getResources().getFloat( R.dimen.desktop_mode_fullscreen_region_scale); final float toFullscreenWidth = (layout.width() * toFullscreenScale); Loading @@ -153,9 +186,11 @@ public class DesktopModeVisualIndicator { (int) ((layout.width() / 2f) + (toFullscreenWidth / 2f)), transitionHeight)); } // A screen-wide Rect if the task is in fullscreen or split. if (windowingMode == WINDOWING_MODE_FULLSCREEN || windowingMode == WINDOWING_MODE_MULTI_WINDOW) { // A screen-wide Rect if the task is in fullscreen, split, or a dragged intent. if (mDragStartState == DragStartState.FROM_FULLSCREEN || mDragStartState == DragStartState.FROM_SPLIT || mDragStartState == DragStartState.DRAGGED_INTENT ) { region.union(new Rect(0, -captionHeight, layout.width(), Loading @@ -166,12 +201,11 @@ public class DesktopModeVisualIndicator { @VisibleForTesting Region calculateToDesktopRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, Region splitLeftRegion, Region splitRightRegion, Region toFullscreenRegion) { final Region region = new Region(); // If in desktop, we need no region. Otherwise it's the same for all windowing modes. if (windowingMode != WINDOWING_MODE_FREEFORM) { if (mDragStartState != DragStartState.FROM_FREEFORM) { region.union(new Rect(0, 0, layout.width(), layout.height())); region.op(splitLeftRegion, Region.Op.DIFFERENCE); region.op(splitRightRegion, Region.Op.DIFFERENCE); Loading @@ -182,11 +216,10 @@ public class DesktopModeVisualIndicator { @VisibleForTesting Region calculateSplitLeftRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, int transitionEdgeWidth, int captionHeight) { final Region region = new Region(); // In freeform, keep the top corners clear. int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM ? mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_split_from_desktop_height) : -captionHeight; Loading @@ -196,11 +229,10 @@ public class DesktopModeVisualIndicator { @VisibleForTesting Region calculateSplitRightRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, int transitionEdgeWidth, int captionHeight) { final Region region = new Region(); // In freeform, keep the top corners clear. int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM ? mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_split_from_desktop_height) : -captionHeight; Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +87 −19 File changed.Preview size limit exceeded, changes collapsed. Show changes libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +14 −7 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.annotations.ExternalMainThread; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; Loading Loading @@ -127,7 +128,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll * drag. */ default boolean onUnhandledDrag(@NonNull PendingIntent launchIntent, @NonNull SurfaceControl dragSurface, @NonNull DragEvent dragEvent, @NonNull Consumer<Boolean> onFinishCallback) { return false; } Loading Loading @@ -329,9 +330,18 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll return false; } DragSession dragSession = null; if (event.getAction() == ACTION_DRAG_STARTED) { mActiveDragDisplay = displayId; pd.isHandlingDrag = DragUtils.canHandleDrag(event); dragSession = new DragSession(ActivityTaskManager.getInstance(), mDisplayController.getDisplayLayout(displayId), event.getClipData(), event.getDragFlags()); dragSession.initialize(); final ActivityManager.RunningTaskInfo taskInfo = dragSession.runningTaskInfo; // Desktop tasks will have their own drag handling. final boolean isDesktopDrag = taskInfo != null && taskInfo.isFreeform() && DesktopModeStatus.canEnterDesktopMode(mContext); pd.isHandlingDrag = DragUtils.canHandleDrag(event) && !isDesktopDrag; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s flags=%s", pd.isHandlingDrag, event.getClipData().getItemCount(), Loading @@ -349,10 +359,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll Slog.w(TAG, "Unexpected drag start during an active drag"); return false; } pd.dragSession = new DragSession(ActivityTaskManager.getInstance(), mDisplayController.getDisplayLayout(displayId), event.getClipData(), event.getDragFlags()); pd.dragSession.initialize(); pd.dragSession = dragSession; pd.activeDragCount++; pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession)); if (pd.dragSession.hideDragSourceTaskId != -1) { Loading Loading @@ -437,7 +444,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll } final boolean handled = notifyListeners( l -> l.onUnhandledDrag(launchIntent, dragEvent.getDragSurface(), onFinishCallback)); l -> l.onUnhandledDrag(launchIntent, dragEvent, onFinishCallback)); if (!handled) { // Nobody handled this, we still have to notify WM onFinishCallback.accept(false); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +12 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.DefaultDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; Loading Loading @@ -558,6 +559,7 @@ public abstract class WMShellModule { ReturnToDragStartAnimator returnToDragStartAnimator, EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler, ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler, DesktopModeDragAndDropTransitionHandler desktopModeDragAndDropTransitionHandler, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, DragToDesktopTransitionHandler dragToDesktopTransitionHandler, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, Loading @@ -573,7 +575,8 @@ public abstract class WMShellModule { displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, keyguardManager, returnToDragStartAnimator, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, exitDesktopTransitionHandler, desktopModeDragAndDropTransitionHandler, toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, desktopModeTaskRepository, desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter, Loading Loading @@ -653,6 +656,14 @@ public abstract class WMShellModule { transitions, context, interactionJankMonitor); } @WMSingleton @Provides static DesktopModeDragAndDropTransitionHandler provideDesktopModeDragAndDropTransitionHandler( Transitions transitions ) { return new DesktopModeDragAndDropTransitionHandler(transitions); } @WMSingleton @Provides @DynamicOverride Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeDragAndDropTransitionHandler.kt 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_OPEN import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TransitionFinishCallback /** * Transition handler for drag-and-drop (i.e., tab tear) transitions that occur in desktop mode. */ class DesktopModeDragAndDropTransitionHandler(private val transitions: Transitions) : Transitions.TransitionHandler { private val pendingTransitionTokens: MutableList<IBinder> = mutableListOf() /** * Begin a transition when a [android.app.PendingIntent] is dropped without a window to * accept it. */ fun handleDropEvent(wct: WindowContainerTransaction): IBinder { val token = transitions.startTransition(TRANSIT_OPEN, wct, this) pendingTransitionTokens.add(token) return token } override fun startAnimation( transition: IBinder, info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: TransitionFinishCallback ): Boolean { if (!pendingTransitionTokens.contains(transition)) return false val change = findRelevantChange(info) val leash = change.leash val endBounds = change.endAbsBounds startTransaction.hide(leash) .setWindowCrop(leash, endBounds.width(), endBounds.height()) .apply() val animator = ValueAnimator() animator.setFloatValues(0f, 1f) animator.setDuration(FADE_IN_ANIMATION_DURATION) val t = SurfaceControl.Transaction() animator.addListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator) { t.show(leash) t.apply() } override fun onAnimationEnd(animation: Animator) { finishCallback.onTransitionFinished(null) } }) animator.addUpdateListener { animation: ValueAnimator -> t.setAlpha(leash, animation.animatedFraction) t.apply() } animator.start() pendingTransitionTokens.remove(transition) return true } private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change { val matchingChanges = info.changes.filter { c -> isValidTaskChange(c) && c.mode == TRANSIT_OPEN } if (matchingChanges.size != 1) { throw IllegalStateException( "Expected 1 relevant change but found: ${matchingChanges.size}" ) } return matchingChanges.first() } private fun isValidTaskChange(change: TransitionInfo.Change): Boolean { return change.taskInfo != null && change.taskInfo?.taskId != -1 } override fun handleRequest( transition: IBinder, request: TransitionRequestInfo ): WindowContainerTransaction? { return null } companion object { const val FADE_IN_ANIMATION_DURATION = 300L } }
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +57 −25 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; Loading @@ -29,7 +28,6 @@ import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.WindowConfiguration; import android.content.Context; import android.content.res.Resources; import android.graphics.PixelFormat; Loading Loading @@ -70,6 +68,37 @@ public class DesktopModeVisualIndicator { TO_SPLIT_RIGHT_INDICATOR } /** * The conditions surrounding the drag event that led to the indicator's creation. */ public enum DragStartState { /** The indicator is resulting from a freeform task drag. */ FROM_FREEFORM, /** The indicator is resulting from a split screen task drag */ FROM_SPLIT, /** The indicator is resulting from a fullscreen task drag */ FROM_FULLSCREEN, /** The indicator is resulting from an Intent generated during a drag-and-drop event */ DRAGGED_INTENT; /** * Get the {@link DragStartState} of a drag event based on the windowing mode of the task. * Note that DRAGGED_INTENT will be specified by the caller if needed and not returned * here. */ public static DesktopModeVisualIndicator.DragStartState getDragStartState( ActivityManager.RunningTaskInfo taskInfo ) { if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { return FROM_FULLSCREEN; } else if (taskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { return FROM_SPLIT; } else if (taskInfo.isFreeform()) { return FROM_FREEFORM; } else return null; } } private final Context mContext; private final DisplayController mDisplayController; private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer; Loading @@ -82,11 +111,13 @@ public class DesktopModeVisualIndicator { private View mView; private IndicatorType mCurrentType; private DragStartState mDragStartState; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) { RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, DragStartState dragStartState) { mSyncQueue = syncQueue; mTaskInfo = taskInfo; mDisplayController = displayController; Loading @@ -94,6 +125,7 @@ public class DesktopModeVisualIndicator { mTaskSurface = taskSurface; mRootTdaOrganizer = taskDisplayAreaOrganizer; mCurrentType = IndicatorType.NO_INDICATOR; mDragStartState = dragStartState; } /** Loading @@ -101,7 +133,7 @@ public class DesktopModeVisualIndicator { * display, including no visible indicator. */ @NonNull IndicatorType updateIndicatorType(PointF inputCoordinates, int windowingMode) { IndicatorType updateIndicatorType(PointF inputCoordinates) { final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone. IndicatorType result = IndicatorType.NO_INDICATOR; Loading @@ -111,14 +143,13 @@ public class DesktopModeVisualIndicator { // account for the possibility of the task going off the top of the screen by captionHeight final int captionHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_freeform_decor_caption_height); final Region fullscreenRegion = calculateFullscreenRegion(layout, windowingMode, final Region fullscreenRegion = calculateFullscreenRegion(layout, captionHeight); final Region splitLeftRegion = calculateSplitLeftRegion(layout, transitionAreaWidth, captionHeight); final Region splitLeftRegion = calculateSplitLeftRegion(layout, windowingMode, transitionAreaWidth, captionHeight); final Region splitRightRegion = calculateSplitRightRegion(layout, windowingMode, transitionAreaWidth, captionHeight); final Region toDesktopRegion = calculateToDesktopRegion(layout, windowingMode, splitLeftRegion, splitRightRegion, fullscreenRegion); final Region splitRightRegion = calculateSplitRightRegion(layout, transitionAreaWidth, captionHeight); final Region toDesktopRegion = calculateToDesktopRegion(layout, splitLeftRegion, splitRightRegion, fullscreenRegion); if (fullscreenRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) { result = IndicatorType.TO_FULLSCREEN_INDICATOR; } Loading @@ -131,20 +162,22 @@ public class DesktopModeVisualIndicator { if (toDesktopRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) { result = IndicatorType.TO_DESKTOP_INDICATOR; } if (mDragStartState != DragStartState.DRAGGED_INTENT) { transitionIndicator(result); } return result; } @VisibleForTesting Region calculateFullscreenRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, int captionHeight) { Region calculateFullscreenRegion(DisplayLayout layout, int captionHeight) { final Region region = new Region(); int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM || mDragStartState == DragStartState.DRAGGED_INTENT ? mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness) : 2 * layout.stableInsets().top; // A Rect at the top of the screen that takes up the center 40%. if (windowingMode == WINDOWING_MODE_FREEFORM) { if (mDragStartState == DragStartState.FROM_FREEFORM) { final float toFullscreenScale = mContext.getResources().getFloat( R.dimen.desktop_mode_fullscreen_region_scale); final float toFullscreenWidth = (layout.width() * toFullscreenScale); Loading @@ -153,9 +186,11 @@ public class DesktopModeVisualIndicator { (int) ((layout.width() / 2f) + (toFullscreenWidth / 2f)), transitionHeight)); } // A screen-wide Rect if the task is in fullscreen or split. if (windowingMode == WINDOWING_MODE_FULLSCREEN || windowingMode == WINDOWING_MODE_MULTI_WINDOW) { // A screen-wide Rect if the task is in fullscreen, split, or a dragged intent. if (mDragStartState == DragStartState.FROM_FULLSCREEN || mDragStartState == DragStartState.FROM_SPLIT || mDragStartState == DragStartState.DRAGGED_INTENT ) { region.union(new Rect(0, -captionHeight, layout.width(), Loading @@ -166,12 +201,11 @@ public class DesktopModeVisualIndicator { @VisibleForTesting Region calculateToDesktopRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, Region splitLeftRegion, Region splitRightRegion, Region toFullscreenRegion) { final Region region = new Region(); // If in desktop, we need no region. Otherwise it's the same for all windowing modes. if (windowingMode != WINDOWING_MODE_FREEFORM) { if (mDragStartState != DragStartState.FROM_FREEFORM) { region.union(new Rect(0, 0, layout.width(), layout.height())); region.op(splitLeftRegion, Region.Op.DIFFERENCE); region.op(splitRightRegion, Region.Op.DIFFERENCE); Loading @@ -182,11 +216,10 @@ public class DesktopModeVisualIndicator { @VisibleForTesting Region calculateSplitLeftRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, int transitionEdgeWidth, int captionHeight) { final Region region = new Region(); // In freeform, keep the top corners clear. int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM ? mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_split_from_desktop_height) : -captionHeight; Loading @@ -196,11 +229,10 @@ public class DesktopModeVisualIndicator { @VisibleForTesting Region calculateSplitRightRegion(DisplayLayout layout, @WindowConfiguration.WindowingMode int windowingMode, int transitionEdgeWidth, int captionHeight) { final Region region = new Region(); // In freeform, keep the top corners clear. int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM int transitionHeight = mDragStartState == DragStartState.FROM_FREEFORM ? mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_split_from_desktop_height) : -captionHeight; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +87 −19 File changed.Preview size limit exceeded, changes collapsed. Show changes
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +14 −7 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.annotations.ExternalMainThread; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; Loading Loading @@ -127,7 +128,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll * drag. */ default boolean onUnhandledDrag(@NonNull PendingIntent launchIntent, @NonNull SurfaceControl dragSurface, @NonNull DragEvent dragEvent, @NonNull Consumer<Boolean> onFinishCallback) { return false; } Loading Loading @@ -329,9 +330,18 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll return false; } DragSession dragSession = null; if (event.getAction() == ACTION_DRAG_STARTED) { mActiveDragDisplay = displayId; pd.isHandlingDrag = DragUtils.canHandleDrag(event); dragSession = new DragSession(ActivityTaskManager.getInstance(), mDisplayController.getDisplayLayout(displayId), event.getClipData(), event.getDragFlags()); dragSession.initialize(); final ActivityManager.RunningTaskInfo taskInfo = dragSession.runningTaskInfo; // Desktop tasks will have their own drag handling. final boolean isDesktopDrag = taskInfo != null && taskInfo.isFreeform() && DesktopModeStatus.canEnterDesktopMode(mContext); pd.isHandlingDrag = DragUtils.canHandleDrag(event) && !isDesktopDrag; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s flags=%s", pd.isHandlingDrag, event.getClipData().getItemCount(), Loading @@ -349,10 +359,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll Slog.w(TAG, "Unexpected drag start during an active drag"); return false; } pd.dragSession = new DragSession(ActivityTaskManager.getInstance(), mDisplayController.getDisplayLayout(displayId), event.getClipData(), event.getDragFlags()); pd.dragSession.initialize(); pd.dragSession = dragSession; pd.activeDragCount++; pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession)); if (pd.dragSession.hideDragSourceTaskId != -1) { Loading Loading @@ -437,7 +444,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll } final boolean handled = notifyListeners( l -> l.onUnhandledDrag(launchIntent, dragEvent.getDragSurface(), onFinishCallback)); l -> l.onUnhandledDrag(launchIntent, dragEvent, onFinishCallback)); if (!handled) { // Nobody handled this, we still have to notify WM onFinishCallback.accept(false); Loading