diff options
| author | 2016-04-13 20:17:43 -0700 | |
|---|---|---|
| committer | 2016-04-14 20:45:45 -0700 | |
| commit | eb88d83fc5da8ea05033c03bbb9f0d4b804ba162 (patch) | |
| tree | d86fa563f3370a86caba49ce4b223b59b514d1cc | |
| parent | be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5 (diff) | |
Add nice animation when adjusting for IME in multi-window
- Run a separate animation when we need to adjust for the IME. We
can't use the attached animation because the adjustment animation
needs to be longer than the IME animation.
- Also run an animation when IME is disappearing.
- Adjust IME exit animation to better match with adjustment exit
animation.
- Make sure to update adjust for IME when entry/exit animation of
IME is starting, to avoid flickers.
- Don't update the IME window in PhoneWindowManager for layout
until the animation has started. This lead to an issue where the
content inset was set too large too early.
Bug: 27154882
Bug: 28175599
Change-Id: I09a33413e307f84d6c3cf4ae928c280f7ad48348
6 files changed, 116 insertions, 77 deletions
diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml index 117774aff802..575404d2775f 100644 --- a/core/res/res/anim/input_method_exit.xml +++ b/core/res/res/anim/input_method_exit.xml @@ -17,10 +17,10 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> - <translate android:fromYDelta="0" android:toYDelta="10%" - android:interpolator="@interpolator/accelerate_quint" - android:duration="@android:integer/config_shortAnimTime"/> + <translate android:fromYDelta="0" android:toYDelta="8%" + android:interpolator="@interpolator/fast_out_linear_in" + android:duration="150"/> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:interpolator="@interpolator/accelerate_cubic" - android:duration="@android:integer/config_shortAnimTime"/> + android:interpolator="@interpolator/fast_out_linear_in" + android:duration="150"/> </set> diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2e81132cebf8..8f259db4c924 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4754,7 +4754,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw() - && !win.getGivenInsetsPendingLw()) { + && win.isDisplayedLw() && !win.getGivenInsetsPendingLw()) { setLastInputMethodWindowLw(null, null); offsetInputMethodWindowLw(win); } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index ff537bef1aa9..7d76759760a1 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -38,6 +38,7 @@ import android.view.IDockedStackListener; import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; import com.android.server.wm.DimLayer.DimLayerUser; @@ -74,6 +75,11 @@ public class DockedStackDividerController implements DimLayerUser { */ private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f; + private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR = + new PathInterpolator(0.1f, 0f, 0.1f, 1f); + + private static final long IME_ADJUST_DURATION = 280; + private final WindowManagerService mService; private final DisplayContent mDisplayContent; private int mDividerWindowWidth; @@ -188,8 +194,10 @@ public class DockedStackDividerController implements DimLayerUser { void setAdjustedForIme(boolean adjusted, boolean animate) { if (mAdjustedForIme != adjusted) { - mAnimatingForIme = animate; mAdjustedForIme = adjusted; + if (animate) { + startImeAdjustAnimation(adjusted ? 0 : 1, adjusted ? 1 : 0); + } } } @@ -371,7 +379,7 @@ public class DockedStackDividerController implements DimLayerUser { return; } - mAnimatingForIme = false; + clearImeAdjustAnimation(); if (minimizedDock) { if (animate) { startAdjustAnimation(0f, 1f); @@ -387,6 +395,17 @@ public class DockedStackDividerController implements DimLayerUser { } } + private void clearImeAdjustAnimation() { + final ArrayList<TaskStack> stacks = mDisplayContent.getStacks(); + for (int i = stacks.size() - 1; i >= 0; --i) { + final TaskStack stack = stacks.get(i); + if (stack != null && stack.isAdjustedForIme()) { + stack.resetAdjustedForIme(true /* adjustBoundsNow */); + } + } + mAnimatingForIme = false; + } + private void startAdjustAnimation(float from, float to) { mAnimatingForMinimizedDockedStack = true; mAnimationStarted = false; @@ -394,6 +413,13 @@ public class DockedStackDividerController implements DimLayerUser { mAnimationTarget = to; } + private void startImeAdjustAnimation(float from, float to) { + mAnimatingForIme = true; + mAnimationStarted = false; + mAnimationStart = from; + mAnimationTarget = to; + } + private void setMinimizedDockedStack(boolean minimized) { final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked(); notifyDockedStackMinimizedChanged(minimized, 0); @@ -413,39 +439,44 @@ public class DockedStackDividerController implements DimLayerUser { if (mAnimatingForMinimizedDockedStack) { return animateForMinimizedDockedStack(now); } else if (mAnimatingForIme) { - return animateForIme(); + return animateForIme(now); } else { return false; } } - private boolean animateForIme() { - boolean updated = false; - boolean animating = false; - + private boolean animateForIme(long now) { + if (!mAnimationStarted) { + mAnimationStarted = true; + mAnimationStartTime = now; + mAnimationDuration = (long) + (IME_ADJUST_DURATION * mService.getWindowAnimationScaleLocked()); + } + float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration); + t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR) + .getInterpolation(t); final ArrayList<TaskStack> stacks = mDisplayContent.getStacks(); + boolean updated = false; for (int i = stacks.size() - 1; i >= 0; --i) { final TaskStack stack = stacks.get(i); if (stack != null && stack.isAdjustedForIme()) { - updated |= stack.updateAdjustForIme(); - animating |= stack.isAnimatingForIme(); + if (t >= 1f && mAnimationTarget == 0f) { + stack.resetAdjustedForIme(true /* adjustBoundsNow */); + updated = true; + } else { + updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t)); + } } } - if (updated) { mService.mWindowPlacerLocked.performSurfacePlacement(); } - - if (!animating) { + if (t >= 1.0f) { mAnimatingForIme = false; - for (int i = stacks.size() - 1; i >= 0; --i) { - final TaskStack stack = stacks.get(i); - if (stack != null) { - stack.clearImeGoingAway(); - } - } + return false; + } else { + return true; } - return animating; } private boolean animateForMinimizedDockedStack(long now) { @@ -478,11 +509,15 @@ public class DockedStackDividerController implements DimLayerUser { } } + private float getInterpolatedAnimationValue(float t) { + return t * mAnimationTarget + (1 - t) * mAnimationStart; + } + /** * Gets the amount how much to minimize a stack depending on the interpolated fraction t. */ private float getMinimizeAmount(TaskStack stack, float t) { - final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart; + final float naturalAmount = getInterpolatedAnimationValue(t); if (isAnimationMaximizing()) { return adjustMaximizeAmount(stack, t, naturalAmount); } else { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 7074a83a812f..0a08a54e9189 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -40,6 +40,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.DisplayInfo; import android.view.Surface; +import android.view.animation.PathInterpolator; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; @@ -52,14 +53,6 @@ import java.util.ArrayList; public class TaskStack implements DimLayer.DimLayerUser, BoundsAnimationController.AnimateBoundsUser { - // If the stack should be resized to fullscreen. - private static final boolean FULLSCREEN = true; - - // When we have a top-bottom split screen, we shift the bottom stack up to accommodate - // the IME window. The static flag below controls whether to run animation when the - // IME window goes away. - private static final boolean ANIMATE_IME_GOING_AWAY = false; - /** Unique identifier */ final int mStackId; @@ -83,6 +76,12 @@ public class TaskStack implements DimLayer.DimLayerUser, /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */ private final Rect mAdjustedBounds = new Rect(); + /** + * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they + * represent the state when the animation has ended. + */ + private final Rect mFullyAdjustedImeBounds = new Rect(); + /** Whether mBounds is fullscreen */ private boolean mFullscreen = true; @@ -118,6 +117,7 @@ public class TaskStack implements DimLayer.DimLayerUser, private boolean mImeGoingAway; private WindowState mImeWin; private float mMinimizeAmount; + private float mAdjustImeAmount; private final int mDockedStackMinimizeThickness; // If this is true, the task will be down or upscaled @@ -211,21 +211,26 @@ public class TaskStack implements DimLayer.DimLayerUser, * the normal task bounds. * * @param bounds The adjusted bounds. - * @param keepInsets Whether to keep the insets from the original bounds or to calculate new - * ones depending on the adjusted bounds. - * @return true if the adjusted bounds has changed. */ - private boolean setAdjustedBounds(Rect bounds, boolean keepInsets) { - if (mAdjustedBounds.equals(bounds)) { - return false; + private void setAdjustedBounds(Rect bounds) { + if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) { + return; } mAdjustedBounds.set(bounds); final boolean adjusted = !mAdjustedBounds.isEmpty(); - alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, - adjusted && keepInsets ? mBounds : null); + Rect insetBounds = null; + if (adjusted && isAdjustedForMinimizedDock()) { + insetBounds = mBounds; + } else if (adjusted && isAdjustedForIme()) { + if (mImeGoingAway) { + insetBounds = mBounds; + } else { + insetBounds = mFullyAdjustedImeBounds; + } + } + alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds); mDisplayContent.layoutNeeded = true; - return true; } private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) { @@ -829,6 +834,7 @@ public class TaskStack implements DimLayer.DimLayerUser, */ void setAdjustedForIme(WindowState imeWin) { mAdjustedForIme = true; + mAdjustImeAmount = 0f; mImeWin = imeWin; mImeGoingAway = false; } @@ -836,9 +842,6 @@ public class TaskStack implements DimLayer.DimLayerUser, boolean isAdjustedForIme() { return mAdjustedForIme || mImeGoingAway; } - void clearImeGoingAway() { - mImeGoingAway = false; - } boolean isAnimatingForIme() { return mImeWin != null && mImeWin.isAnimatingLw(); @@ -852,16 +855,14 @@ public class TaskStack implements DimLayer.DimLayerUser, * * @return true if a traversal should be performed after the adjustment. */ - boolean updateAdjustForIme() { - boolean stopped = false; - if (mImeGoingAway && (!ANIMATE_IME_GOING_AWAY || !isAnimatingForIme())) { - mImeWin = null; - mAdjustedForIme = false; - stopped = true; + boolean updateAdjustForIme(float adjustAmount) { + if (adjustAmount != mAdjustImeAmount) { + mAdjustImeAmount = adjustAmount; + updateAdjustedBounds(); + return isVisibleForUserLocked(); + } else { + return false; } - // Make sure to run a traversal when the animation stops so that the stack - // is moved to its final position. - return updateAdjustedBounds() || stopped; } /** @@ -875,6 +876,7 @@ public class TaskStack implements DimLayer.DimLayerUser, mImeWin = null; mAdjustedForIme = false; mImeGoingAway = false; + mAdjustImeAmount = 0f; updateAdjustedBounds(); } else { mImeGoingAway |= mAdjustedForIme; @@ -904,7 +906,6 @@ public class TaskStack implements DimLayer.DimLayerUser, private boolean adjustForIME(final WindowState imeWin) { final int dockedSide = getDockSide(); final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM; - final Rect adjustedBounds = mTmpAdjustedBounds; if (imeWin == null || !dockedTopOrBottom) { return false; } @@ -917,41 +918,38 @@ public class TaskStack implements DimLayer.DimLayerUser, contentBounds.set(displayContentRect); int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top); - // if IME window is animating, get its actual vertical shown position (but no smaller than - // the final target vertical position) - if (imeWin.isAnimatingLw()) { - imeTop = Math.max(imeTop, imeWin.getShownPositionLw().y); - } imeTop += imeWin.getGivenContentInsetsLw().top; if (contentBounds.bottom > imeTop) { contentBounds.bottom = imeTop; } - // If content bounds not changing, nothing to do. - if (mLastContentBounds.equals(contentBounds)) { - return true; - } - - // Content bounds changed, need to apply adjustments depending on dock sides. mLastContentBounds.set(contentBounds); - adjustedBounds.set(mBounds); final int yOffset = displayContentRect.bottom - contentBounds.bottom; if (dockedSide == DOCKED_TOP) { // If this stack is docked on top, we make it smaller so the bottom stack is not // occluded by IME. We shift its bottom up by the height of the IME (capped by // the display content rect). Note that we don't change the task bounds. - adjustedBounds.bottom = Math.max( - adjustedBounds.bottom - yOffset, displayContentRect.top); + int bottom = Math.max( + mBounds.bottom - yOffset, displayContentRect.top); + mTmpAdjustedBounds.set(mBounds); + mTmpAdjustedBounds.bottom = + (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom); + mFullyAdjustedImeBounds.set(mBounds); } else { // If this stack is docked on bottom, 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 (although the best // we could do is to make the top stack fully collapsed). final int dividerWidth = getDisplayContent().mDividerControllerLocked .getContentWidth(); - adjustedBounds.top = Math.max( - adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth); - adjustedBounds.bottom = adjustedBounds.top + mBounds.height(); + int top = Math.max(mBounds.top - yOffset, displayContentRect.top + dividerWidth); + mTmpAdjustedBounds.set(mBounds); + mTmpAdjustedBounds.top = + (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top); + mTmpAdjustedBounds.bottom = mTmpAdjustedBounds.top + mBounds.height(); + mFullyAdjustedImeBounds.set(mBounds); + mFullyAdjustedImeBounds.top = top; + mFullyAdjustedImeBounds.bottom = top + mBounds.height(); } return true; } @@ -1007,7 +1005,7 @@ public class TaskStack implements DimLayer.DimLayerUser, /** * Updates the adjustment depending on it's current state. */ - boolean updateAdjustedBounds() { + void updateAdjustedBounds() { boolean adjust = false; if (mMinimizeAmount != 0f) { adjust = adjustForMinimizedDockedStack(mMinimizeAmount); @@ -1018,7 +1016,7 @@ public class TaskStack implements DimLayer.DimLayerUser, mTmpAdjustedBounds.setEmpty(); mLastContentBounds.setEmpty(); } - return setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack()); + setAdjustedBounds(mTmpAdjustedBounds); } boolean isAdjustedForMinimizedDockedStack() { @@ -1030,6 +1028,9 @@ public class TaskStack implements DimLayer.DimLayerUser, pw.println(prefix + "mDeferDetach=" + mDeferDetach); pw.println(prefix + "mFullscreen=" + mFullscreen); pw.println(prefix + "mBounds=" + mBounds.toShortString()); + if (!mAdjustedBounds.isEmpty()) { + pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString()); + } for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) { mTasks.get(taskNdx).dump(prefix + " ", pw); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e325d6fffe81..a4d5c9586ceb 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7443,7 +7443,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void adjustForImeIfNeeded(final DisplayContent displayContent) { + void adjustForImeIfNeeded(final DisplayContent displayContent) { final WindowState imeWin = mInputMethodWindow; final TaskStack focusedStack = mCurrentFocus != null ? mCurrentFocus.getStack() : null; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 329cbbdd38f6..db8f9bd231a4 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; import static android.view.WindowManager.LayoutParams.FLAG_SCALED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 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.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; @@ -1759,7 +1760,9 @@ class WindowStateAnimator { } else { clearAnimation(); } - + if (mWin.mAttrs.type == TYPE_INPUT_METHOD) { + mService.adjustForImeIfNeeded(mWin.mDisplayContent); + } return mAnimation != null; } |