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

Commit 1dad36fb authored by Felix Stern's avatar Felix Stern
Browse files

Remove refactorInsetsController Flag

Fix: 409604617
Test: atest CtsInputMethodTestCases
Flag: EXEMPT flag removal
Change-Id: I2b04517af59b949d30929db577c288b7232cfe65
parent 679475ec
Loading
Loading
Loading
Loading
+13 −13
Original line number Diff line number Diff line
@@ -225,12 +225,12 @@ class IInputMethodWrapper extends IInputMethod.Stub
                return;
            case DO_SHOW_SOFT_INPUT: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg3;
                final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg2;
                if (isValid(inputMethod, target, "DO_SHOW_SOFT_INPUT")) {
                    ImeTracker.forLogging().onProgress(
                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
                    inputMethod.showSoftInputWithToken(
                            msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1, statsToken);
                    inputMethod.showSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg1,
                            statsToken);
                } else {
                    ImeTracker.forLogging().onFailed(
                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
@@ -240,12 +240,12 @@ class IInputMethodWrapper extends IInputMethod.Stub
            }
            case DO_HIDE_SOFT_INPUT: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg3;
                final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg2;
                if (isValid(inputMethod, target, "DO_HIDE_SOFT_INPUT")) {
                    ImeTracker.forLogging().onProgress(
                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
                    inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
                            (IBinder) args.arg1, statsToken);
                    inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg1,
                            statsToken);
                } else {
                    ImeTracker.forLogging().onFailed(
                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
@@ -453,20 +453,20 @@ class IInputMethodWrapper extends IInputMethod.Stub

    @BinderThread
    @Override
    public void showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
    public void showSoftInput(@NonNull ImeTracker.Token statsToken,
            @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
        mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
                flags, showInputToken, resultReceiver, statsToken));
        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_SHOW_SOFT_INPUT,
                flags, resultReceiver, statsToken));
    }

    @BinderThread
    @Override
    public void hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
            int flags, ResultReceiver resultReceiver) {
    public void hideSoftInput(@NonNull ImeTracker.Token statsToken, int flags,
            ResultReceiver resultReceiver) {
        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
        mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT,
                flags, hideInputToken, resultReceiver, statsToken));
        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_HIDE_SOFT_INPUT,
                flags, resultReceiver, statsToken));
    }

    @BinderThread
+14 −66
Original line number Diff line number Diff line
@@ -87,7 +87,6 @@ import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.Region;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -649,26 +648,6 @@ public class InputMethodService extends AbstractInputMethodService {
    // committed by commitHandwritingDelegationTextIfAvailable().
    private CharSequence mHandwritingDelegationText;

    /**
     * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
     * The original app window token is passed from client app window.
     * {@link com.android.server.inputmethod.InputMethodManagerService} creates a unique
     * placeholder token to identify this window.
     * This placeholder token is only valid for a single call to
     * {@link InputMethodImpl#showSoftInput}, after which it is set null until next call.
     */
    private IBinder mCurShowInputToken;

    /**
     * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#hideSoftInput}
     * The original app window token is passed from client app window.
     * {@link com.android.server.inputmethod.InputMethodManagerService} creates a unique
     * placeholder token to identify this window.
     * This placeholder token is only valid for a single call to
     * {@link InputMethodImpl#hideSoftInput}, after which it is set {@code null} until next call.
     */
    private IBinder mCurHideInputToken;

    /**
     * The token tracking the current IME request.
     *
@@ -881,14 +860,12 @@ public class InputMethodService extends AbstractInputMethodService {
        @MainThread
        @Override
        public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
                IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) {
                @NonNull ImeTracker.Token statsToken) {
            mSystemCallingHideSoftInput = true;
            mCurHideInputToken = hideInputToken;
            mCurStatsToken = statsToken;
            try {
                hideSoftInput(flags, resultReceiver);
            } finally {
                mCurHideInputToken = null;
                mSystemCallingHideSoftInput = false;
            }
        }
@@ -936,14 +913,12 @@ public class InputMethodService extends AbstractInputMethodService {
                                : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
            }
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            if (android.view.inputmethod.Flags.refactorInsetsController()) {
            // After the IME window was hidden, we can remove its surface
            scheduleImeSurfaceRemoval();
            // The hide request first finishes the animation and then proceeds to the server
            // side, finally reaching here, marking this the end state.
            ImeTracker.forLogging().onHidden(statsToken);
        }
        }

        /**
         * {@inheritDoc}
@@ -952,15 +927,12 @@ public class InputMethodService extends AbstractInputMethodService {
        @MainThread
        @Override
        public void showSoftInputWithToken(@InputMethod.ShowFlags int flags,
                ResultReceiver resultReceiver, IBinder showInputToken,
                @NonNull ImeTracker.Token statsToken) {
                ResultReceiver resultReceiver, @NonNull ImeTracker.Token statsToken) {
            mSystemCallingShowSoftInput = true;
            mCurShowInputToken = showInputToken;
            mCurStatsToken = statsToken;
            try {
                showSoftInput(flags, resultReceiver);
            } finally {
                mCurShowInputToken = null;
                mSystemCallingShowSoftInput = false;
            }
        }
@@ -3108,12 +3080,10 @@ public class InputMethodService extends AbstractInputMethodService {

        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW);

        if (android.view.inputmethod.Flags.refactorInsetsController()) {
        // The ImeInsetsSourceProvider need the statsToken when dispatching the control
        // (whenever the IME has drawn and its window is visible). Therefore, sending the
        // statsToken here first.
        notifyPreImeWindowVisibilityChanged(true /* visible */, statsToken);
        }

        ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper,
                null /* icProto */);
@@ -3132,9 +3102,6 @@ public class InputMethodService extends AbstractInputMethodService {
        if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
        mWindow.show();
        mDecorViewWasVisible = true;
        if (!android.view.inputmethod.Flags.refactorInsetsController()) {
            applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken);
        }
        cancelImeSurfaceRemoval();
        mInShowWindow = false;
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3266,21 +3233,6 @@ public class InputMethodService extends AbstractInputMethodService {
        if (doShowInput) startExtractingText(false);
    }

    /**
     * Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}.
     *
     * @param setVisible {@code true} to make it visible, false to hide it.
     * @param statsToken the token tracking the current IME request.
     */
    private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible,
            @NonNull ImeTracker.Token statsToken) {
        ImeTracing.getInstance().triggerServiceDump(
                "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
                null /* icProto */);
        mPrivOps.applyImeVisibilityAsync(setVisible
                ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken);
    }

    /**
     * Notifies the ImeInsetsSourceProvider before the IME visibility changes.
     *
@@ -3336,13 +3288,9 @@ public class InputMethodService extends AbstractInputMethodService {
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
                null /* icProto */);
        setImeWindowVisibility(0 /* vis */);
        if (android.view.inputmethod.Flags.refactorInsetsController()) {
        // The ImeInsetsSourceProvider need the statsToken when dispatching the control. We
        // send the token here, so that another request in the provider can be cancelled.
        notifyPreImeWindowVisibilityChanged(false /* visible */, statsToken);
        } else {
            applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken);
        }
        mWindowVisible = false;
        finishViews(false /* finishingInput */);
        if (mDecorViewVisible) {
+4 −7
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import android.util.Log;
import android.view.animation.BackGestureInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.inputmethod.Flags;
import android.view.inputmethod.ImeTracker;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -151,13 +150,11 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
        } else {
            startPostCommitAnim(/*hideIme*/ true);
        }
        if (Flags.refactorInsetsController()) {
        // Unregister all IME back callbacks so that back events are sent to the next callback
        // even while the hide animation is playing
        mInsetsController.getHost().getInputMethodManager().getImeOnBackInvokedDispatcher()
                .preliminaryClear();
    }
    }

    private void setPreCommitProgress(float progress) {
        if (isHideAnimationInProgress()) return;
+1 −3
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.annotation.NonNull;
import android.annotation.UiThread;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;

import com.android.internal.inputmethod.InputMethodDebug;
@@ -151,8 +150,7 @@ public final class ImeFocusController {
        if (!mHasImeFocus || isInLocalFocusMode(windowAttribute)) {
            return InputMethodManager.DISPATCH_NOT_HANDLED;
        }
        if (Flags.refactorInsetsController() && event instanceof KeyEvent keyEvent
                && keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        if (event instanceof KeyEvent keyEvent && keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            final var insetsController = mViewRootImpl.getInsetsController();
            if (insetsController.getAnimationType(WindowInsets.Type.ime())
                    == InsetsController.ANIMATION_TYPE_HIDE
+0 −291
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package android.view;

import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.ImeInsetsSourceConsumerProto.HAS_PENDING_REQUEST;
import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.Flags;
import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputMethodManager;

import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.SoftInputShowHideReason;

/**
 * Controls the visibility and animations of IME window insets source.
 * @hide
 */
public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {

    /**
     * Tracks whether are requested to show during the hide animation or requested to hide during
     * the show animation. If this is true, we should not remove the surface.
     */
    private boolean mHasPendingRequest;

    /**
     * Tracks whether we have an outstanding request from the IME to show, but weren't able to
     * execute it because we didn't have control yet, or we didn't have a leash on the control yet.
     */
    private boolean mIsRequestedVisibleAwaitingLeash;

    public ImeInsetsSourceConsumer(int id, InsetsState state, InsetsController controller) {
        super(id, WindowInsets.Type.ime(), state, controller);
    }

    @Override
    public boolean onAnimationStateChanged(boolean running) {
        if (Flags.refactorInsetsController()) {
            return super.onAnimationStateChanged(running);
        } else {
            if (!running) {
                ImeTracing.getInstance().triggerClientDump(
                        "ImeInsetsSourceConsumer#onAnimationFinished",
                        mController.getHost().getInputMethodManager(), null /* icProto */);
            }
            boolean insetsChanged = false;
            if (!running && isShowRequested() && mAnimationState == ANIMATION_STATE_HIDE) {
                // A user controlled hide animation may have ended in the shown state (e.g.
                // cancelled predictive back animation) -> Insets need to be reset to shown.
                insetsChanged |= applyLocalVisibilityOverride();
            }
            insetsChanged |= super.onAnimationStateChanged(running);
            if (running && !isShowRequested()
                    && mController.isPredictiveBackImeHideAnimInProgress()) {
                // IME predictive back animation switched from pre-commit to post-commit.
                insetsChanged |= applyLocalVisibilityOverride();
            }
            if (!isShowRequested()) {
                mIsRequestedVisibleAwaitingLeash = false;
                if (!running && !mHasPendingRequest) {
                    final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
                            ImeTracker.ORIGIN_CLIENT,
                            SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED,
                            mController.getHost().isHandlingPointerEvent() /* fromUser */);
                    notifyHidden(statsToken);
                    removeSurface();
                }
            }
            // This method is called
            // (1) after the animation starts.
            // (2) after the animation ends (including the case of cancel).
            // (3) if the IME is not controllable (running == false in this case).
            // We should reset mHasPendingRequest in all cases.
            mHasPendingRequest = false;
            return insetsChanged;
        }
    }

    @Override
    public void onWindowFocusGained(boolean hasViewFocus) {
        super.onWindowFocusGained(hasViewFocus);
        if (!Flags.refactorInsetsController()) {
            getImm().registerImeConsumer(this);
            if ((mController.getRequestedVisibleTypes() & getType()) != 0 && !hasLeash()) {
                mIsRequestedVisibleAwaitingLeash = true;
            }
        }
    }

    @Override
    public void onWindowFocusLost() {
        super.onWindowFocusLost();
        if (!Flags.refactorInsetsController()) {
            getImm().unregisterImeConsumer(this);
            mIsRequestedVisibleAwaitingLeash = false;
        }
    }

    @Override
    public boolean applyLocalVisibilityOverride() {
        if (!Flags.refactorInsetsController()) {
            ImeTracing.getInstance().triggerClientDump(
                    "ImeInsetsSourceConsumer#applyLocalVisibilityOverride",
                    mController.getHost().getInputMethodManager(), null /* icProto */);
        }
        return super.applyLocalVisibilityOverride();
    }

    /**
     * Request {@link InputMethodManager} to show the IME.
     * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}.
     */
    @Override
    @ShowResult
    public int requestShow(boolean fromIme, @Nullable ImeTracker.Token statsToken) {
        if (!Flags.refactorInsetsController()) {
            if (fromIme) {
                ImeTracing.getInstance().triggerClientDump(
                        "ImeInsetsSourceConsumer#requestShow",
                        mController.getHost().getInputMethodManager(), null /* icProto */);
            }
            onShowRequested();

            // TODO: ResultReceiver for IME.
            // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
            ImeTracker.forLogging().onProgress(statsToken,
                    ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW);

            if (!hasLeash()) {
                // If control or leash is null, schedule to show IME when both available.
                mIsRequestedVisibleAwaitingLeash = true;
            }
            // If we had a request before to show from IME (tracked with mImeRequestedShow),
            // reaching this code here means that we now got control, so we can start the
            // animation immediately. If client window is trying to control IME and IME is
            // already visible, it is immediate.
            if (fromIme || (mState.isSourceOrDefaultVisible(getId(), getType())
                    && hasLeash())) {
                return ShowResult.SHOW_IMMEDIATELY;
            }

            return getImm().requestImeShow(mController.getHost().getWindowToken(), statsToken)
                    ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
        } else {
            return ShowResult.IME_SHOW_FAILED;
        }
    }

    void requestHide(boolean fromIme, @Nullable ImeTracker.Token statsToken) {
        if (!Flags.refactorInsetsController()) {
            if (!fromIme) {
                // Create a new token to track the hide request when we have control and leash,
                // as we use the passed in token for the insets animation already.
                final var notifyStatsToken = hasLeash()
                        ? ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
                            ImeTracker.ORIGIN_CLIENT,
                            SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL,
                            mController.getHost().isHandlingPointerEvent() /* fromUser */)
                        : statsToken;
                // The insets might be controlled by a remote target. Let the server know we are
                // requested to hide.
                notifyHidden(notifyStatsToken);
            }
            if (mAnimationState == ANIMATION_STATE_SHOW) {
                mHasPendingRequest = true;
            }
        }
    }

    /**
     * Notify {@link com.android.server.inputmethod.InputMethodManagerService} that
     * IME insets are hidden.
     *
     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
     */
    private void notifyHidden(@NonNull ImeTracker.Token statsToken) {
        if (!Flags.refactorInsetsController()) {
            ImeTracker.forLogging().onProgress(statsToken,
                    ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN);

            getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken);
            mIsRequestedVisibleAwaitingLeash = false;
            Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
        }
    }

    @Override
    public void removeSurface() {
        if (Flags.refactorInsetsController()) {
            super.removeSurface();
        } else {
            final IBinder window = mController.getHost().getWindowToken();
            if (window != null) {
                getImm().removeImeSurface(window);
            }
        }
    }

    @Override
    public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
            int[] hideTypes, int[] cancelTypes, int[] transientTypes) {
        if (Flags.refactorInsetsController()) {
            return super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
        } else {
            ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
                    mController.getHost().getInputMethodManager(), null /* icProto */);
            if (!super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes)) {
                return false;
            }
            if (control == null && !mIsRequestedVisibleAwaitingLeash) {
                mController.setRequestedVisibleTypes(0 /* visibleTypes */, getType());
                removeSurface();
            }
            final boolean hasLeash = control != null && control.getLeash() != null;
            if (hasLeash) {
                mIsRequestedVisibleAwaitingLeash = false;
            }
            return true;
        }
    }

    @Override
    protected boolean isRequestedVisibleAwaitingControl() {
        return super.isRequestedVisibleAwaitingControl() || mIsRequestedVisibleAwaitingLeash;
    }

    /**
     * Checks whether the consumer has an insets source control with a leash.
     */
    private boolean hasLeash() {
        final var control = getControl();
        return control != null && control.getLeash() != null;
    }

    @Override
    public void onPerceptible(boolean perceptible) {
        super.onPerceptible(perceptible);
        if (!Flags.refactorInsetsController()) {
            final IBinder window = mController.getHost().getWindowToken();
            if (window != null) {
                getImm().reportPerceptible(window, perceptible);
            }
        }
    }

    @Override
    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
        final long token = proto.start(fieldId);
        super.dumpDebug(proto, INSETS_SOURCE_CONSUMER);
        proto.write(IS_REQUESTED_VISIBLE_AWAITING_CONTROL, mIsRequestedVisibleAwaitingLeash);
        proto.write(HAS_PENDING_REQUEST, mHasPendingRequest);
        proto.end(token);
    }

    /**
     * Called when {@link #requestShow(boolean, ImeTracker.Token)} or
     * {@link InputMethodManager#showSoftInput(View, int)} is called.
     */
    public void onShowRequested() {
        if (mAnimationState == ANIMATION_STATE_HIDE
                || mController.isPredictiveBackImeHideAnimInProgress()) {
            mHasPendingRequest = true;
        }
    }

    private InputMethodManager getImm() {
        return mController.getHost().getInputMethodManager();
    }
}
Loading