From f66db43063e4409206f1572fa1bac4f87c431f9a Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 13 Jan 2016 10:39:51 -0800 Subject: [PATCH] Several fixes for docking non-resizeable tasks - Keep track of original task bounds and scrolled bounds separately, so that we can reset the scrolling when the it's no longer in effect. - Calculate the vertical offset for the toast on top half using the content rect. The original toast position was relative to the bottom of the content rect, not the display rect. - Move toast display to prepareSurfaceLocked, as performShowLocked() may not be called if the app surface is already shown. related-to: b/26451625 related-to: b/26447921 Change-Id: I82113683c9e3c3beb4938dbd0829d0abf491efd9 --- .../com/android/server/wm/DisplayContent.java | 4 + .../core/java/com/android/server/wm/Task.java | 74 +++++++++++++++---- .../java/com/android/server/wm/TaskStack.java | 6 +- .../com/android/server/wm/WindowState.java | 6 +- .../server/wm/WindowStateAnimator.java | 9 ++- 5 files changed, 74 insertions(+), 25 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a9025bda2fbcb..0c429e5a1cd25 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -222,6 +222,10 @@ class DisplayContent { out.set(left, top, left + width, top + height); } + void getContentRect(Rect out) { + out.set(mContentRect); + } + /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */ void attachStack(TaskStack stack, boolean onTop) { if (stack.mStackId == HOME_STACK_ID) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6bb3e20727e88..832a298d74317 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -63,6 +63,9 @@ class Task implements DimLayer.DimLayerUser { private Rect mBounds = new Rect(); final Rect mPreparedFrozenBounds = new Rect(); + private Rect mPreScrollBounds = new Rect(); + private boolean mScrollValid; + // Bounds used to calculate the insets. private final Rect mTempInsetBounds = new Rect(); @@ -127,12 +130,25 @@ class Task implements DimLayer.DimLayerUser { int yOffset = 0; if (dockSide != DOCKED_INVALID) { mStack.getBounds(mTmpRect); - displayContent.getLogicalDisplayRect(mTmpRect2); if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) { + // The toast was originally placed at the bottom and centered. To place it + // at the bottom-center of the stack, we offset it horizontally by the diff + // between the center of the stack bounds vs. the center of the screen. + displayContent.getLogicalDisplayRect(mTmpRect2); xOffset = mTmpRect.centerX() - mTmpRect2.centerX(); } else if (dockSide == DOCKED_TOP) { + // The toast was originally placed at the bottom and centered. To place it + // at the bottom center of the top stack, we offset it vertically by the diff + // between the bottom of the stack bounds vs. the bottom of the content rect. + // + // Note here we use the content rect instead of the display rect, as we want + // the toast's distance to the dock divider (when it's placed at the top half) + // to be the same as it's distance to the top of the navigation bar (when it's + // placed at the bottom). + // We don't adjust for DOCKED_BOTTOM case since it's already at the bottom. + displayContent.getContentRect(mTmpRect2); yOffset = mTmpRect2.bottom - mTmpRect.bottom; } mService.mH.obtainMessage( @@ -258,19 +274,23 @@ class Task implements DimLayer.DimLayerUser { // Can't set to fullscreen if we don't have a display to get bounds from... return BOUNDS_CHANGE_NONE; } - if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { + if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { return BOUNDS_CHANGE_NONE; } int boundsChange = BOUNDS_CHANGE_NONE; - if (mBounds.left != bounds.left || mBounds.top != bounds.top) { + if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) { boundsChange |= BOUNDS_CHANGE_POSITION; } - if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) { + if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) { boundsChange |= BOUNDS_CHANGE_SIZE; } - mBounds.set(bounds); + + mPreScrollBounds.set(bounds); + + resetScrollLocked(); + mRotation = rotation; if (displayContent != null) { displayContent.mDimLayerController.updateDimLayer(this); @@ -331,6 +351,32 @@ class Task implements DimLayer.DimLayerUser { mPreparedFrozenBounds.set(mBounds); } + void resetScrollLocked() { + if (mScrollValid) { + mScrollValid = false; + applyScrollToAllWindows(0, 0); + } + mBounds.set(mPreScrollBounds); + } + + void applyScrollToAllWindows(final int xOffset, final int yOffset) { + for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { + final ArrayList windows = mAppTokens.get(activityNdx).allAppWindows; + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + final WindowState win = windows.get(winNdx); + win.mXOffset = xOffset; + win.mYOffset = yOffset; + } + } + } + + void applyScrollToWindowIfNeeded(final WindowState win) { + if (mScrollValid) { + win.mXOffset = mBounds.left; + win.mYOffset = mBounds.top; + } + } + boolean scrollLocked(Rect bounds) { // shift the task bound if it doesn't fully cover the stack area mStack.getDimBounds(mTmpRect); @@ -352,21 +398,17 @@ class Task implements DimLayer.DimLayerUser { } } - if (bounds.equals(mBounds)) { + // We can stop here if we're already scrolling and the scrolled bounds not changed. + if (mScrollValid && bounds.equals(mBounds)) { return false; } + // Normal setBounds() does not allow non-null bounds for fullscreen apps. // We only change bounds for the scrolling case without change it size, // on resizing path we should still want the validation. mBounds.set(bounds); - for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { - final ArrayList windows = mAppTokens.get(activityNdx).allAppWindows; - for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { - final WindowState win = windows.get(winNdx); - win.mXOffset = bounds.left; - win.mYOffset = bounds.top; - } - } + mScrollValid = true; + applyScrollToAllWindows(bounds.left, bounds.top); return true; } @@ -483,7 +525,7 @@ class Task implements DimLayer.DimLayerUser { // Device rotation changed. We don't want the task to move around on the screen when // this happens, so update the task bounds so it stays in the same place. - mTmpRect2.set(mBounds); + mTmpRect2.set(mPreScrollBounds); displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) { // Post message to inform activity manager of the bounds change simulating @@ -492,7 +534,7 @@ class Task implements DimLayer.DimLayerUser { // are resizeable independently of their stack resizing. if (mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { mService.mH.sendMessage(mService.mH.obtainMessage( - RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds)); + RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds)); } } } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 27d6e03703dff..f4140f0c0c5bf 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -136,8 +136,8 @@ public class TaskStack implements DimLayer.DimLayerUser { // it might no longer fully cover the stack area. // Save the old bounds and re-apply the scroll. This adjusts the bounds to // fit the new stack bounds. - task.getBounds(mTmpRect); task.setBounds(bounds, config); + task.getBounds(mTmpRect); task.scrollLocked(mTmpRect); } else { task.setBounds(bounds, config); @@ -365,6 +365,10 @@ public class TaskStack implements DimLayer.DimLayerUser { "positionTask: task=" + task + " position=" + position); mTasks.add(position, task); + // If we are moving the task across stacks, the scroll is no longer valid. + if (task.mStack != this) { + task.resetScrollLocked(); + } task.mStack = this; task.updateDisplayInfo(mDisplayContent); boolean toTop = position == mTasks.size() - 1; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 058fa67a5e4a8..c10d9556bc167 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1469,10 +1469,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { void applyScrollIfNeeded() { final Task task = getTask(); - if (task != null && task.isTwoFingerScrollMode()) { - task.getDimBounds(mTmpRect); - mXOffset = mTmpRect.left; - mYOffset = mTmpRect.top; + if (task != null) { + task.applyScrollToWindowIfNeeded(this); } } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 83ab19094fb0e..a3a59c009b501 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1355,6 +1355,11 @@ class WindowStateAnimator { } } w.mToken.hasVisible = true; + + final Task task = w.getTask(); + if (task != null) { + task.scheduleShowNonResizeableDockToastIfNeeded(); + } } } @@ -1513,10 +1518,6 @@ class WindowStateAnimator { mWin.mAppToken.updateReportedVisibilityLocked(); } - final Task task = mWin.getTask(); - if (task != null) { - task.scheduleShowNonResizeableDockToastIfNeeded(); - } return true; } return false;