Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35156073 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Fix some split-screen IME glitches" into rvc-dev am: 0c6b6424 am:...

Merge "Fix some split-screen IME glitches" into rvc-dev am: 0c6b6424 am: 13ed9864 am: 42be6ca9

Change-Id: I46219cb8e732fb64404fb0d5b0d548d418203dbf
parents e8782e62 42be6ca9
Loading
Loading
Loading
Loading
+172 −44
Original line number Diff line number Diff line
@@ -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;
                @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);
@@ -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();
                }
            };

+3 −0
Original line number Diff line number Diff line
@@ -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)
+5 −16
Original line number Diff line number Diff line
@@ -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);
+56 −24
Original line number Diff line number Diff line
@@ -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;
            }
            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();
@@ -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();
                        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();
@@ -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) {}
    }
}
+4 −3
Original line number Diff line number Diff line
@@ -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() {