OSDN Git Service

Fix IME adjust when stack focus changes while IME is visible
authorChong Zhang <chz@google.com>
Tue, 19 Apr 2016 04:02:01 +0000 (21:02 -0700)
committerChong Zhang <chz@google.com>
Wed, 20 Apr 2016 18:55:58 +0000 (11:55 -0700)
- Use two values to animate divider width adjustment separately
  from stack position adjustment. For example IME is visible
  with focus on bottom stack, then user clicks top stack. In this
  case bottom stack position should go back to unadjusted, but
  divider should remain thinner.

- If we need to start a new animation during an existing animation,
  start the motion from where the existing animation left off, so
  that it doesn't look discontinuous.

- Do not adjust if IME is not actually focused on any stack. This
  could happen when swiping down the status bar.

bug: 28175599
Change-Id: I802def5d1c13ebe11094eb28fc5a0b0c309e4d76

services/core/java/com/android/server/wm/DockedStackDividerController.java
services/core/java/com/android/server/wm/TaskStack.java
services/core/java/com/android/server/wm/WindowManagerService.java

index b90d0d1..8a003de 100644 (file)
@@ -116,6 +116,11 @@ public class DockedStackDividerController implements DimLayerUser {
     private boolean mAnimatingForIme;
     private boolean mAdjustedForIme;
     private WindowState mDelayedImeWin;
+    private boolean mAdjustedForDivider;
+    private float mDividerAnimationStart;
+    private float mDividerAnimationTarget;
+    private float mLastAnimationProgress;
+    private float mLastDividerProgress;
 
     DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -208,16 +213,18 @@ public class DockedStackDividerController implements DimLayerUser {
         return mLastVisibility;
     }
 
-    void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
-        if (mAdjustedForIme != adjusted) {
-            mAdjustedForIme = adjusted;
+    void setAdjustedForIme(
+            boolean adjustedForIme, boolean adjustedForDivider,
+            boolean animate, WindowState imeWin) {
+        if (mAdjustedForIme != adjustedForIme || mAdjustedForDivider != adjustedForDivider) {
             if (animate) {
-                startImeAdjustAnimation(adjusted, imeWin);
+                startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
             } else {
-
                 // Animation might be delayed, so only notify if we don't run an animation.
-                notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
+                notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
             }
+            mAdjustedForIme = adjustedForIme;
+            mAdjustedForDivider = adjustedForDivider;
         }
     }
 
@@ -457,11 +464,25 @@ public class DockedStackDividerController implements DimLayerUser {
         mAnimationTarget = to;
     }
 
-    private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
+    private void startImeAdjustAnimation(
+            boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
         mAnimatingForIme = true;
         mAnimationStarted = false;
-        mAnimationStart = adjusted ? 0 : 1;
-        mAnimationTarget = adjusted ? 1 : 0;
+
+        // If we're not in an animation, the starting point depends on whether we're adjusted
+        // or not. If we're already in an animation, we start from where the current animation
+        // left off, so that the motion doesn't look discontinuous.
+        if (!mAnimatingForIme) {
+            mAnimationStart = mAdjustedForIme ? 1 : 0;
+            mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
+            mLastAnimationProgress = mAnimationStart;
+            mLastDividerProgress = mDividerAnimationStart;
+        } else {
+            mAnimationStart = mLastAnimationProgress;
+            mDividerAnimationStart = mLastDividerProgress;
+        }
+        mAnimationTarget = adjustedForIme ? 1 : 0;
+        mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
 
         final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
         for (int i = stacks.size() - 1; i >= 0; --i) {
@@ -492,10 +513,12 @@ public class DockedStackDividerController implements DimLayerUser {
                 if (mDelayedImeWin != null) {
                     mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
                 }
-                notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+                notifyAdjustedForImeChanged(
+                        adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
             };
         } else {
-            notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+            notifyAdjustedForImeChanged(
+                    adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
         }
     }
 
@@ -539,11 +562,15 @@ public class DockedStackDividerController implements DimLayerUser {
         for (int i = stacks.size() - 1; i >= 0; --i) {
             final TaskStack stack = stacks.get(i);
             if (stack != null && stack.isAdjustedForIme()) {
-                if (t >= 1f && mAnimationTarget == 0f) {
+                if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
                     stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                     updated = true;
                 } else {
-                    updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
+                    mLastAnimationProgress = getInterpolatedAnimationValue(t);
+                    mLastDividerProgress = getInterpolatedDividerValue(t);
+                    updated |= stack.updateAdjustForIme(
+                            mLastAnimationProgress,
+                            mLastDividerProgress,
                             false /* force */);
                 }
                 if (t >= 1f) {
@@ -555,6 +582,8 @@ public class DockedStackDividerController implements DimLayerUser {
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
         if (t >= 1.0f) {
+            mLastAnimationProgress = mAnimationTarget;
+            mLastDividerProgress = mDividerAnimationTarget;
             mAnimatingForIme = false;
             return false;
         } else {
@@ -596,6 +625,10 @@ public class DockedStackDividerController implements DimLayerUser {
         return t * mAnimationTarget + (1 - t) * mAnimationStart;
     }
 
+    private float getInterpolatedDividerValue(float t) {
+        return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
+    }
+
     /**
      * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
      */
index 1fd2b1f..a289855 100644 (file)
@@ -126,6 +126,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
     private WindowState mImeWin;
     private float mMinimizeAmount;
     private float mAdjustImeAmount;
+    private float mAdjustDividerAmount;
     private final int mDockedStackMinimizeThickness;
 
     // If this is true, we are in the bounds animating mode.
@@ -853,7 +854,8 @@ public class TaskStack implements DimLayer.DimLayerUser,
         if (!mAdjustedForIme) {
             mAdjustedForIme = true;
             mAdjustImeAmount = 0f;
-            updateAdjustForIme(0f, true /* force */);
+            mAdjustDividerAmount = 0f;
+            updateAdjustForIme(0f, 0f, true /* force */);
         }
     }
 
@@ -873,9 +875,11 @@ public class TaskStack implements DimLayer.DimLayerUser,
      *
      * @return true if a traversal should be performed after the adjustment.
      */
-    boolean updateAdjustForIme(float adjustAmount, boolean force) {
-        if (adjustAmount != mAdjustImeAmount || force) {
+    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
+        if (adjustAmount != mAdjustImeAmount
+                || adjustDividerAmount != mAdjustDividerAmount || force) {
             mAdjustImeAmount = adjustAmount;
+            mAdjustDividerAmount = adjustDividerAmount;
             updateAdjustedBounds();
             return isVisibleForUserLocked();
         } else {
@@ -895,6 +899,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
             mAdjustedForIme = false;
             mImeGoingAway = false;
             mAdjustImeAmount = 0f;
+            mAdjustDividerAmount = 0f;
             updateAdjustedBounds();
             mService.setResizeDimLayer(false, mStackId, 1.0f);
         } else {
@@ -992,25 +997,27 @@ public class TaskStack implements DimLayer.DimLayerUser,
                     (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
             mFullyAdjustedImeBounds.set(mBounds);
         } else {
-            final int top;
-            final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
-            if (isFocusedStack) {
-                // If this stack is docked on bottom and has focus, we shift it up so that it's not
-                // occluded by IME. We try to move it up by the height of the IME window, but only
-                // to the extent that leaves at least 30% of the top stack visible.
-                final int minTopStackBottom =
-                        getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
-                top = Math.max(
-                        mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
-            } else {
-                // If this stack is docked on bottom but doesn't have focus, we don't need to adjust
-                // for IME, but still need to apply a small adjustment due to the thinner divider.
-                top = mBounds.top - dividerWidth + dividerWidthInactive;
-            }
+            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
+            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
+
+            // When the stack is on bottom and has focus, it needs to be moved up so as to
+            // not occluded by IME, and at the same time adjusted for divider width.
+            // We try to move it up by the height of the IME window, but only to the extent
+            // that leaves at least 30% of the top stack visible.
+            // 'top' is where the top of bottom stack will move to in this case.
+            final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
+            final int minTopStackBottom =
+                    getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
+            final int top = Math.max(
+                    mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
 
             mTmpAdjustedBounds.set(mBounds);
-            mTmpAdjustedBounds.top =
-                    (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top);
+            // Account for the adjustment for IME and divider width separately.
+            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
+            // and dividerWidthDelta is due to divider width change only.
+            mTmpAdjustedBounds.top = mBounds.top +
+                    (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
+                            mAdjustDividerAmount * dividerWidthDelta);
             mFullyAdjustedImeBounds.set(mBounds);
             mFullyAdjustedImeBounds.top = top;
             mFullyAdjustedImeBounds.bottom = top + mBounds.height();
@@ -1082,9 +1089,10 @@ public class TaskStack implements DimLayer.DimLayerUser,
         }
         setAdjustedBounds(mTmpAdjustedBounds);
 
-        final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
-        if (mAdjustedForIme && adjust && !isFocusedStack) {
-            final float alpha = mAdjustImeAmount * IME_ADJUST_DIM_AMOUNT;
+        final boolean isImeTarget = (mService.getImeTargetStackLocked() == this);
+        if (mAdjustedForIme && adjust && !isImeTarget) {
+            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
+                    * IME_ADJUST_DIM_AMOUNT;
             mService.setResizeDimLayer(true, mStackId, alpha);
         }
     }
index 38f12a1..9994af3 100644 (file)
@@ -7455,27 +7455,38 @@ public class WindowManagerService extends IWindowManager.Stub
 
     void adjustForImeIfNeeded(final DisplayContent displayContent) {
         final WindowState imeWin = mInputMethodWindow;
-        final TaskStack focusedStack = getFocusedStackLocked();
+        final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw();
         final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
-        if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
-                && dockVisible && focusedStack != null) {
-            final boolean isFocusOnBottom = focusedStack.getDockSide() == DOCKED_BOTTOM;
+        final TaskStack imeTargetStack = getImeTargetStackLocked();
+
+        // The divider could be adjusted for IME position, or be thinner than usual,
+        // or both. There are three possible cases:
+        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
+        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
+        // - If IME is not visible, divider is not moved and is normal width.
+
+        if (imeVisible && dockVisible && imeTargetStack != null) {
+            final boolean isFocusOnBottom = imeTargetStack.getDockSide() == DOCKED_BOTTOM;
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
                 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
                 if (stack.isVisibleLocked() && (isFocusOnBottom || isDockedOnBottom)) {
                     stack.setAdjustedForIme(imeWin);
+                } else {
+                    stack.resetAdjustedForIme(false);
                 }
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, imeWin);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(
+                    isFocusOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin);
         } else {
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
                 stack.resetAdjustedForIme(!dockVisible);
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible, imeWin);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(
+                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, null);
         }
     }
 
@@ -7608,8 +7619,10 @@ public class WindowManagerService extends IWindowManager.Stub
         return mCurrentFocus;
     }
 
-    TaskStack getFocusedStackLocked() {
-        return mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+    TaskStack getImeTargetStackLocked() {
+        // Don't use WindowState.getStack() because it returns home stack for system windows.
+        Task imeTask = mInputMethodTarget != null ? mInputMethodTarget.getTask() : null;
+        return imeTask != null ? imeTask.mStack : null;
     }
 
     private void showAuditSafeModeNotification() {
@@ -9354,7 +9367,6 @@ public class WindowManagerService extends IWindowManager.Stub
         WindowState newFocus = computeFocusedWindowLocked();
         if (mCurrentFocus != newFocus) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
-            TaskStack oldFocusedStack = getFocusedStackLocked();
             // This check makes sure that we don't already have the focus
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
@@ -9376,7 +9388,6 @@ public class WindowManagerService extends IWindowManager.Stub
             mLosingFocus.remove(newFocus);
 
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
-            TaskStack newFocusedStack = getFocusedStackLocked();
 
             if (imWindowChanged && oldFocus != mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
@@ -9406,18 +9417,6 @@ public class WindowManagerService extends IWindowManager.Stub
                 mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
             }
 
-            // TODO: Reset and re-apply IME adjustment if needed when stack focus changed.
-            // This makes sure divider starts an animation from pre-adjust position to final
-            // position. Ideally we want to skip the reset and animation from current position
-            // directly to final position.
-            final WindowState imeWin = mInputMethodWindow;
-            if (oldFocusedStack != null) {
-                oldFocusedStack.resetAdjustedForIme(true);
-            }
-            if (newFocusedStack != null) {
-                newFocusedStack.resetAdjustedForIme(true);
-            }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(false, false, imeWin);
             adjustForImeIfNeeded(displayContent);
 
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);