Merge "Fix some split-screen IME glitches" into rvc-dev am: 0c6b642465 am: 13ed9864f8 am: 8eaf0bce9f am: 245029ff87

Change-Id: I4e07c01e9d6fc754dfca8dca2ecca6baaffc0723
This commit is contained in:
Automerger Merge Worker
2020-03-05 04:27:50 +00:00
5 changed files with 240 additions and 87 deletions

View File

@@ -19,6 +19,9 @@ package com.android.systemui.stackdivider;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.Display.DEFAULT_DISPLAY;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -35,6 +38,8 @@ import android.view.SurfaceSession;
import android.view.View;
import android.view.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
@@ -69,6 +74,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
static final boolean DEBUG = true;
static final int DEFAULT_APP_TRANSITION_DURATION = 336;
static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
@@ -121,42 +127,92 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
};
private IWindowContainer mLastImeTarget = null;
private boolean mShouldAdjustForIme = false;
private DisplayImeController.ImePositionProcessor mImePositionProcessor =
new DisplayImeController.ImePositionProcessor() {
private int mStartTop = 0;
private int mFinalTop = 0;
/**
* These are the y positions of the top of the IME surface when it is hidden and
* when it is shown respectively. These are NOT necessarily the top of the visible
* IME itself.
*/
private int mHiddenTop = 0;
private int mShownTop = 0;
// The following are target states (what we are curretly animating towards).
/**
* {@code true} if, at the end of the animation, the split task positions should be
* adjusted by height of the IME. This happens when the secondary split is the IME
* target.
*/
private boolean mTargetAdjusted = false;
/**
* {@code true} if, at the end of the animation, the IME should be shown/visible
* regardless of what has focus.
*/
private boolean mTargetShown = false;
// The following are the current (most recent) states set during animation
/**
* {@code true} if the secondary split has IME focus.
*/
private boolean mSecondaryHasFocus = false;
/** The dimming currently applied to the primary/secondary splits. */
private float mLastPrimaryDim = 0.f;
private float mLastSecondaryDim = 0.f;
/** The most recent y position of the top of the IME surface */
private int mLastAdjustTop = -1;
// The following are states reached last time an animation fully completed.
/** {@code true} if the IME was shown/visible by the last-completed animation. */
private boolean mImeWasShown = false;
/**
* {@code true} if the split positions were adjusted by the last-completed
* animation.
*/
private boolean mAdjusted = false;
/**
* When some aspect of split-screen needs to animate independent from the IME,
* this will be non-null and control split animation.
*/
@Nullable
private ValueAnimator mAnimation = null;
private boolean getSecondaryHasFocus(int displayId) {
try {
IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
.getImeTarget(displayId);
return imeSplit != null
&& (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to get IME target", e);
}
return false;
}
@Override
public void onImeStartPositioning(int displayId, int imeTop, int finalImeTop,
boolean showing, SurfaceControl.Transaction t) {
mStartTop = imeTop;
mFinalTop = finalImeTop;
if (showing) {
try {
mLastImeTarget = ActivityTaskManager.getTaskOrganizerController()
.getImeTarget(displayId);
mShouldAdjustForIme = mLastImeTarget != null
&& !mSplitLayout.mDisplayLayout.isLandscape()
&& (mLastImeTarget.asBinder()
== mSplits.mSecondary.token.asBinder());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to get IME target", e);
}
public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean imeShouldShow, SurfaceControl.Transaction t) {
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
&& !mSplitLayout.mDisplayLayout.isLandscape();
mHiddenTop = hiddenTop;
mShownTop = shownTop;
mTargetShown = imeShouldShow;
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
}
if (!mShouldAdjustForIme) {
setAdjustedForIme(false);
return;
if (mAnimation != null || (mImeWasShown && imeShouldShow
&& mTargetAdjusted != mAdjusted)) {
// We need to animate adjustment independently of the IME position, so
// start our own animation to drive adjustment. This happens when a
// different split's editor has gained focus while the IME is still visible.
startAsyncAnimation();
}
mView.setAdjustedForIme(showing, showing
? DisplayImeController.ANIMATION_DURATION_SHOW_MS
: DisplayImeController.ANIMATION_DURATION_HIDE_MS);
// Reposition the server's secondary split position so that it evaluates
// insets properly.
WindowContainerTransaction wct = new WindowContainerTransaction();
if (showing) {
mSplitLayout.updateAdjustedBounds(finalImeTop, imeTop, finalImeTop);
if (mTargetAdjusted) {
mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
} else {
wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
@@ -166,34 +222,106 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
.applyContainerTransaction(wct, null /* organizer */);
} catch (RemoteException e) {
}
setAdjustedForIme(showing);
// Update all the adjusted-for-ime states
mView.setAdjustedForIme(mTargetShown, mTargetShown
? DisplayImeController.ANIMATION_DURATION_SHOW_MS
: DisplayImeController.ANIMATION_DURATION_HIDE_MS);
setAdjustedForIme(mTargetShown);
}
@Override
public void onImePositionChanged(int displayId, int imeTop,
SurfaceControl.Transaction t) {
if (!mShouldAdjustForIme) {
if (mAnimation != null) {
// Not synchronized with IME anymore, so return.
return;
}
mSplitLayout.updateAdjustedBounds(imeTop, mStartTop, mFinalTop);
mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
mSplitLayout.mAdjustedSecondary);
final boolean showing = mFinalTop < mStartTop;
final float progress = ((float) (imeTop - mStartTop)) / (mFinalTop - mStartTop);
final float fraction = showing ? progress : 1.f - progress;
mView.setResizeDimLayer(t, true /* primary */, fraction * 0.3f);
final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
final float progress = mTargetShown ? fraction : 1.f - fraction;
onProgress(progress, t);
}
@Override
public void onImeEndPositioning(int displayId, int imeTop,
boolean showing, SurfaceControl.Transaction t) {
if (!mShouldAdjustForIme) {
public void onImeEndPositioning(int displayId, boolean cancelled,
SurfaceControl.Transaction t) {
if (mAnimation != null) {
// Not synchronized with IME anymore, so return.
return;
}
mSplitLayout.updateAdjustedBounds(imeTop, mStartTop, mFinalTop);
mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
mSplitLayout.mAdjustedSecondary);
mView.setResizeDimLayer(t, true /* primary */, showing ? 0.3f : 0.f);
onEnd(cancelled, t);
}
private void onProgress(float progress, SurfaceControl.Transaction t) {
if (mTargetAdjusted != mAdjusted) {
final float fraction = mTargetAdjusted ? progress : 1.f - progress;
mLastAdjustTop =
(int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
mSplitLayout.mAdjustedSecondary);
}
final float invProg = 1.f - progress;
final float targetPrimaryDim = (mSecondaryHasFocus && mTargetShown)
? ADJUSTED_NONFOCUS_DIM : 0.f;
final float targetSecondaryDim = (!mSecondaryHasFocus && mTargetShown)
? ADJUSTED_NONFOCUS_DIM : 0.f;
mView.setResizeDimLayer(t, true /* primary */,
mLastPrimaryDim * invProg + progress * targetPrimaryDim);
mView.setResizeDimLayer(t, false /* primary */,
mLastSecondaryDim * invProg + progress * targetSecondaryDim);
}
private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
if (!cancelled) {
onProgress(1.f, t);
mAdjusted = mTargetAdjusted;
mImeWasShown = mTargetShown;
mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
mLastPrimaryDim =
(mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
mLastSecondaryDim =
(!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
}
}
private void startAsyncAnimation() {
if (mAnimation != null) {
mAnimation.cancel();
}
mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
if (mTargetAdjusted != mAdjusted) {
final float fraction =
((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
mAnimation.setCurrentFraction(progress);
}
mAnimation.addUpdateListener(animation -> {
SurfaceControl.Transaction t = mTransactionPool.acquire();
float value = (float) animation.getAnimatedValue();
onProgress(value, t);
t.apply();
mTransactionPool.release(t);
});
mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
mAnimation.addListener(new AnimatorListenerAdapter() {
private boolean mCancel = false;
@Override
public void onAnimationCancel(Animator animation) {
mCancel = true;
}
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
onEnd(mCancel, t);
t.apply();
mTransactionPool.release(t);
mAnimation = null;
}
});
mAnimation.start();
}
};

View File

@@ -935,6 +935,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
if (mAdjustedForIme == adjustedForIme) {
return;
}
updateDockSide();
mHandle.animate()
.setInterpolator(IME_ADJUST_INTERPOLATOR)

View File

@@ -171,22 +171,13 @@ public class SplitDisplayLayout {
/**
* Updates the adjustment depending on it's current state.
*/
void updateAdjustedBounds(int currImeTop, int startTop, int finalTop) {
updateAdjustedBounds(mDisplayLayout, currImeTop, startTop, finalTop, mDividerSize,
void updateAdjustedBounds(int currImeTop, int hiddenTop, int shownTop) {
adjustForIME(mDisplayLayout, currImeTop, hiddenTop, shownTop, mDividerSize,
mDividerSizeInactive, mPrimary, mSecondary);
}
/**
* Updates the adjustment depending on it's current state.
*/
private void updateAdjustedBounds(DisplayLayout dl, int currImeTop, int startTop, int finalTop,
int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
adjustForIME(dl, currImeTop, startTop, finalTop, dividerWidth, dividerWidthInactive,
primaryBounds, secondaryBounds);
}
/** Assumes top/bottom split. Splits are not adjusted for left/right splits. */
private void adjustForIME(DisplayLayout dl, int currImeTop, int startTop, int finalTop,
private void adjustForIME(DisplayLayout dl, int currImeTop, int hiddenTop, int shownTop,
int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
if (mAdjustedPrimary == null) {
mAdjustedPrimary = new Rect();
@@ -196,11 +187,9 @@ public class SplitDisplayLayout {
final Rect displayStableRect = new Rect();
dl.getStableBounds(displayStableRect);
final boolean showing = finalTop < startTop;
final float progress = ((float) (currImeTop - startTop)) / (finalTop - startTop);
final float dividerSquish = showing ? progress : 1.f - progress;
final float shownFraction = ((float) (currImeTop - hiddenTop)) / (shownTop - hiddenTop);
final int currDividerWidth =
(int) (dividerWidthInactive * dividerSquish + dividerWidth * (1.f - dividerSquish));
(int) (dividerWidthInactive * shownFraction + dividerWidth * (1.f - shownFraction));
final int minTopStackBottom = displayStableRect.top
+ (int) ((mPrimary.bottom - displayStableRect.top) * ADJUSTED_STACK_FRACTION_MIN);

View File

@@ -51,7 +51,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public static final int ANIMATION_DURATION_SHOW_MS = 275;
public static final int ANIMATION_DURATION_HIDE_MS = 340;
static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
private static final int DIRECTION_NONE = 0;
private static final int DIRECTION_SHOW = 1;
private static final int DIRECTION_HIDE = 2;
@@ -127,20 +127,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
private void dispatchStartPositioning(int displayId, int imeTop, int finalImeTop,
private void dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean show, SurfaceControl.Transaction t) {
synchronized (mPositionProcessors) {
for (ImePositionProcessor pp : mPositionProcessors) {
pp.onImeStartPositioning(displayId, imeTop, finalImeTop, show, t);
pp.onImeStartPositioning(displayId, hiddenTop, shownTop, show, t);
}
}
}
private void dispatchEndPositioning(int displayId, int imeTop, boolean show,
private void dispatchEndPositioning(int displayId, boolean cancel,
SurfaceControl.Transaction t) {
synchronized (mPositionProcessors) {
for (ImePositionProcessor pp : mPositionProcessors) {
pp.onImeEndPositioning(displayId, imeTop, show, t);
pp.onImeEndPositioning(displayId, cancel, t);
}
}
}
@@ -173,6 +173,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
int mAnimationDirection = DIRECTION_NONE;
ValueAnimator mAnimation = null;
int mRotation = Surface.ROTATION_0;
boolean mImeShowing = false;
PerDisplay(int displayId, int initialRotation) {
mDisplayId = displayId;
@@ -239,23 +240,39 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
if (imeSource == null || mImeSourceControl == null) {
return;
}
if ((mAnimationDirection == DIRECTION_SHOW && show)
|| (mAnimationDirection == DIRECTION_HIDE && !show)) {
return;
}
if (mAnimationDirection != DIRECTION_NONE) {
mAnimation.end();
mAnimationDirection = DIRECTION_NONE;
}
mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
mHandler.post(() -> {
if ((mAnimationDirection == DIRECTION_SHOW && show)
|| (mAnimationDirection == DIRECTION_HIDE && !show)) {
return;
}
boolean seek = false;
float seekValue = 0;
if (mAnimation != null) {
if (mAnimation.isRunning()) {
seekValue = (float) mAnimation.getAnimatedValue();
seek = true;
}
mAnimation.cancel();
}
mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
final float defaultY = mImeSourceControl.getSurfacePosition().y;
final float x = mImeSourceControl.getSurfacePosition().x;
final float startY = show ? defaultY + imeSource.getFrame().height() : defaultY;
final float endY = show ? defaultY : defaultY + imeSource.getFrame().height();
final float hiddenY = defaultY + imeSource.getFrame().height();
final float shownY = defaultY;
final float startY = show ? hiddenY : shownY;
final float endY = show ? shownY : hiddenY;
if (mImeShowing && show) {
// IME is already showing, so set seek to end
seekValue = shownY;
seek = true;
}
mImeShowing = show;
mAnimation = ValueAnimator.ofFloat(startY, endY);
mAnimation.setDuration(
show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
if (seek) {
mAnimation.setCurrentFraction((seekValue - startY) / (endY - startY));
}
mAnimation.addUpdateListener(animation -> {
SurfaceControl.Transaction t = mTransactionPool.acquire();
@@ -267,12 +284,13 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
});
mAnimation.setInterpolator(INTERPOLATOR);
mAnimation.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled = false;
@Override
public void onAnimationStart(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, startY);
dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY),
imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW,
dispatchStartPositioning(mDisplayId, imeTop(imeSource, hiddenY),
imeTop(imeSource, shownY), mAnimationDirection == DIRECTION_SHOW,
t);
if (mAnimationDirection == DIRECTION_SHOW) {
t.show(mImeSourceControl.getLeash());
@@ -281,12 +299,17 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
mTransactionPool.release(t);
}
@Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, endY);
dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY),
mAnimationDirection == DIRECTION_SHOW, t);
if (mAnimationDirection == DIRECTION_HIDE) {
if (!mCancelled) {
t.setPosition(mImeSourceControl.getLeash(), x, endY);
}
dispatchEndPositioning(mDisplayId, mCancelled, t);
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
t.hide(mImeSourceControl.getLeash());
}
t.apply();
@@ -317,21 +340,30 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public interface ImePositionProcessor {
/**
* Called when the IME position is starting to animate.
*
* @param hiddenTop The y position of the top of the IME surface when it is hidden.
* @param shownTop The y position of the top of the IME surface when it is shown.
* @param showing {@code true} when we are animating from hidden to shown, {@code false}
* when animating from shown to hidden.
*/
default void onImeStartPositioning(int displayId, int imeTop, int finalImeTop,
default void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean showing, SurfaceControl.Transaction t) {}
/**
* Called when the ime position changed. This is expected to be a synchronous call on the
* animation thread. Operations can be added to the transaction to be applied in sync.
*
* @param imeTop The current y position of the top of the IME surface.
*/
default void onImePositionChanged(int displayId, int imeTop,
SurfaceControl.Transaction t) {}
/**
* Called when the IME position is done animating.
*
* @param cancel {@code true} if this was cancelled. This implies another start is coming.
*/
default void onImeEndPositioning(int displayId, int imeTop, boolean showing,
default void onImeEndPositioning(int displayId, boolean cancel,
SurfaceControl.Transaction t) {}
}
}

View File

@@ -64,13 +64,14 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
final InsetsControlTarget target = mDisplayContent.mInputMethodControlTarget;
ProtoLog.d(WM_DEBUG_IME, "call showInsets(ime) on %s",
mDisplayContent.mInputMethodControlTarget.getWindow().getName());
mDisplayContent.mInputMethodControlTarget.showInsets(
WindowInsets.Type.ime(), true /* fromIme */);
target.getWindow() != null ? target.getWindow().getName() : "");
target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
}
abortShowImePostLayout();
};
mDisplayContent.mWmService.requestTraversal();
}
void checkShowImePostLayout() {