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

Commit ec8e715b authored by Felix Stern's avatar Felix Stern
Browse files

Changes in ImeTracker to be compatible with the InsetsController refactoring

- passing the statsToken (via `InsetsController#reportRequestedVisibleTypes`), and `onControlsChanged`
- setting the mStatsToken in the ImeInsetsSourceProvider after the IME was started/hidden to use when the IME control is dispatched
- adding new phases

Test: atest CtsInputMethodTestCases
Flag: android.view.inputmethod.refactor_insets_controller
Fix: 329229469
Change-Id: Iea89ee3fc15c6a487ccac660ae1edd55ad0488bb
parent 523f9b01
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -974,6 +974,11 @@ public class InputMethodService extends AbstractInputMethodService {
                                : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
            }
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            if (android.view.inputmethod.Flags.refactorInsetsController()) {
                // 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);
            }
        }

        /**
@@ -3104,6 +3109,13 @@ 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 */);
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
@@ -3127,7 +3139,9 @@ 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);
@@ -3238,6 +3252,20 @@ public class InputMethodService extends AbstractInputMethodService {
                ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken);
    }

    /**
     * Notifies the ImeInsetsSourceProvider before the IME visibility changes.
     *
     * @param visible {@code true} if it became visible, {@code false} otherwise.
     * @param statsToken the token tracking the current IME request.
     */
    private void notifyPreImeWindowVisibilityChanged(boolean visible,
            @NonNull ImeTracker.Token statsToken) {
        final var viewRootImpl = getWindow().getWindow().getDecorView().getViewRootImpl();
        if (viewRootImpl != null) {
            viewRootImpl.notifyImeVisibilityChanged(visible, statsToken);
        }
    }

    private void finishViews(boolean finishingInput) {
        if (mInputViewStarted) {
            if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
@@ -3279,7 +3307,13 @@ public class InputMethodService extends AbstractInputMethodService {
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
                null /* icProto */);
        setImeWindowStatus(0, mBackDisposition);
        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) {
+13 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.view.IWindow;
import android.view.IWindowId;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.inputmethod.ImeTracker;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
@@ -276,7 +277,8 @@ interface IWindowSession {
    /**
     * Updates the requested visible types of insets.
     */
    oneway void updateRequestedVisibleTypes(IWindow window, int requestedVisibleTypes);
    oneway void updateRequestedVisibleTypes(IWindow window, int requestedVisibleTypes,
            in @nullable ImeTracker.Token imeStatsToken);

    /**
     * Called when the system gesture exclusion has changed.
@@ -369,4 +371,14 @@ interface IWindowSession {
     * @return {@code true} if the focus changes. Otherwise, {@code false}.
     */
    boolean moveFocusToAdjacentWindow(IWindow fromWindow, int direction);

    /**
     * Notifies the statsToken and IME visibility to the ImeInsetsSourceProvider.
     *
     * @param window The window that is used to get the ImeInsetsSourceProvider.
     * @param visible {@code true} to make it visible, {@code false} to hide it.
     * @param statsToken the token tracking the current IME request.
     */
    oneway void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
            in ImeTracker.Token statsToken);
}
+56 −19
Original line number Diff line number Diff line
@@ -121,8 +121,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
         * The visibilities should be reported back to WM.
         *
         * @param types Bitwise flags of types requested visible.
         * @param statsToken the token tracking the current IME request or {@code null} otherwise.
         */
        void updateRequestedVisibleTypes(@InsetsType int types);
        void updateRequestedVisibleTypes(@InsetsType int types,
                @Nullable ImeTracker.Token statsToken);

        /**
         * @return Whether the host has any callbacks it wants to synchronize the animations with.
@@ -974,6 +976,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        int consumedControlCount = 0;
        final @InsetsType int[] showTypes = new int[1];
        final @InsetsType int[] hideTypes = new int[1];
        ImeTracker.Token statsToken = null;

        // Ensure to update all existing source consumers
        for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
@@ -988,6 +991,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            if (control != null) {
                controllableTypes |= control.getType();
                consumedControlCount++;

                if (Flags.refactorInsetsController()) {
                    if (control.getId() == ID_IME) {
                        statsToken = control.getImeStatsToken();
                    }
                }
            }

            // control may be null, but we still need to update the control to null if it got
@@ -1021,34 +1030,31 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        if (Flags.refactorInsetsController()) {
            if (mPendingImeControlRequest != null && getImeSourceConsumer().getControl() != null
                    && getImeSourceConsumer().getControl().getLeash() != null) {
                // TODO we need to pass the statsToken
                handlePendingControlRequest(null);
                handlePendingControlRequest(statsToken);
            } else {
                if (showTypes[0] != 0) {
                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
                            null /* statsToken */);
                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
                }
                if (hideTypes[0] != 0) {
                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
                            null /* statsToken */);
                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
                }
            }
        } else {
            if (showTypes[0] != 0) {
                final var statsToken =
                final var newStatsToken =
                        (showTypes[0] & ime()) == 0 ? null : ImeTracker.forLogging().onStart(
                                ImeTracker.TYPE_SHOW, ImeTracker.ORIGIN_CLIENT,
                                SoftInputShowHideReason.CONTROLS_CHANGED,
                                mHost.isHandlingPointerEvent() /* fromUser */);
                applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
                applyAnimation(showTypes[0], true /* show */, false /* fromIme */, newStatsToken);
            }
            if (hideTypes[0] != 0) {
                final var statsToken =
                final var newStatsToken =
                        (hideTypes[0] & ime()) == 0 ? null : ImeTracker.forLogging().onStart(
                                ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
                                SoftInputShowHideReason.CONTROLS_CHANGED,
                                mHost.isHandlingPointerEvent() /* fromUser */);
                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, newStatsToken);
            }
        }

@@ -1065,7 +1071,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        }

        // InsetsSourceConsumer#setControl might change the requested visibility.
        reportRequestedVisibleTypes();
        // TODO(b/353463205) check this: if the requestedVisibleTypes for the IME were already
        //  sent, the request would fail. Therefore, don't send the statsToken here.
        reportRequestedVisibleTypes(null /* statsToken */);
    }

    @VisibleForTesting(visibility = PACKAGE)
@@ -1176,6 +1184,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        }
        if (DEBUG) Log.d(TAG, "show typesReady: " + typesReady);
        if ((Flags.refactorInsetsController() || fromIme) && (typesReady & Type.ime()) != 0) {
            // TODO(b/353463205) check if this is needed here
            ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
        }
        applyAnimation(typesReady, true /* show */, fromIme, statsToken);
@@ -1243,6 +1252,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                    // an animation again (mRequestedVisibleTypes are reported at the end of the IME
                    // hide animation but set at the beginning)
                    if ((mRequestedVisibleTypes & ime()) == 0) {
                        ImeTracker.forLogging().onCancelled(statsToken,
                                ImeTracker.PHASE_CLIENT_ALREADY_HIDDEN);
                        continue;
                    }
                }
@@ -1346,7 +1357,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        // We are finishing setting the requested visible types. Report them to the server
        // and/or the app.
        reportRequestedVisibleTypes();
        reportRequestedVisibleTypes(statsToken);
    }

    private void controlAnimationUncheckedInner(@InsetsType int types,
@@ -1396,8 +1407,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            // Ime will not be contained in typesReady nor in controls, if we don't have a leash
            Pair<Integer, Integer> typesReadyPair = collectSourceControlsV2(types, controls);
            typesReady = typesReadyPair.first;
            @InsetsType int typesWithoutLeash = typesReadyPair.second;
            if (animationType == ANIMATION_TYPE_USER) {
                @InsetsType int typesWithoutLeash = typesReadyPair.second;
                // When using an app-driven animation, the IME won't have a leash (because the
                // window isn't created yet). If we have a control, but no leash, defers the
                // request until the leash gets created.
@@ -1431,6 +1442,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                }
                // We need to wait until all types are ready
                if (typesReady != types) {
                    if (DEBUG) {
                        Log.d(TAG, TextUtils.formatSimple(
                                "not all types are ready yet, waiting. typesReady: %s, types: %s",
                                typesReady, types));
                    }
                    return;
                }
            }
@@ -1728,9 +1744,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        } else {
            ImeTracker.forLogging().onProgress(statsToken,
                    ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_HIDE);
            // The requestedVisibleTypes are only send at the end of the hide animation.
            // Therefore, the requested is not finished at this point.
            if (!Flags.refactorInsetsController()) {
                ImeTracker.forLogging().onHidden(statsToken);
            }
        reportRequestedVisibleTypes();
        }
        reportRequestedVisibleTypes(shown ? null : runner.getStatsToken());
    }

    @Override
@@ -1787,7 +1807,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                            if (mHost != null) {
                                // if the (hide) animation is cancelled, the
                                // requestedVisibleTypes should be reported at this point.
                                reportRequestedVisibleTypes();
                                reportRequestedVisibleTypes(control.getStatsToken());
                                mHost.getInputMethodManager().removeImeSurface(
                                        mHost.getWindowToken());
                            }
@@ -1923,8 +1943,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    /**
     * Called when finishing setting requested visible types or finishing setting controls.
     *
     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
     */
    private void reportRequestedVisibleTypes() {
    private void reportRequestedVisibleTypes(@Nullable ImeTracker.Token statsToken) {
        final @InsetsType int typesToReport;
        if (Flags.refactorInsetsController()) {
            // If the IME is currently animating out, it is still visible, therefore we only
@@ -1941,8 +1963,23 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            if (WindowInsets.Type.hasCompatSystemBars(diff)) {
                mCompatSysUiVisibilityStaled = true;
            }
            if (Flags.refactorInsetsController()) {
                ImeTracker.forLogging().onProgress(statsToken,
                        ImeTracker.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES);
            }
            mReportedRequestedVisibleTypes = mRequestedVisibleTypes;
            mHost.updateRequestedVisibleTypes(mReportedRequestedVisibleTypes);
            mHost.updateRequestedVisibleTypes(mReportedRequestedVisibleTypes, statsToken);
        } else if (Flags.refactorInsetsController()) {
            if ((typesToReport & ime()) != 0 && mImeSourceConsumer != null) {
                InsetsSourceControl control = mImeSourceConsumer.getControl();
                if (control != null && control.getLeash() == null) {
                    // If the IME was requested twice, and we didn't receive the controls
                    // yet, this request will not continue. It should be cancelled here, as
                    // it would time out otherwise.
                    ImeTracker.forLogging().onCancelled(statsToken,
                            ImeTracker.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES);
                }
            }
        }
        updateCompatSysUiVisibility();
    }
+20 −2
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.proto.ProtoOutputStream;
import android.view.WindowInsets.Type.InsetsType;
import android.view.inputmethod.ImeTracker;

import java.io.PrintWriter;
import java.util.Arrays;
@@ -56,6 +57,9 @@ public class InsetsSourceControl implements Parcelable {
    private boolean mSkipAnimationOnce;
    private int mParcelableFlags;

    /** The token tracking the current IME request */
    private @Nullable ImeTracker.Token mImeStatsToken;

    public InsetsSourceControl(int id, @InsetsType int type, @Nullable SurfaceControl leash,
            boolean initiallyVisible, Point surfacePosition, Insets insetsHint) {
        mId = id;
@@ -78,6 +82,7 @@ public class InsetsSourceControl implements Parcelable {
        mSurfacePosition = new Point(other.mSurfacePosition);
        mInsetsHint = other.mInsetsHint;
        mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
        mImeStatsToken = other.getImeStatsToken();
    }

    public InsetsSourceControl(Parcel in) {
@@ -88,6 +93,7 @@ public class InsetsSourceControl implements Parcelable {
        mSurfacePosition = in.readTypedObject(Point.CREATOR);
        mInsetsHint = in.readTypedObject(Insets.CREATOR);
        mSkipAnimationOnce = in.readBoolean();
        mImeStatsToken = in.readTypedObject(ImeTracker.Token.CREATOR);
    }

    public int getId() {
@@ -153,6 +159,15 @@ public class InsetsSourceControl implements Parcelable {
        return result;
    }

    @Nullable
    public ImeTracker.Token getImeStatsToken() {
        return mImeStatsToken;
    }

    public void setImeStatsToken(@Nullable ImeTracker.Token imeStatsToken) {
        mImeStatsToken = imeStatsToken;
    }

    public void setParcelableFlags(int parcelableFlags) {
        mParcelableFlags = parcelableFlags;
    }
@@ -171,6 +186,7 @@ public class InsetsSourceControl implements Parcelable {
        dest.writeTypedObject(mSurfacePosition, mParcelableFlags);
        dest.writeTypedObject(mInsetsHint, mParcelableFlags);
        dest.writeBoolean(mSkipAnimationOnce);
        dest.writeTypedObject(mImeStatsToken, mParcelableFlags);
    }

    public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
@@ -196,13 +212,14 @@ public class InsetsSourceControl implements Parcelable {
                && mInitiallyVisible == that.mInitiallyVisible
                && mSurfacePosition.equals(that.mSurfacePosition)
                && mInsetsHint.equals(that.mInsetsHint)
                && mSkipAnimationOnce == that.mSkipAnimationOnce;
                && mSkipAnimationOnce == that.mSkipAnimationOnce
                && Objects.equals(mImeStatsToken, that.mImeStatsToken);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mId, mType, mLeash, mInitiallyVisible, mSurfacePosition, mInsetsHint,
                mSkipAnimationOnce);
                mSkipAnimationOnce, mImeStatsToken);
    }

    @Override
@@ -225,6 +242,7 @@ public class InsetsSourceControl implements Parcelable {
        pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
        pw.print(" mInsetsHint="); pw.print(mInsetsHint);
        pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
        pw.print(" mImeStatsToken="); pw.print(mImeStatsToken);
        pw.println();
    }

+18 −0
Original line number Diff line number Diff line
@@ -10056,6 +10056,24 @@ public final class ViewRootImpl implements ViewParent,
        mHandler.sendMessage(msg);
    }
    /**
     * Dispatches the statsToken and IME visibility to the ImeInsetsSourceProvider.
     *
     * @param visible {@code true} if it became visible, {@code false} otherwise.
     * @param statsToken the token tracking the current IME request.
     *
     * @hide
     */
    public void notifyImeVisibilityChanged(boolean visible, @NonNull ImeTracker.Token statsToken) {
        ImeTracker.forLogging().onProgress(statsToken,
                ImeTracker.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED);
        try {
            mWindowSession.notifyImeWindowVisibilityChangedFromClient(mWindow, visible, statsToken);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
    }
    /**
     * Represents a pending input event that is waiting in a queue.
     *
Loading