diff options
| author | 2022-11-04 00:04:41 +0000 | |
|---|---|---|
| committer | 2022-11-11 00:48:49 +0000 | |
| commit | 5a95db047e8de46b31f63a0999ed06ec8656b621 (patch) | |
| tree | 254c66f8fb58636da1faacee1477ea8be3fab501 | |
| parent | 70b8153a79fdb6d3792fdb92762c34a278b63437 (diff) | |
Add WCT#setDragResizing to optimize fluid resizing
Allows WM Shell to indicate the start/end of drag resizing, which
core can use as a signal to reuse a single (larger) surface size
for the entire drag resize operation to avoid continuous buffer
allocations after each size change.
Bug: 249808500
Test: drag resize a freeform window, verify WindowLayout requests
a fullscreen sized surface; atest TaskPositionerTest
Change-Id: I27e2b44270d7ea4f701fa8037f93b20dc691284b
5 files changed, 198 insertions, 6 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index cfad1afe1b5b..fbf8d8bf9fe4 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -467,6 +467,23 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Sets whether a container is being drag-resized. + * When {@code true}, the client will reuse a single (larger) surface size to avoid + * continuous allocations on every size change. + * + * @param container WindowContainerToken of the task that changed its drag resizing state + * @hide + */ + @NonNull + public WindowContainerTransaction setDragResizing(@NonNull WindowContainerToken container, + boolean dragResizing) { + final Change change = getOrCreateChange(container.asBinder()); + change.mChangeMask |= Change.CHANGE_DRAG_RESIZING; + change.mDragResizing = dragResizing; + return this; + } + + /** * Sends a pending intent in sync. * @param sender The PendingIntent sender. * @param intent The fillIn intent to patch over the sender's base intent. @@ -906,12 +923,14 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5; public static final int CHANGE_FORCE_NO_PIP = 1 << 6; public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 7; + public static final int CHANGE_DRAG_RESIZING = 1 << 8; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; private boolean mHidden = false; private boolean mIgnoreOrientationRequest = false; private boolean mForceTranslucent = false; + private boolean mDragResizing = false; private int mChangeMask = 0; private @ActivityInfo.Config int mConfigSetMask = 0; @@ -932,6 +951,7 @@ public final class WindowContainerTransaction implements Parcelable { mHidden = in.readBoolean(); mIgnoreOrientationRequest = in.readBoolean(); mForceTranslucent = in.readBoolean(); + mDragResizing = in.readBoolean(); mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); @@ -980,6 +1000,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((other.mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) { mForceTranslucent = other.mForceTranslucent; } + if ((other.mChangeMask & CHANGE_DRAG_RESIZING) != 0) { + mDragResizing = other.mDragResizing; + } mChangeMask |= other.mChangeMask; if (other.mActivityWindowingMode >= 0) { mActivityWindowingMode = other.mActivityWindowingMode; @@ -1039,6 +1062,15 @@ public final class WindowContainerTransaction implements Parcelable { return mForceTranslucent; } + /** Gets the requested drag resizing state. */ + public boolean getDragResizing() { + if ((mChangeMask & CHANGE_DRAG_RESIZING) == 0) { + throw new RuntimeException("Drag resizing not set. " + + "Check CHANGE_DRAG_RESIZING first"); + } + return mDragResizing; + } + public int getChangeMask() { return mChangeMask; } @@ -1100,6 +1132,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((mChangeMask & CHANGE_FOCUSABLE) != 0) { sb.append("focusable:" + mFocusable + ","); } + if ((mChangeMask & CHANGE_DRAG_RESIZING) != 0) { + sb.append("dragResizing:" + mDragResizing + ","); + } if (mBoundsChangeTransaction != null) { sb.append("hasBoundsTransaction,"); } @@ -1117,6 +1152,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeBoolean(mHidden); dest.writeBoolean(mIgnoreOrientationRequest); dest.writeBoolean(mForceTranslucent); + dest.writeBoolean(mDragResizing); dest.writeInt(mChangeMask); dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index a352063aa6ee..f998a690f5a0 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -2402,7 +2402,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return; } final ThreadedRenderer renderer = getThreadedRenderer(); - if (renderer != null) { + if (renderer != null && !CAPTION_ON_SHELL) { loadBackgroundDrawablesIfNeeded(); WindowInsets rootInsets = getRootWindowInsets(); mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java index f0f2db7ded80..a49a300995e6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java @@ -40,6 +40,9 @@ class TaskPositioner implements DragResizeCallback { private final Rect mTaskBoundsAtDragStart = new Rect(); private final PointF mResizeStartPoint = new PointF(); private final Rect mResizeTaskBounds = new Rect(); + // Whether the |dragResizing| hint should be sent with the next bounds change WCT. + // Used to optimized fluid resizing of freeform tasks. + private boolean mPendingDragResizeHint = false; private int mCtrlType; private DragStartListener mDragStartListener; @@ -53,6 +56,12 @@ class TaskPositioner implements DragResizeCallback { @Override public void onDragResizeStart(int ctrlType, float x, float y) { + if (ctrlType != CTRL_TYPE_UNDEFINED) { + // The task is being resized, send the |dragResizing| hint to core with the first + // bounds-change wct. + mPendingDragResizeHint = true; + } + mDragStartListener.onDragStart(mWindowDecoration.mTaskInfo.taskId); mCtrlType = ctrlType; @@ -63,19 +72,31 @@ class TaskPositioner implements DragResizeCallback { @Override public void onDragResizeMove(float x, float y) { - changeBounds(x, y); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (changeBounds(wct, x, y)) { + if (mPendingDragResizeHint) { + // This is the first bounds change since drag resize operation started. + wct.setDragResizing(mWindowDecoration.mTaskInfo.token, true /* dragResizing */); + mPendingDragResizeHint = false; + } + mTaskOrganizer.applyTransaction(wct); + } } @Override public void onDragResizeEnd(float x, float y) { - changeBounds(x, y); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setDragResizing(mWindowDecoration.mTaskInfo.token, false /* dragResizing */); + changeBounds(wct, x, y); + mTaskOrganizer.applyTransaction(wct); mCtrlType = 0; mTaskBoundsAtDragStart.setEmpty(); mResizeStartPoint.set(0, 0); + mPendingDragResizeHint = false; } - private void changeBounds(float x, float y) { + private boolean changeBounds(WindowContainerTransaction wct, float x, float y) { float deltaX = x - mResizeStartPoint.x; mResizeTaskBounds.set(mTaskBoundsAtDragStart); if ((mCtrlType & CTRL_TYPE_LEFT) != 0) { @@ -96,10 +117,10 @@ class TaskPositioner implements DragResizeCallback { } if (!mResizeTaskBounds.isEmpty()) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mWindowDecoration.mTaskInfo.token, mResizeTaskBounds); - mTaskOrganizer.applyTransaction(wct); + return true; } + return false; } interface DragStartListener { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt new file mode 100644 index 000000000000..ac10ddb0116a --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt @@ -0,0 +1,130 @@ +package com.android.wm.shell.windowdecor + +import android.app.ActivityManager +import android.graphics.Rect +import android.os.IBinder +import android.testing.AndroidTestingRunner +import android.window.WindowContainerToken +import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_RIGHT +import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_UNDEFINED +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.argThat +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations + +/** + * Tests for [TaskPositioner]. + * + * Build/Install/Run: + * atest WMShellUnitTests:TaskPositionerTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class TaskPositionerTest : ShellTestCase() { + + @Mock + private lateinit var mockShellTaskOrganizer: ShellTaskOrganizer + @Mock + private lateinit var mockWindowDecoration: WindowDecoration<*> + @Mock + private lateinit var mockDragStartListener: TaskPositioner.DragStartListener + + @Mock + private lateinit var taskToken: WindowContainerToken + @Mock + private lateinit var taskBinder: IBinder + + private lateinit var taskPositioner: TaskPositioner + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + taskPositioner = TaskPositioner( + mockShellTaskOrganizer, + mockWindowDecoration, + mockDragStartListener + ) + `when`(taskToken.asBinder()).thenReturn(taskBinder) + mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { + taskId = TASK_ID + token = taskToken + configuration.windowConfiguration.bounds = STARTING_BOUNDS + } + } + + @Test + fun testDragResize_move_skipsDragResizingFlag() { + taskPositioner.onDragResizeStart( + CTRL_TYPE_UNDEFINED, // Move + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat() + ) + + // Move the task 10px to the right. + val newX = STARTING_BOUNDS.left.toFloat() + 10 + val newY = STARTING_BOUNDS.top.toFloat() + taskPositioner.onDragResizeMove( + newX, + newY + ) + + taskPositioner.onDragResizeEnd(newX, newY) + + verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> + return@argThat wct.changes.any { (token, change) -> + token == taskBinder && + ((change.changeMask and CHANGE_DRAG_RESIZING) != 0) && + change.dragResizing + } + }) + } + + @Test + fun testDragResize_resize_setsDragResizingFlag() { + taskPositioner.onDragResizeStart( + CTRL_TYPE_RIGHT, // Resize right + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat() + ) + + // Resize the task by 10px to the right. + val newX = STARTING_BOUNDS.right.toFloat() + 10 + val newY = STARTING_BOUNDS.top.toFloat() + taskPositioner.onDragResizeMove( + newX, + newY + ) + + taskPositioner.onDragResizeEnd(newX, newY) + + verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + return@argThat wct.changes.any { (token, change) -> + token == taskBinder && + ((change.changeMask and CHANGE_DRAG_RESIZING) != 0) && + change.dragResizing + } + }) + verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + return@argThat wct.changes.any { (token, change) -> + token == taskBinder && + ((change.changeMask and CHANGE_DRAG_RESIZING) != 0) && + !change.dragResizing + } + }) + } + + companion object { + private const val TASK_ID = 5 + private val STARTING_BOUNDS = Rect(0, 0, 100, 100) + } +} diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 32a110ea530e..53daf204fa89 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -48,6 +48,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED; import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; @@ -725,6 +726,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub effects = TRANSACT_EFFECTS_LIFECYCLE; } + if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING) != 0) { + tr.setDragResizing(c.getDragResizing(), DRAG_RESIZE_MODE_FREEFORM); + } + final int childWindowingMode = c.getActivityWindowingMode(); if (childWindowingMode > -1) { tr.setActivityWindowingMode(childWindowingMode); |