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:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user