OSDN Git Service

Put windows into resizing during IME adjust animation
authorJorim Jaggi <jjaggi@google.com>
Thu, 14 Apr 2016 20:12:36 +0000 (13:12 -0700)
committerJorim Jaggi <jjaggi@google.com>
Fri, 15 Apr 2016 03:47:45 +0000 (20:47 -0700)
Because the IME animates in with translucency there was a black hole
visible at the bottom. This CL puts the window into resizing mode,
waits until the change is commited, and then starts the animation

Bug: 28175599
Change-Id: Ib31c1e765639e5490208bccba77b25318ec8dc71

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

index 21c9ee6..3bd7a96 100644 (file)
@@ -24,6 +24,7 @@ import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
 import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -41,6 +42,7 @@ import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
 import com.android.server.wm.DimLayer.DimLayerUser;
+import com.android.server.wm.WindowManagerService.H;
 
 import java.util.ArrayList;
 
@@ -76,10 +78,12 @@ 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);
+            new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
     private static final long IME_ADJUST_ANIM_DURATION = 280;
 
+    private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
+
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private int mDividerWindowWidth;
@@ -101,11 +105,13 @@ public class DockedStackDividerController implements DimLayerUser {
     private float mAnimationStart;
     private float mAnimationTarget;
     private long mAnimationDuration;
+    private boolean mAnimationStartDelayed;
     private final Interpolator mMinimizedDockInterpolator;
     private float mMaximizeMeetFraction;
     private final Rect mTouchRegion = new Rect();
     private boolean mAnimatingForIme;
     private boolean mAdjustedForIme;
+    private WindowState mDelayedImeWin;
 
     DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -192,13 +198,16 @@ public class DockedStackDividerController implements DimLayerUser {
         return mLastVisibility;
     }
 
-    void setAdjustedForIme(boolean adjusted, boolean animate) {
+    void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
         if (mAdjustedForIme != adjusted) {
             mAdjustedForIme = adjusted;
             if (animate) {
-                startImeAdjustAnimation(adjusted ? 0 : 1, adjusted ? 1 : 0);
+                startImeAdjustAnimation(adjusted, imeWin);
+            } else {
+
+                // Animation might be delayed, so only notify if we don't run an animation.
+                notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
             }
-            notifyAdjustedForImeChanged(adjusted, animate ? IME_ADJUST_ANIM_DURATION : 0);
         }
     }
 
@@ -429,11 +438,46 @@ public class DockedStackDividerController implements DimLayerUser {
         mAnimationTarget = to;
     }
 
-    private void startImeAdjustAnimation(float from, float to) {
+    private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
         mAnimatingForIme = true;
         mAnimationStarted = false;
-        mAnimationStart = from;
-        mAnimationTarget = to;
+        mAnimationStart = adjusted ? 0 : 1;
+        mAnimationTarget = adjusted ? 1 : 0;
+
+        final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            final TaskStack stack = stacks.get(i);
+            if (stack.isVisibleLocked() && stack.isAdjustedForIme()) {
+                stack.beginImeAdjustAnimation();
+            }
+        }
+
+        // We put all tasks into drag resizing mode - wait until all of them have completed the
+        // drag resizing switch.
+        if (!mService.mWaitingForDrawn.isEmpty()) {
+            mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
+            mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
+                    IME_ADJUST_DRAWN_TIMEOUT);
+            mAnimationStartDelayed = true;
+            if (imeWin != null) {
+
+                // There might be an old window delaying the animation start - clear it.
+                if (mDelayedImeWin != null) {
+                    mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+                }
+                mDelayedImeWin = imeWin;
+                imeWin.mWinAnimator.startDelayingAnimationStart();
+            }
+            mService.mWaitingForDrawnCallback = () -> {
+                mAnimationStartDelayed = false;
+                if (mDelayedImeWin != null) {
+                    mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+                }
+                notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+            };
+        } else {
+            notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+        }
     }
 
     private void setMinimizedDockedStack(boolean minimized) {
@@ -462,7 +506,7 @@ public class DockedStackDividerController implements DimLayerUser {
     }
 
     private boolean animateForIme(long now) {
-        if (!mAnimationStarted) {
+        if (!mAnimationStarted || mAnimationStartDelayed) {
             mAnimationStarted = true;
             mAnimationStartTime = now;
             mAnimationDuration = (long)
@@ -480,7 +524,11 @@ public class DockedStackDividerController implements DimLayerUser {
                     stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                     updated = true;
                 } else {
-                    updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t));
+                    updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
+                            false /* force */);
+                }
+                if (t >= 1f) {
+                    stack.endImeAdjustAnimation();
                 }
             }
         }
index 7b16dbe..13bfa57 100644 (file)
@@ -509,6 +509,22 @@ class Task implements DimLayer.DimLayerUser {
         return mDragResizeMode;
     }
 
+    /**
+     * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag
+     * resizing state of the window has been changed.
+     */
+    void addWindowsWaitingForDrawnIfResizingChanged() {
+        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState win = windows.get(winNdx);
+                if (win.isDragResizeChanged()) {
+                    mService.mWaitingForDrawn.add(win);
+                }
+            }
+        }
+    }
+
     void updateDisplayInfo(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
@@ -619,6 +635,16 @@ class Task implements DimLayer.DimLayerUser {
         return false;
     }
 
+    boolean isVisible() {
+        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+            final AppWindowToken appToken = mAppTokens.get(i);
+            if (appToken.isVisible()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     boolean inHomeStack() {
         return mStack != null && mStack.mStackId == HOME_STACK_ID;
     }
index 0a08a54..c322cd8 100644 (file)
@@ -26,6 +26,7 @@ import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
@@ -833,10 +834,13 @@ public class TaskStack implements DimLayer.DimLayerUser,
      * @param imeWin The IME window.
      */
     void setAdjustedForIme(WindowState imeWin) {
-        mAdjustedForIme = true;
-        mAdjustImeAmount = 0f;
         mImeWin = imeWin;
         mImeGoingAway = false;
+        if (!mAdjustedForIme) {
+            mAdjustedForIme = true;
+            mAdjustImeAmount = 0f;
+            updateAdjustForIme(0f, true /* force */);
+        }
     }
 
     boolean isAdjustedForIme() {
@@ -855,8 +859,8 @@ public class TaskStack implements DimLayer.DimLayerUser,
      *
      * @return true if a traversal should be performed after the adjustment.
      */
-    boolean updateAdjustForIme(float adjustAmount) {
-        if (adjustAmount != mAdjustImeAmount) {
+    boolean updateAdjustForIme(float adjustAmount, boolean force) {
+        if (adjustAmount != mAdjustImeAmount || force) {
             mAdjustImeAmount = adjustAmount;
             updateAdjustedBounds();
             return isVisibleForUserLocked();
@@ -903,6 +907,29 @@ public class TaskStack implements DimLayer.DimLayerUser,
         return mMinimizeAmount != 0f;
     }
 
+    /**
+     * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
+     * to the list of to be drawn windows the service is waiting for.
+     */
+    void beginImeAdjustAnimation() {
+        for (int j = mTasks.size() - 1; j >= 0; j--) {
+            final Task task = mTasks.get(j);
+            if (task.isVisibleForUser()) {
+                task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+                task.addWindowsWaitingForDrawnIfResizingChanged();
+            }
+        }
+    }
+
+    /**
+     * Resets the resizing state of all windows.
+     */
+    void endImeAdjustAnimation() {
+        for (int j = mTasks.size() - 1; j >= 0; j--) {
+            mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+        }
+    }
+
     private boolean adjustForIME(final WindowState imeWin) {
         final int dockedSide = getDockSide();
         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
@@ -946,7 +973,6 @@ public class TaskStack implements DimLayer.DimLayerUser,
             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();
@@ -1159,7 +1185,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
         return mDragResizing;
     }
 
-    private void setDragResizingLocked(boolean resizing) {
+    void setDragResizingLocked(boolean resizing) {
         if (mDragResizing == resizing) {
             return;
         }
index a4d5c95..a4238c1 100644 (file)
@@ -7459,14 +7459,14 @@ public class WindowManagerService extends IWindowManager.Stub
                     stack.setAdjustedForIme(imeWin);
                 }
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(true, true);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, 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);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible, imeWin);
         }
     }
 
index db8f9bd..06c3a02 100644 (file)
@@ -22,7 +22,7 @@ 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.AppWindowAnimator.sDummyAnimation;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -183,6 +183,8 @@ class WindowStateAnimator {
      * window is first added or shown, cleared when the callback has been made. */
     boolean mEnteringAnimation;
 
+    private boolean mAnimationStartDelayed;
+
     boolean mKeyguardGoingAwayAnimation;
     boolean mKeyguardGoingAwayWithWallpaper;
 
@@ -299,7 +301,7 @@ class WindowStateAnimator {
     /** Is the window animating the DummyAnimation? */
     boolean isDummyAnimation() {
         return mAppAnimator != null
-                && mAppAnimator.animation == AppWindowAnimator.sDummyAnimation;
+                && mAppAnimator.animation == sDummyAnimation;
     }
 
     /** Is this window currently set to animate or currently animating? */
@@ -323,8 +325,12 @@ class WindowStateAnimator {
         if ((mAnimation == null) || !mLocalAnimating) {
             return false;
         }
+        currentTime = getAnimationFrameTime(mAnimation, currentTime);
         mTransformation.clear();
         final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
+        if (mAnimationStartDelayed && mAnimationIsEntrance) {
+            mTransformation.setAlpha(0f);
+        }
         if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
                 + ", xform=" + mTransformation);
         return more;
@@ -1841,6 +1847,9 @@ class WindowStateAnimator {
                     pw.print(" mDsDy="); pw.print(mDsDy);
                     pw.print(" mDtDy="); pw.println(mDtDy);
         }
+        if (mAnimationStartDelayed) {
+            pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed);
+        }
     }
 
     @Override
@@ -1919,4 +1928,25 @@ class WindowStateAnimator {
                     mDeferTransactionUntilFrame);
         }
     }
+
+    /**
+     * Sometimes we need to synchronize the first frame of animation with some external event.
+     * To achieve this, we prolong the start of the animation and keep producing the first frame of
+     * the animation.
+     */
+    private long getAnimationFrameTime(Animation animation, long currentTime) {
+        if (mAnimationStartDelayed) {
+            animation.setStartTime(currentTime);
+            return currentTime + 1;
+        }
+        return currentTime;
+    }
+
+    void startDelayingAnimationStart() {
+        mAnimationStartDelayed = true;
+    }
+
+    void endDelayingAnimationStart() {
+        mAnimationStartDelayed = false;
+    }
 }