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

Commit 42ce7119 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Handle controlInputMethodAnim correctly when IME isn't ready"

parents 4183a629 d7f10ed0
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -87,7 +87,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
     * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}.
     * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}.
     */
     */
    @Override
    @Override
    @ShowResult int requestShow(boolean fromIme) {
    public @ShowResult int requestShow(boolean fromIme) {
        // TODO: ResultReceiver for IME.
        // TODO: ResultReceiver for IME.
        // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
        // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
        if (fromIme) {
        if (fromIme) {
@@ -95,7 +95,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
        }
        }


        return getImm().requestImeShow(null /* resultReceiver */)
        return getImm().requestImeShow(null /* resultReceiver */)
                ? ShowResult.SHOW_DELAYED : ShowResult.SHOW_FAILED;
                ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
    }
    }


    /**
    /**
+97 −39
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package android.view;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.toPublicType;
import static android.view.InsetsState.toPublicType;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;


@@ -31,6 +32,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
@@ -55,6 +57,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.function.BiFunction;


/**
/**
 * Implements {@link WindowInsetsController} on the client.
 * Implements {@link WindowInsetsController} on the client.
@@ -64,6 +67,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation


    private static final int ANIMATION_DURATION_SHOW_MS = 275;
    private static final int ANIMATION_DURATION_SHOW_MS = 275;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;
    private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;


    static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
    static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);


@@ -241,6 +245,30 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            mStartingAnimation = startingAnimation;
            mStartingAnimation = startingAnimation;
        }
        }
    }
    }
    /**
     * Represents a control request that we had to defer because we are waiting for the IME to
     * process our show request.
     */
    private static class PendingControlRequest {

        PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
                long durationMs, Interpolator interpolator, @AnimationType int animationType,
                @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
            this.types = types;
            this.listener = listener;
            this.durationMs = durationMs;
            this.interpolator = interpolator;
            this.animationType = animationType;
            this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
        }

        final @InsetsType int types;
        final WindowInsetsAnimationControlListener listener;
        final long durationMs;
        final Interpolator interpolator;
        final @AnimationType int animationType;
        final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
    }


    private final String TAG = "InsetsControllerImpl";
    private final String TAG = "InsetsControllerImpl";


@@ -248,8 +276,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private final InsetsState mTmpState = new InsetsState();
    private final InsetsState mTmpState = new InsetsState();


    private final Rect mFrame = new Rect();
    private final Rect mFrame = new Rect();
    private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
    private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
    private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
    private final ViewRootImpl mViewRoot;
    private final ViewRootImpl mViewRoot;
    private final Handler mHandler;


    private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
    private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
    private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
    private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
@@ -263,7 +293,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private final Rect mLastLegacyContentInsets = new Rect();
    private final Rect mLastLegacyContentInsets = new Rect();
    private final Rect mLastLegacyStableInsets = new Rect();
    private final Rect mLastLegacyStableInsets = new Rect();


    private int mPendingTypesToShow;
    /** Pending control request that is waiting on IME to be ready to be shown */
    private PendingControlRequest mPendingImeControlRequest;


    private int mLastLegacySoftInputMode;
    private int mLastLegacySoftInputMode;
    private int mLastLegacySystemUiFlags;
    private int mLastLegacySystemUiFlags;
@@ -271,8 +302,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation


    private SyncRtSurfaceTransactionApplier mApplier;
    private SyncRtSurfaceTransactionApplier mApplier;


    private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;

    public InsetsController(ViewRootImpl viewRoot) {
    public InsetsController(ViewRootImpl viewRoot) {
        this(viewRoot, (controller, type) -> {
            if (type == ITYPE_IME) {
                return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller);
            } else {
                return new InsetsSourceConsumer(type, controller.mState, Transaction::new,
                        controller);
            }
        }, viewRoot.mHandler);
    }

    @VisibleForTesting
    public InsetsController(ViewRootImpl viewRoot,
            BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator,
            Handler handler) {
        mViewRoot = viewRoot;
        mViewRoot = viewRoot;
        mConsumerCreator = consumerCreator;
        mHandler = handler;
        mAnimCallback = () -> {
        mAnimCallback = () -> {
            mAnimCallbackScheduled = false;
            mAnimCallbackScheduled = false;
            if (mRunningAnimations.isEmpty()) {
            if (mRunningAnimations.isEmpty()) {
@@ -393,7 +442,21 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        show(types, false /* fromIme */);
        show(types, false /* fromIme */);
    }
    }


    void show(@InsetsType int types, boolean fromIme) {
    @VisibleForTesting
    public void show(@InsetsType int types, boolean fromIme) {

        // Handle pending request ready in case there was one set.
        if (fromIme && mPendingImeControlRequest != null) {
            PendingControlRequest pendingRequest = mPendingImeControlRequest;
            mPendingImeControlRequest = null;
            mHandler.removeCallbacks(mPendingControlTimeout);
            controlAnimationUnchecked(pendingRequest.types, pendingRequest.listener, mFrame,
                    true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
                    false /* fade */, pendingRequest.animationType,
                    pendingRequest.layoutInsetsDuringAnimation);
            return;
        }

        // TODO: Support a ResultReceiver for IME.
        // TODO: Support a ResultReceiver for IME.
        // TODO(b/123718661): Make show() work for multi-session IME.
        // TODO(b/123718661): Make show() work for multi-session IME.
        int typesReady = 0;
        int typesReady = 0;
@@ -463,6 +526,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
        if (types == 0) {
        if (types == 0) {
            // nothing to animate.
            // nothing to animate.
            listener.onCancelled();
            return;
            return;
        }
        }
        cancelExistingControllers(types);
        cancelExistingControllers(types);
@@ -471,19 +535,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
        final SparseArray<InsetsSourceControl> controls = new SparseArray<>();


        Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
        Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
                fromIme, internalTypes, controls, listener);
                fromIme, internalTypes, controls);
        int typesReady = typesReadyPair.first;
        int typesReady = typesReadyPair.first;
        boolean isReady = typesReadyPair.second;
        boolean imeReady = typesReadyPair.second;
        if (!isReady) {
        if (!imeReady) {
            // IME isn't ready, all requested types would be shown once IME is ready.
            // IME isn't ready, all requested types will be animated once IME is ready
            mPendingTypesToShow = typesReady;
            abortPendingImeControlRequest();
            // TODO: listener for pending types.
            mPendingImeControlRequest = new PendingControlRequest(types, listener, durationMs,
                    interpolator, animationType, layoutInsetsDuringAnimation);
            mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
            return;
            return;
        }
        }


        // pending types from previous request.
        typesReady = collectPendingTypes(typesReady);

        if (typesReady == 0) {
        if (typesReady == 0) {
            listener.onCancelled();
            listener.onCancelled();
            return;
            return;
@@ -496,13 +559,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    }
    }


    /**
    /**
     * @return Pair of (types ready to animate, is ready to animate).
     * @return Pair of (types ready to animate, IME ready to animate).
     */
     */
    private Pair<Integer, Boolean> collectSourceControls(boolean fromIme,
    private Pair<Integer, Boolean> collectSourceControls(boolean fromIme,
            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls,
            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls) {
            WindowInsetsAnimationControlListener listener) {
        int typesReady = 0;
        int typesReady = 0;
        boolean isReady = true;
        boolean imeReady = true;
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
            InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
            InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
            boolean setVisible = !consumer.isRequestedVisible();
            boolean setVisible = !consumer.isRequestedVisible();
@@ -512,16 +574,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                    case ShowResult.SHOW_IMMEDIATELY:
                    case ShowResult.SHOW_IMMEDIATELY:
                        typesReady |= InsetsState.toPublicType(consumer.getType());
                        typesReady |= InsetsState.toPublicType(consumer.getType());
                        break;
                        break;
                    case ShowResult.SHOW_DELAYED:
                    case ShowResult.IME_SHOW_DELAYED:
                        isReady = false;
                        imeReady = false;
                        break;
                        break;
                    case ShowResult.SHOW_FAILED:
                    case ShowResult.IME_SHOW_FAILED:
                        // IME cannot be shown (since it didn't have focus), proceed
                        // IME cannot be shown (since it didn't have focus), proceed
                        // with animation of other types.
                        // with animation of other types.
                        if (mPendingTypesToShow != 0) {
                            // remove IME from pending because view no longer has focus.
                            mPendingTypesToShow &= ~InsetsState.toPublicType(ITYPE_IME);
                        }
                        break;
                        break;
                }
                }
            } else {
            } else {
@@ -538,13 +596,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                controls.put(consumer.getType(), control);
                controls.put(consumer.getType(), control);
            }
            }
        }
        }
        return new Pair<>(typesReady, isReady);
        return new Pair<>(typesReady, imeReady);
    }

    private int collectPendingTypes(@InsetsType int typesReady) {
        typesReady |= mPendingTypesToShow;
        mPendingTypesToShow = 0;
        return typesReady;
    }
    }


    private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode(
    private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode(
@@ -577,6 +629,17 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                cancelAnimation(control, true /* invokeCallback */);
                cancelAnimation(control, true /* invokeCallback */);
            }
            }
        }
        }
        if ((types & ime()) != 0) {
            abortPendingImeControlRequest();
        }
    }

    private void abortPendingImeControlRequest() {
        if (mPendingImeControlRequest != null) {
            mPendingImeControlRequest.listener.onCancelled();
            mPendingImeControlRequest = null;
            mHandler.removeCallbacks(mPendingControlTimeout);
        }
    }
    }


    @VisibleForTesting
    @VisibleForTesting
@@ -608,6 +671,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                cancelAnimation(control, true /* invokeCallback */);
                cancelAnimation(control, true /* invokeCallback */);
            }
            }
        }
        }
        if (consumer.getType() == ITYPE_IME) {
            abortPendingImeControlRequest();
        }
    }
    }


    private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) {
    private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) {
@@ -635,7 +701,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        if (controller != null) {
        if (controller != null) {
            return controller;
            return controller;
        }
        }
        controller = createConsumerOfType(type);
        controller = mConsumerCreator.apply(this, type);
        mSourceConsumers.put(type, controller);
        mSourceConsumers.put(type, controller);
        return controller;
        return controller;
    }
    }
@@ -696,14 +762,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        return ANIMATION_TYPE_NONE;
        return ANIMATION_TYPE_NONE;
    }
    }


    private InsetsSourceConsumer createConsumerOfType(int type) {
        if (type == ITYPE_IME) {
            return new ImeInsetsSourceConsumer(mState, Transaction::new, this);
        } else {
            return new InsetsSourceConsumer(type, mState, Transaction::new, this);
        }
    }

    /**
    /**
     * Sends the local visibility state back to window manager.
     * Sends the local visibility state back to window manager.
     */
     */
+5 −4
Original line number Original line Diff line number Diff line
@@ -36,7 +36,7 @@ import java.util.function.Supplier;
public class InsetsSourceConsumer {
public class InsetsSourceConsumer {


    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.SHOW_DELAYED, ShowResult.SHOW_FAILED})
    @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED})
    @interface ShowResult {
    @interface ShowResult {
        /**
        /**
         * Window type is ready to be shown, will be shown immidiately.
         * Window type is ready to be shown, will be shown immidiately.
@@ -46,12 +46,12 @@ public class InsetsSourceConsumer {
         * Result will be delayed. Window needs to be prepared or request is not from controller.
         * Result will be delayed. Window needs to be prepared or request is not from controller.
         * Request will be delegated to controller and may or may not be shown.
         * Request will be delegated to controller and may or may not be shown.
         */
         */
        int SHOW_DELAYED = 1;
        int IME_SHOW_DELAYED = 1;
        /**
        /**
         * Window will not be shown because one of the conditions couldn't be met.
         * Window will not be shown because one of the conditions couldn't be met.
         * (e.g. in IME's case, when no editor is focused.)
         * (e.g. in IME's case, when no editor is focused.)
         */
         */
        int SHOW_FAILED = 2;
        int IME_SHOW_FAILED = 2;
    }
    }


    protected final InsetsController mController;
    protected final InsetsController mController;
@@ -155,7 +155,8 @@ public class InsetsSourceConsumer {
     *                       {@link android.inputmethodservice.InputMethodService}).
     *                       {@link android.inputmethodservice.InputMethodService}).
     * @return @see {@link ShowResult}.
     * @return @see {@link ShowResult}.
     */
     */
    @ShowResult int requestShow(boolean fromController) {
    @VisibleForTesting
    public @ShowResult int requestShow(boolean fromController) {
        return ShowResult.SHOW_IMMEDIATELY;
        return ShowResult.SHOW_IMMEDIATELY;
    }
    }


+2 −1
Original line number Original line Diff line number Diff line
@@ -636,6 +636,7 @@ public final class ViewRootImpl implements ViewParent,
            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
                    new InputEventConsistencyVerifier(this, 0) : null;
                    new InputEventConsistencyVerifier(this, 0) : null;


    private final InsetsController mInsetsController;
    private final ImeFocusController mImeFocusController;
    private final ImeFocusController mImeFocusController;


    /**
    /**
@@ -646,7 +647,6 @@ public final class ViewRootImpl implements ViewParent,
        return mImeFocusController;
        return mImeFocusController;
    }
    }


    private final InsetsController mInsetsController = new InsetsController(this);


    private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();
    private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();


@@ -705,6 +705,7 @@ public final class ViewRootImpl implements ViewParent,
        mFallbackEventHandler = new PhoneFallbackEventHandler(context);
        mFallbackEventHandler = new PhoneFallbackEventHandler(context);
        mChoreographer = Choreographer.getInstance();
        mChoreographer = Choreographer.getInstance();
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        mInsetsController = new InsetsController(this);


        String processorOverrideName = context.getResources().getString(
        String processorOverrideName = context.getResources().getString(
                                    R.string.config_inputEventCompatProcessorOverrideClassName);
                                    R.string.config_inputEventCompatProcessorOverrideClassName);
+1 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ android_test {
        "truth-prebuilt",
        "truth-prebuilt",
        "print-test-util-lib",
        "print-test-util-lib",
        "testng",
        "testng",
        "servicestests-utils"
    ],
    ],


    libs: [
    libs: [
Loading