diff options
24 files changed, 297 insertions, 39 deletions
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index f20503cef705..91add2783c0d 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -249,6 +249,11 @@ interface IActivityTaskManager { /** Returns an interface enabling the management of window organizers. */ IWindowOrganizerController getWindowOrganizerController(); + /** + * Sets whether we are currently in an interactive split screen resize operation where we + * are changing the docked stack size. + */ + void setSplitScreenResizing(boolean resizing); boolean supportsLocalVoiceInteraction(); // Get device configuration diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 9d95d0b705ef..84a233ffd2ad 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -394,7 +394,7 @@ public abstract class WallpaperService extends Service { public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, - int syncSeqId, boolean dragResizing) { + int syncSeqId, int resizeMode) { Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED, reportDraw ? 1 : 0, mergedConfiguration); diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index d554514349c3..8e16f24b154f 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -57,7 +57,7 @@ oneway interface IWindow { void resized(in ClientWindowFrames frames, boolean reportDraw, in MergedConfiguration newMergedConfiguration, in InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, - int syncSeqId, boolean dragResizing); + int syncSeqId, int resizeMode); /** * Called when this window retrieved control over a specified set of insets sources. diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0aba80db5378..6d9f99f76958 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -457,6 +457,12 @@ interface IWindowManager int getDockedStackSide(); /** + * Sets the region the user can touch the divider. This region will be excluded from the region + * which is used to cause a focus switch when dispatching touch. + */ + void setDockedTaskDividerTouchRegion(in Rect touchableRegion); + + /** * Registers a listener that will be called when the pinned task state changes. */ void registerPinnedTaskListener(int displayId, IPinnedTaskListener listener); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index eaa6820c6864..33b58d762412 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -51,6 +51,8 @@ import static android.view.ViewRootImplProto.WIDTH; import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES; import static android.view.ViewRootImplProto.WIN_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; +import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM; +import static android.view.WindowCallbacks.RESIZE_MODE_INVALID; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -513,6 +515,7 @@ public final class ViewRootImpl implements ViewParent, private boolean mPendingDragResizing; private boolean mDragResizing; private boolean mInvalidateRootRequested; + private int mResizeMode = RESIZE_MODE_INVALID; private int mCanvasOffsetX; private int mCanvasOffsetY; private boolean mActivityRelaunched; @@ -1790,7 +1793,7 @@ public final class ViewRootImpl implements ViewParent, CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration); final boolean forceNextWindowRelayout = args.argi1 != 0; final int displayId = args.argi3; - final boolean dragResizing = args.argi5 != 0; + final int resizeMode = args.argi5; final Rect frame = frames.frame; final Rect displayFrame = frames.displayFrame; @@ -1806,14 +1809,16 @@ public final class ViewRootImpl implements ViewParent, final boolean attachedFrameChanged = LOCAL_LAYOUT && !Objects.equals(mTmpFrames.attachedFrame, attachedFrame); final boolean displayChanged = mDisplay.getDisplayId() != displayId; + final boolean resizeModeChanged = mResizeMode != resizeMode; final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale; if (msg == MSG_RESIZED && !frameChanged && !configChanged && !attachedFrameChanged - && !displayChanged && !forceNextWindowRelayout + && !displayChanged && !resizeModeChanged && !forceNextWindowRelayout && !compatScaleChanged) { return; } - mPendingDragResizing = dragResizing; + mPendingDragResizing = resizeMode != RESIZE_MODE_INVALID; + mResizeMode = resizeMode; mTmpFrames.compatScale = compatScale; mInvCompatScale = 1f / compatScale; @@ -3010,7 +3015,7 @@ public final class ViewRootImpl implements ViewParent, frame.width() < desiredWindowWidth && frame.width() != mWidth) || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && frame.height() < desiredWindowHeight && frame.height() != mHeight)); - windowShouldResize |= mDragResizing && mPendingDragResizing; + windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM; // If the activity was just relaunched, it might have unfrozen the task bounds (while // relaunching), so we need to force a call into window manager to pick up the latest @@ -3257,7 +3262,7 @@ public final class ViewRootImpl implements ViewParent, && mWinFrame.height() == mPendingBackDropFrame.height(); // TODO: Need cutout? startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame, - mAttachInfo.mContentInsets, mAttachInfo.mStableInsets); + mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mResizeMode); } else { // We shouldn't come here, but if we come we should end the resize. endDragResizing(); @@ -8825,7 +8830,7 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void dispatchResized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, - boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) { + boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) { Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); SomeArgs args = SomeArgs.obtain(); final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid()); @@ -8847,7 +8852,7 @@ public final class ViewRootImpl implements ViewParent, args.argi2 = alwaysConsumeSystemBars ? 1 : 0; args.argi3 = displayId; args.argi4 = syncSeqId; - args.argi5 = dragResizing ? 1 : 0; + args.argi5 = resizeMode; msg.obj = args; mHandler.sendMessage(msg); @@ -10239,11 +10244,11 @@ public final class ViewRootImpl implements ViewParent, public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, - boolean dragResizing) { + int resizeMode) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState, - forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing); + forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, resizeMode); } } @@ -10448,13 +10453,13 @@ public final class ViewRootImpl implements ViewParent, * Start a drag resizing which will inform all listeners that a window resize is taking place. */ private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, - Rect stableInsets) { + Rect stableInsets, int resizeMode) { if (!mDragResizing) { mDragResizing = true; if (mUseMTRenderer) { for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { mWindowCallbacks.get(i).onWindowDragResizeStart( - initialBounds, fullscreen, systemInsets, stableInsets); + initialBounds, fullscreen, systemInsets, stableInsets, resizeMode); } } mFullRedrawNeeded = true; diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java index 94b2d93455d3..a7f0ef0a0324 100644 --- a/core/java/android/view/WindowCallbacks.java +++ b/core/java/android/view/WindowCallbacks.java @@ -28,6 +28,22 @@ import android.graphics.Rect; */ public interface WindowCallbacks { + int RESIZE_MODE_INVALID = -1; + + /** + * The window is being resized by dragging one of the window corners, + * in this case the surface would be fullscreen-sized. The client should + * render to the actual frame location (instead of (0,curScrollY)). + */ + int RESIZE_MODE_FREEFORM = 0; + + /** + * The window is being resized by dragging on the docked divider. The client should render + * at (0, 0) and extend its background to the background frame passed into + * {@link IWindow#resized}. + */ + int RESIZE_MODE_DOCKED_DIVIDER = 1; + /** * Called by the system when the window got changed by the user, before the layouter got called. * It also gets called when the insets changed, or when the window switched between a fullscreen @@ -53,7 +69,7 @@ public interface WindowCallbacks { * @param stableInsets The stable insets for the window. */ void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets, - Rect stableInsets); + Rect stableInsets, int resizeMode); /** * Called when a drag resize ends. diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 2d6c1d913e90..69340aa39daf 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.WindowCallbacks.RESIZE_MODE_INVALID; + import android.annotation.Nullable; import android.content.res.Configuration; import android.graphics.PixelFormat; @@ -548,7 +550,7 @@ public class WindowlessWindowManager implements IWindowSession { mTmpConfig.setConfiguration(mConfiguration, mConfiguration); s.mClient.resized(mTmpFrames, false /* reportDraw */, mTmpConfig, state, false /* forceLayout */, false /* alwaysConsumeSystemBars */, s.mDisplayId, - Integer.MAX_VALUE, false /* dragResizing */); + Integer.MAX_VALUE, RESIZE_MODE_INVALID); } catch (RemoteException e) { // Too bad } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index b5b27f5289c9..145aeafb46a1 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -274,6 +274,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private boolean mApplyFloatingVerticalInsets = false; private boolean mApplyFloatingHorizontalInsets = false; + private int mResizeMode = RESIZE_MODE_INVALID; private final int mResizeShadowSize; private final Paint mVerticalResizeShadowPaint = new Paint(); private final Paint mHorizontalResizeShadowPaint = new Paint(); @@ -807,7 +808,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateElevation(); mAllowUpdateElevation = true; - if (changed && mDrawLegacyNavigationBarBackground) { + if (changed + && (mResizeMode == RESIZE_MODE_DOCKED_DIVIDER + || mDrawLegacyNavigationBarBackground)) { getViewRootImpl().requestInvalidateRootRenderNode(); } } @@ -2389,7 +2392,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets, - Rect stableInsets) { + Rect stableInsets, int resizeMode) { if (mWindow.isDestroyed()) { // If the owner's window is gone, we should not be able to come here anymore. releaseThreadedRenderer(); @@ -2415,6 +2418,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateColorViews(null /* insets */, false); } + mResizeMode = resizeMode; getViewRootImpl().requestInvalidateRootRenderNode(); } @@ -2422,6 +2426,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind public void onWindowDragResizeEnd() { releaseThreadedRenderer(); updateColorViews(null /* insets */, false); + mResizeMode = RESIZE_MODE_INVALID; getViewRootImpl().requestInvalidateRootRenderNode(); } @@ -2466,7 +2471,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } private void drawResizingShadowIfNeeded(RecordingCanvas canvas) { - if (mWindow.mIsFloating || mWindow.isTranslucent() || mWindow.isShowingWallpaper()) { + if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating + || mWindow.isTranslucent() + || mWindow.isShowingWallpaper()) { return; } canvas.save(); diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index 4a5ed7e8970d..2ac43099c741 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -53,7 +53,7 @@ public class BaseIWindow extends IWindow.Stub { @Override public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, - boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing) { + boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) { if (reportDraw) { try { mSession.finishDrawing(this, null /* postDrawTransaction */, seqId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java index 94aeb2beb1e0..af13bf54f691 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java @@ -346,7 +346,7 @@ public class SystemWindows { public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration newMergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, - boolean dragResizing) {} + int resizeMode) {} @Override public void insetsControlChanged(InsetsState insetsState, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index 65da757b1396..9d6711f42efe 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -239,7 +239,7 @@ public class TaskSnapshotWindow { public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int seqId, - boolean dragResizing) { + int resizeMode) { final TaskSnapshotWindow snapshot = mOuter.get(); if (snapshot == null) { return; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 866fef76f3ca..eb04687d7d0c 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3616,6 +3616,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public void setSplitScreenResizing(boolean resizing) { + enforceTaskPermission("setSplitScreenResizing()"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + mTaskSupervisor.setSplitScreenResizing(resizing); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public IWindowOrganizerController getWindowOrganizerController() { return mWindowOrganizerController; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 23c2ec71336f..33c90a00234b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -207,6 +207,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Used to indicate that a task is removed it should also be removed from recents. static final boolean REMOVE_FROM_RECENTS = true; + /** True if the docked root task is currently being resized. */ + private boolean mDockedRootTaskResizing; + // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = new ArrayMap<>(); @@ -1523,6 +1526,15 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return mLaunchParamsController; } + void setSplitScreenResizing(boolean resizing) { + if (resizing == mDockedRootTaskResizing) { + return; + } + + mDockedRootTaskResizing = resizing; + mWindowManager.setDockedRootTaskResizing(resizing); + } + private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) { /** * Workaround: Force-stop all the activities in the root pinned task before we reparent them diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 169e7703b1ee..c6dc24f32837 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -525,6 +525,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** Remove this display when animation on it has completed. */ private boolean mDeferredRemoval; + final DockedTaskDividerController mDividerControllerLocked; final PinnedTaskController mPinnedTaskController; final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>(); @@ -1162,6 +1163,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplayPolicy.systemReady(); } mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius(); + mDividerControllerLocked = new DockedTaskDividerController(this); mPinnedTaskController = new PinnedTaskController(mWmService, this); final Transaction pendingTransaction = getPendingTransaction(); @@ -2592,6 +2594,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } + DockedTaskDividerController getDockedDividerController() { + return mDividerControllerLocked; + } + PinnedTaskController getPinnedTaskController() { return mPinnedTaskController; } diff --git a/services/core/java/com/android/server/wm/DockedTaskDividerController.java b/services/core/java/com/android/server/wm/DockedTaskDividerController.java new file mode 100644 index 000000000000..925a6d858a3d --- /dev/null +++ b/services/core/java/com/android/server/wm/DockedTaskDividerController.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 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.server.wm; + +import android.graphics.Rect; + +/** + * Keeps information about the docked task divider. + */ +public class DockedTaskDividerController { + + private final DisplayContent mDisplayContent; + private boolean mResizing; + + private final Rect mTouchRegion = new Rect(); + + DockedTaskDividerController(DisplayContent displayContent) { + mDisplayContent = displayContent; + } + + boolean isResizing() { + return mResizing; + } + + void setResizing(boolean resizing) { + if (mResizing != resizing) { + mResizing = resizing; + resetDragResizingChangeReported(); + } + } + + void setTouchRegion(Rect touchRegion) { + mTouchRegion.set(touchRegion); + // We need to report touchable region changes to accessibility. + if (mDisplayContent.mWmService.mAccessibilityController.hasCallbacks()) { + mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMoved( + mDisplayContent.getDisplayId()); + } + } + + void getTouchRegion(Rect outRegion) { + outRegion.set(mTouchRegion); + } + + private void resetDragResizingChangeReported() { + mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported, + true /* traverseTopToBottom */); + } +} diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java new file mode 100644 index 000000000000..684cf06e08b8 --- /dev/null +++ b/services/core/java/com/android/server/wm/DragResizeMode.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 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.server.wm; + +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + +/** + * Describes the mode in which a window is drag resizing. + */ +class DragResizeMode { + + /** + * Freeform mode: Client surface is fullscreen, and client is responsible to draw window at + * the correct position. + */ + static final int DRAG_RESIZE_MODE_FREEFORM = 0; + + /** + * Mode for resizing the docked (and adjacent) root task: Client surface is fullscreen, but + * window is drawn at (0, 0), window manager is responsible for positioning the surface when + * dragging. + */ + static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1; + + static boolean isModeAllowedForRootTask(Task rootTask, int mode) { + switch (mode) { + case DRAG_RESIZE_MODE_FREEFORM: + return rootTask.getWindowingMode() == WINDOWING_MODE_FREEFORM; + default: + return false; + } + } +} diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 7291e27840a9..07e3b836bd1d 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -469,6 +469,7 @@ class Task extends TaskFragment { // Whether the task is currently being drag-resized private boolean mDragResizing; + private int mDragResizeMode; // This represents the last resolved activity values for this task // NOTE: This value needs to be persisted with each task @@ -2809,6 +2810,11 @@ class Task extends TaskFragment { } final Task rootTask = getRootTask(); + final DisplayContent displayContent = rootTask.getDisplayContent(); + // It doesn't matter if we in particular are part of the resize, since we couldn't have + // a DimLayer anyway if we weren't visible. + final boolean dockedResizing = displayContent != null + && displayContent.mDividerControllerLocked.isResizing(); if (inFreeformWindowingMode()) { boolean[] foundTop = { false }; forAllActivities(a -> { getMaxVisibleBounds(a, out, foundTop); }); @@ -2819,10 +2825,18 @@ class Task extends TaskFragment { if (!matchParentBounds()) { // When minimizing the root docked task when going home, we don't adjust the task bounds - // so we need to intersect the task bounds with the root task bounds here.. - rootTask.getBounds(mTmpRect); - mTmpRect.intersect(getBounds()); - out.set(mTmpRect); + // so we need to intersect the task bounds with the root task bounds here. + // + // If we are Docked Resizing with snap points, the task bounds could be smaller than the + // root task bounds and so we don't even want to use them. Even if the app should not be + // resized the Dim should keep up with the divider. + if (dockedResizing) { + rootTask.getBounds(out); + } else { + rootTask.getBounds(mTmpRect); + mTmpRect.intersect(getBounds()); + out.set(mTmpRect); + } } else { out.set(getBounds()); } @@ -2853,15 +2867,16 @@ class Task extends TaskFragment { } } - void setDragResizing(boolean dragResizing) { + void setDragResizing(boolean dragResizing, int dragResizeMode) { if (mDragResizing != dragResizing) { - // No need to check if allowed if it's leaving dragResize + // No need to check if the mode is allowed if it's leaving dragResize if (dragResizing - && !(getRootTask().getWindowingMode() == WINDOWING_MODE_FREEFORM)) { - throw new IllegalArgumentException("Drag resize not allow for root task id=" - + getRootTaskId()); + && !DragResizeMode.isModeAllowedForRootTask(getRootTask(), dragResizeMode)) { + throw new IllegalArgumentException("Drag resize mode not allow for root task id=" + + getRootTaskId() + " dragResizeMode=" + dragResizeMode); } mDragResizing = dragResizing; + mDragResizeMode = dragResizeMode; resetDragResizingChangeReported(); } } @@ -2870,6 +2885,10 @@ class Task extends TaskFragment { return mDragResizing; } + int getDragResizeMode() { + return mDragResizeMode; + } + void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { if (displayContent == null) { return; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 9b3fb6b881c4..5b32149b818d 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -27,6 +27,7 @@ import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -367,7 +368,7 @@ class TaskPositioner implements IBinder.DeathRecipient { private void endDragLocked() { mResizing = false; - mTask.setDragResizing(false); + mTask.setDragResizing(false, DRAG_RESIZE_MODE_FREEFORM); } /** Returns true if the move operation should be ended. */ @@ -379,7 +380,7 @@ class TaskPositioner implements IBinder.DeathRecipient { if (mCtrlType != CTRL_NONE) { resizeDrag(x, y); - mTask.setDragResizing(true); + mTask.setDragResizing(true, DRAG_RESIZE_MODE_FREEFORM); return false; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 23bce36fc5d4..be1e7e6977fa 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7128,6 +7128,20 @@ public class WindowManagerService extends IWindowManager.Stub return 0; } + void setDockedRootTaskResizing(boolean resizing) { + getDefaultDisplayContentLocked().getDockedDividerController().setResizing(resizing); + requestTraversal(); + } + + @Override + public void setDockedTaskDividerTouchRegion(Rect touchRegion) { + synchronized (mGlobalLock) { + final DisplayContent dc = getDefaultDisplayContentLocked(); + dc.getDockedDividerController().setTouchRegion(touchRegion); + dc.updateTouchExcludeRegion(); + } + } + void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) { synchronized (mGlobalLock) { mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays; diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 9b69369d8195..72411727361a 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -51,6 +51,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; @@ -721,7 +722,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING) != 0) { - tr.setDragResizing(c.getDragResizing()); + tr.setDragResizing(c.getDragResizing(), DRAG_RESIZE_MODE_FREEFORM); } final int childWindowingMode = c.getActivityWindowingMode(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 4d6f7bc5011e..1b7bd9e1f36f 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -36,6 +36,9 @@ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE; +import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER; +import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM; +import static android.view.WindowCallbacks.RESIZE_MODE_INVALID; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.systemBars; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; @@ -120,6 +123,8 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE import static com.android.server.wm.AnimationSpecProto.MOVE; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; @@ -365,6 +370,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP boolean mHidden = true; // Used to determine if to show child windows. private boolean mDragResizing; private boolean mDragResizingChangeReported = true; + private int mResizeMode; private boolean mRedrawForSyncReported; /** @@ -3938,14 +3944,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (isDragResizeChanged) { setDragResizing(); } - final boolean isDragResizing = isDragResizing(); + int resizeMode = RESIZE_MODE_INVALID; + if (isDragResizing()) { + switch (getResizeMode()) { + case DRAG_RESIZE_MODE_FREEFORM: + resizeMode = RESIZE_MODE_FREEFORM; + break; + case DRAG_RESIZE_MODE_DOCKED_DIVIDER: + resizeMode = RESIZE_MODE_DOCKED_DIVIDER; + break; + } + } markRedrawForSyncReported(); try { mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration, getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId, - syncWithBuffers ? mSyncSeqId : -1, isDragResizing); + syncWithBuffers ? mSyncSeqId : -1, resizeMode); if (drawPending && prevRotation >= 0 && prevRotation != mLastReportedConfiguration .getMergedConfiguration().windowConfiguration.getRotation()) { mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime(); @@ -4188,6 +4204,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP super.resetDragResizingChangeReported(); } + int getResizeMode() { + return mResizeMode; + } + private boolean computeDragResizing() { final Task task = getTask(); if (task == null) { @@ -4210,7 +4230,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return true; } - return false; + return getDisplayContent().mDividerControllerLocked.isResizing() + && !task.inFreeformWindowingMode() && !isGoneForLayout(); } void setDragResizing() { @@ -4219,12 +4240,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } mDragResizing = resizing; + final Task task = getTask(); + if (task != null && task.isDragResizing()) { + mResizeMode = task.getDragResizeMode(); + } else { + mResizeMode = mDragResizing && getDisplayContent().mDividerControllerLocked.isResizing() + ? DRAG_RESIZE_MODE_DOCKED_DIVIDER + : DRAG_RESIZE_MODE_FREEFORM; + } } boolean isDragResizing() { return mDragResizing; } + boolean isDockedResizing() { + return (mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER) + || (isChildWindow() && getParentWindow().isDockedResizing()); + } + @CallSuper @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @@ -5900,6 +5934,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // level. Because the animation runs before display is rotated, task bounds should // represent the frames in display space coordinates. outFrame.set(getTask().getBounds()); + } else if (isDockedResizing()) { + // If we are animating while docked resizing, then use the root task bounds as the + // animation target (which will be different than the task bounds) + outFrame.set(getTask().getParent().getBounds()); } else { outFrame.set(getParentFrame()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 982137b00bfc..f983fa9b49e3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -3284,7 +3284,7 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput); verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(), insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(), - anyBoolean()); + anyInt()); assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java index 3f8acc651110..6e72bf360295 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java @@ -46,7 +46,7 @@ public class TestIWindow extends IWindow.Stub { @Override public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfig, InsetsState insetsState, boolean forceLayout, - boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing) + boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) throws RemoteException { } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 183ccceec4f4..69e3244af1b6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -276,9 +276,12 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(imeWindow.canBeImeTarget()); // Simulate the window is in split screen root task. + final DockedTaskDividerController controller = + mDisplayContent.getDockedDividerController(); final Task rootTask = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); spyOn(appWindow); + spyOn(controller); spyOn(rootTask); rootTask.setFocusable(false); doReturn(rootTask).when(appWindow).getRootTask(); @@ -772,7 +775,7 @@ public class WindowStateTests extends WindowTestsBase { anyBoolean() /* reportDraw */, any() /* mergedConfig */, any() /* insetsState */, anyBoolean() /* forceLayout */, anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */, - anyInt() /* seqId */, anyBoolean() /* dragResizing */); + anyInt() /* seqId */, anyInt() /* resizeMode */); } catch (RemoteException ignored) { } win.reportResized(); |