Loading packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +172 −44 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; @Override public void onImeStartPositioning(int displayId, int imeTop, int finalImeTop, boolean showing, SurfaceControl.Transaction t) { mStartTop = imeTop; mFinalTop = finalImeTop; if (showing) { /** * 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 { mLastImeTarget = ActivityTaskManager.getTaskOrganizerController() IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController() .getImeTarget(displayId); mShouldAdjustForIme = mLastImeTarget != null && !mSplitLayout.mDisplayLayout.isLandscape() && (mLastImeTarget.asBinder() == mSplits.mSecondary.token.asBinder()); return imeSplit != null && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); } catch (RemoteException e) { Slog.w(TAG, "Failed to get IME target", e); } return false; } if (!mShouldAdjustForIme) { setAdjustedForIme(false); return; @Override 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 (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); Loading @@ -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); 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); mView.setResizeDimLayer(t, true /* primary */, showing ? 0.3f : 0.f); } 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(); } }; Loading packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +3 −0 Original line number Diff line number Diff line Loading @@ -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) Loading packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java +5 −16 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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); Loading packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java +56 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } Loading Loading @@ -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; Loading Loading @@ -239,23 +240,39 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged if (imeSource == null || mImeSourceControl == null) { return; } mHandler.post(() -> { if ((mAnimationDirection == DIRECTION_SHOW && show) || (mAnimationDirection == DIRECTION_HIDE && !show)) { return; } if (mAnimationDirection != DIRECTION_NONE) { mAnimation.end(); mAnimationDirection = DIRECTION_NONE; 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; mHandler.post(() -> { 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(); Loading @@ -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()); Loading @@ -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(); if (!mCancelled) { t.setPosition(mImeSourceControl.getLeash(), x, endY); dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW, t); if (mAnimationDirection == DIRECTION_HIDE) { } dispatchEndPositioning(mDisplayId, mCancelled, t); if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) { t.hide(mImeSourceControl.getLeash()); } t.apply(); Loading Loading @@ -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) {} } } services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +4 −3 Original line number Diff line number Diff line Loading @@ -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() { Loading Loading
packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +172 −44 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; @Override public void onImeStartPositioning(int displayId, int imeTop, int finalImeTop, boolean showing, SurfaceControl.Transaction t) { mStartTop = imeTop; mFinalTop = finalImeTop; if (showing) { /** * 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 { mLastImeTarget = ActivityTaskManager.getTaskOrganizerController() IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController() .getImeTarget(displayId); mShouldAdjustForIme = mLastImeTarget != null && !mSplitLayout.mDisplayLayout.isLandscape() && (mLastImeTarget.asBinder() == mSplits.mSecondary.token.asBinder()); return imeSplit != null && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); } catch (RemoteException e) { Slog.w(TAG, "Failed to get IME target", e); } return false; } if (!mShouldAdjustForIme) { setAdjustedForIme(false); return; @Override 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 (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); Loading @@ -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); 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); mView.setResizeDimLayer(t, true /* primary */, showing ? 0.3f : 0.f); } 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(); } }; Loading
packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +3 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java +5 −16 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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); Loading
packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java +56 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } Loading Loading @@ -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; Loading Loading @@ -239,23 +240,39 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged if (imeSource == null || mImeSourceControl == null) { return; } mHandler.post(() -> { if ((mAnimationDirection == DIRECTION_SHOW && show) || (mAnimationDirection == DIRECTION_HIDE && !show)) { return; } if (mAnimationDirection != DIRECTION_NONE) { mAnimation.end(); mAnimationDirection = DIRECTION_NONE; 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; mHandler.post(() -> { 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(); Loading @@ -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()); Loading @@ -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(); if (!mCancelled) { t.setPosition(mImeSourceControl.getLeash(), x, endY); dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW, t); if (mAnimationDirection == DIRECTION_HIDE) { } dispatchEndPositioning(mDisplayId, mCancelled, t); if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) { t.hide(mImeSourceControl.getLeash()); } t.apply(); Loading Loading @@ -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) {} } }
services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +4 −3 Original line number Diff line number Diff line Loading @@ -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() { Loading