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

Commit 708c957f authored by Hiroki Sato's avatar Hiroki Sato
Browse files

Add private API InputMethodManager#reportVirtualDisplayGeometry

This logically relands the change [1] which added an @hide api
InputMethodManager#reportActivityView() with renaming as
reportVirtualDisplayGeometry().

Because ActivityView was removed, this API was removed [2] once.
However, because this API is useful for OEM customization, this change
adds the same API with a generalized method name.

Note that there was a change on how cross-display input connection
cursor update is blocked [3]. Thus, this CL adapts to it.

[1] Id0411a80456182111bb5b681c6d1230b58e7ec2e
[2] Idd60d96a39f827197d189beb5de016446576d9cd
[3] Iec12733d37e112b7271436bba15094ae2a55a450

Bug: 224424149
Test: manual. Cursor is updated in cross-display connection.
Change-Id: I35b491da5a340844e17542d7a6198f8152bbeda3
parent 62af809a
Loading
Loading
Loading
Loading
+107 −1
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.Binder;
@@ -452,6 +453,18 @@ public final class InputMethodManager {
     */
    private CursorAnchorInfo mCursorAnchorInfo = null;

    /**
     * A special {@link Matrix} that can be provided by the system when this instance is running
     * inside a virtual display.
     *
     * <p>If this is non-{@code null}, {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}
     * should be adjusted with this {@link Matrix}.</p>
     *
     * <p>{@code null} when not used.</p>
     */
    @GuardedBy("mH")
    private Matrix mVirtualDisplayToScreenMatrix = null;

    /**
     * As reported by {@link InputBindResult}. This value is determined by
     * {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
@@ -528,6 +541,7 @@ public final class InputMethodManager {
    static final int MSG_REPORT_FULLSCREEN_MODE = 10;
    static final int MSG_BIND_ACCESSIBILITY_SERVICE = 11;
    static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
    static final int MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX = 30;

    private static boolean isAutofillUIShowing(View servedView) {
        AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -892,6 +906,7 @@ public final class InputMethodManager {
                                InputMethodSessionWrapper.createOrNull(res.method);
                        mCurId = res.id;
                        mBindSequence = res.sequence;
                        mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
                        mIsInputMethodSuppressingSpellChecker =
                                res.isInputMethodSuppressingSpellChecker;
                    }
@@ -1063,6 +1078,45 @@ public final class InputMethodManager {
                    }
                    return;
                }
                case MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX: {
                    final float[] matrixValues = (float[]) msg.obj;
                    final int bindSequence = msg.arg1;
                    synchronized (mH) {
                        if (mBindSequence != bindSequence) {
                            return;
                        }
                        if (matrixValues == null || mVirtualDisplayToScreenMatrix == null) {
                            // Either InputBoundResult#mVirtualDisplayToScreenMatrixValues is null
                            // OR this app is unbound from the parent VirtualDisplay. In this case,
                            // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
                            mVirtualDisplayToScreenMatrix = null;
                            return;
                        }

                        final float[] currentValues = new float[9];
                        mVirtualDisplayToScreenMatrix.getValues(currentValues);
                        if (Arrays.equals(currentValues, matrixValues)) {
                            return;
                        }
                        mVirtualDisplayToScreenMatrix.setValues(matrixValues);

                        if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
                                || mServedInputConnection == null) {
                            return;
                        }
                        final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode
                                & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
                        if (!isMonitoring) {
                            return;
                        }
                        // Since the host VirtualDisplay is moved, we need to issue
                        // IMS#updateCursorAnchorInfo() again.
                        mCurrentInputMethodSession.updateCursorAnchorInfo(
                                CursorAnchorInfo.createForAdditionalParentMatrix(
                                        mCursorAnchorInfo, mVirtualDisplayToScreenMatrix));
                    }
                    return;
                }
            }
        }
    }
@@ -1127,6 +1181,12 @@ public final class InputMethodManager {
                    .sendToTarget();
        }

        @Override
        public void updateVirtualDisplayToScreenMatrix(int bindSequence, float[] matrixValues) {
            mH.obtainMessage(MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX, bindSequence, 0,
                    matrixValues).sendToTarget();
        }

        @Override
        public void setImeTraceEnabled(boolean enabled) {
            ImeTracing.getInstance().setEnabled(enabled);
@@ -1596,7 +1656,9 @@ public final class InputMethodManager {
     * Disconnect any existing input connection, clearing the served view.
     */
    @UnsupportedAppUsage
    @GuardedBy("mH")
    void finishInputLocked() {
        mVirtualDisplayToScreenMatrix = null;
        mIsInputMethodSuppressingSpellChecker = false;
        setNextServedViewLocked(null);
        if (getServedViewLocked() != null) {
@@ -2275,6 +2337,7 @@ public final class InputMethodManager {
                        + InputMethodDebug.startInputFlagsToString(startInputFlags));
                return false;
            }
            mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
            mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
            if (res.id != null) {
                setInputChannelLocked(res.channel);
@@ -2695,7 +2758,13 @@ public final class InputMethodManager {
                return;
            }
            if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
            if (mVirtualDisplayToScreenMatrix != null) {
                mCurrentInputMethodSession.updateCursorAnchorInfo(
                        CursorAnchorInfo.createForAdditionalParentMatrix(
                                cursorAnchorInfo, mVirtualDisplayToScreenMatrix));
            } else {
                mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
            }
            mCursorAnchorInfo = cursorAnchorInfo;
            // Clear immediate bit (if any).
            mRequestUpdateCursorAnchorInfoMonitorMode &= ~CURSOR_UPDATE_IMMEDIATE;
@@ -3268,6 +3337,43 @@ public final class InputMethodManager {
        }
    }

    /**
     * An internal API for {@link android.hardware.display.VirtualDisplay} to report where its
     * embedded virtual display is placed.
     *
     * @param childDisplayId Display ID of the embedded virtual display.
     * @param matrix         {@link Matrix} to convert virtual display screen coordinates to
     *                       the host screen coordinates. {@code null} to clear the relationship.
     * @hide
     */
    public void reportVirtualDisplayGeometry(int childDisplayId, @Nullable Matrix matrix) {
        try {
            final float[] matrixValues;
            if (matrix == null) {
                matrixValues = null;
            } else {
                matrixValues = new float[9];
                matrix.getValues(matrixValues);
            }
            mService.reportVirtualDisplayGeometryAsync(mClient, childDisplayId, matrixValues);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * An internal API that returns if the current display has a transformation matrix to apply.
     *
     * @return {@code true} if {@link Matrix} to convert virtual display screen coordinates to
     * the host screen coordinates is set.
     * @hide
     */
    public boolean hasVirtualDisplayToScreenMatrix() {
        synchronized (mH) {
            return mVirtualDisplayToScreenMatrix != null;
        }
    }

    /**
     * Force switch to the last used input method and subtype. If the last input method didn't have
     * any subtypes, the framework will simply switch to the last input method with no subtype
+30 −1
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@ package com.android.internal.inputmethod;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Matrix;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -202,11 +204,28 @@ public final class InputBindResult implements Parcelable {
     */
    public final int sequence;

    @Nullable
    private final float[] mVirtualDisplayToScreenMatrixValues;

    /**
     * {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}.
     */
    public final boolean isInputMethodSuppressingSpellChecker;

    /**
     * @return {@link Matrix} that corresponds to {@link #mVirtualDisplayToScreenMatrixValues}.
     *         {@code null} if {@link #mVirtualDisplayToScreenMatrixValues} is {@code null}.
     */
    @Nullable
    public Matrix getVirtualDisplayToScreenMatrix() {
        if (mVirtualDisplayToScreenMatrixValues == null) {
            return null;
        }
        final Matrix matrix = new Matrix();
        matrix.setValues(mVirtualDisplayToScreenMatrixValues);
        return matrix;
    }

    /**
     * Creates a new instance of {@link InputBindResult}.
     *
@@ -225,6 +244,7 @@ public final class InputBindResult implements Parcelable {
    public InputBindResult(@ResultCode int result,
            IInputMethodSession method, SparseArray<IInputMethodSession> accessibilitySessions,
            InputChannel channel, String id, int sequence,
            @Nullable Matrix virtualDisplayToScreenMatrix,
            boolean isInputMethodSuppressingSpellChecker) {
        this.result = result;
        this.method = method;
@@ -232,6 +252,12 @@ public final class InputBindResult implements Parcelable {
        this.channel = channel;
        this.id = id;
        this.sequence = sequence;
        if (virtualDisplayToScreenMatrix == null) {
            mVirtualDisplayToScreenMatrixValues = null;
        } else {
            mVirtualDisplayToScreenMatrixValues = new float[9];
            virtualDisplayToScreenMatrix.getValues(mVirtualDisplayToScreenMatrixValues);
        }
        this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
    }

@@ -258,6 +284,7 @@ public final class InputBindResult implements Parcelable {
        }
        id = source.readString();
        sequence = source.readInt();
        mVirtualDisplayToScreenMatrixValues = source.createFloatArray();
        isInputMethodSuppressingSpellChecker = source.readBoolean();
    }

@@ -268,6 +295,7 @@ public final class InputBindResult implements Parcelable {
    public String toString() {
        return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
                + " sequence=" + sequence
                + " virtualDisplayToScreenMatrix=" + getVirtualDisplayToScreenMatrix()
                + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
                + "}";
    }
@@ -299,6 +327,7 @@ public final class InputBindResult implements Parcelable {
        }
        dest.writeString(id);
        dest.writeInt(sequence);
        dest.writeFloatArray(mVirtualDisplayToScreenMatrixValues);
        dest.writeBoolean(isInputMethodSuppressingSpellChecker);
    }

@@ -366,7 +395,7 @@ public final class InputBindResult implements Parcelable {
    }

    private static InputBindResult error(@ResultCode int result) {
        return new InputBindResult(result, null, null, null, null, -1, false);
        return new InputBindResult(result, null, null, null, null, -1, null, false);
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -987,7 +987,8 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
            Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
            return false;
        }
        if (mParentInputMethodManager.getDisplayId() != imeDisplayId) {
        if (mParentInputMethodManager.getDisplayId() != imeDisplayId
                && !mParentInputMethodManager.hasVirtualDisplayToScreenMatrix()) {
            // requestCursorUpdates() is not currently supported across displays.
            return false;
        }
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ oneway interface IInputMethodClient {
    void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
    void scheduleStartInputIfNecessary(boolean fullscreen);
    void reportFullscreenMode(boolean fullscreen);
    void updateVirtualDisplayToScreenMatrix(int bindSequence, in float[] matrixValues);
    void setImeTraceEnabled(boolean enabled);
    void throwExceptionFromSystem(String message);
}
+3 −0
Original line number Diff line number Diff line
@@ -69,6 +69,9 @@ interface IInputMethodManager {
    // TODO(Bug 113914148): Consider removing this.
    int getInputMethodWindowVisibleHeight(in IInputMethodClient client);

    oneway void reportVirtualDisplayGeometryAsync(in IInputMethodClient parentClient,
            int childDisplayId, in float[] matrixValues);

    oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
    /** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
    void removeImeSurface();
Loading