Put windows into resizing during IME adjust animation

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
This commit is contained in:
Jorim Jaggi
2016-04-14 13:12:36 -07:00
parent 698e7634aa
commit ff71d20ff3
5 changed files with 149 additions and 19 deletions

View 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();
}
}
}

View 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;
}

View 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;
}

View 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);
}
}

View 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;
}
}