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

Commit e77386e8 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Introduce InputConnection#reportLanguageHint()

The goal of this CL is to introduce a way for IMEs to tell
applications about what languages are likely to be used in the text to
be committed, for IMEs that support dynamic language switching
(especially without relying on InputMethodSubtype).

It is already obvious that InputMethodSubtype is not working well for
this use case.  We need is a simple, easy, and back-portable way that
can be widely accepted by the ecosystem.

Bug: 7031513
Test: atest CtsInputMethodTestCases
Change-Id: Ie86edafd1ed68b58f702116f561fc448fdbb57a8
parent 3bc6f794
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -49191,6 +49191,7 @@ package android.view.inputmethod {
    method public abstract boolean performEditorAction(int);
    method public abstract boolean performEditorAction(int);
    method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
    method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
    method public abstract boolean reportFullscreenMode(boolean);
    method public abstract boolean reportFullscreenMode(boolean);
    method public default void reportLanguageHint(android.os.LocaleList);
    method public abstract boolean requestCursorUpdates(int);
    method public abstract boolean requestCursorUpdates(int);
    method public abstract boolean sendKeyEvent(android.view.KeyEvent);
    method public abstract boolean sendKeyEvent(android.view.KeyEvent);
    method public abstract boolean setComposingRegion(int, int);
    method public abstract boolean setComposingRegion(int, int);
+34 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.os.LocaleList;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.KeyEvent;


@@ -898,4 +899,37 @@ public interface InputConnection {
     */
     */
    boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
    boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
            @Nullable Bundle opts);
            @Nullable Bundle opts);

    /**
     * Called by the input method to tell a hint about the locales of text to be committed.
     *
     * <p>This is just a hint for editor authors (and the system) to choose better options when
     * they have to disambiguate languages, like editor authors can do for input methods with
     * {@link EditorInfo#hintLocales}.</p>
     *
     * <p>The language hint provided by this callback should have higher priority than
     * {@link InputMethodSubtype#getLanguageTag()}, which cannot be updated dynamically.</p>
     *
     * <p>Note that in general it is discouraged for input method to specify
     * {@link android.text.style.LocaleSpan} when inputting text, mainly because of application
     * compatibility concerns.</p>
     * <ul>
     *     <li>When an existing text that already has {@link android.text.style.LocaleSpan} is being
     *     modified by both the input method and application, there is no reliable and easy way to
     *     keep track of who modified {@link android.text.style.LocaleSpan}. For instance, if the
     *     text was updated by JavaScript, it it highly likely that span information is completely
     *     removed, while some input method attempts to preserve spans if possible.</li>
     *     <li>There is no clear semantics regarding whether {@link android.text.style.LocaleSpan}
     *     means a weak (ignorable) hint or a strong hint. This becomes more problematic when
     *     multiple {@link android.text.style.LocaleSpan} instances are specified to the same
     *     text region, especially when those spans are conflicting.</li>
     * </ul>
     * @param languageHint list of languages sorted by the priority and/or probability
     */
    default void reportLanguageHint(@NonNull LocaleList languageHint) {
        // Intentionally empty.
        //
        // We need to have *some* default implementation for the source compatibility.
        // See Bug 72127682 for details.
    }
}
}
+11 −0
Original line number Original line Diff line number Diff line
@@ -16,8 +16,10 @@


package android.view.inputmethod;
package android.view.inputmethod;


import android.annotation.NonNull;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.os.LocaleList;
import android.view.KeyEvent;
import android.view.KeyEvent;


/**
/**
@@ -303,4 +305,13 @@ public class InputConnectionWrapper implements InputConnection {
    public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
    public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
        return mTarget.commitContent(inputContentInfo, flags, opts);
        return mTarget.commitContent(inputContentInfo, flags, opts);
    }
    }

    /**
     * {@inheritDoc}
     * @throws NullPointerException if the target is {@code null}.
     */
    @Override
    public void reportLanguageHint(@NonNull LocaleList languageHint) {
        mTarget.reportLanguageHint(languageHint);
    }
}
}
+6 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Debug;
import android.os.Debug;
import android.os.Handler;
import android.os.Handler;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.os.StrictMode;
import android.os.StrictMode;
@@ -6026,6 +6027,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
        public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
            return getTarget().commitContent(inputContentInfo, flags, opts);
            return getTarget().commitContent(inputContentInfo, flags, opts);
        }
        }

        @Override
        public void reportLanguageHint(@NonNull LocaleList languageHint) {
            getTarget().reportLanguageHint(languageHint);
        }
    }
    }


    /**
    /**
+16 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.os.LocaleList;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.RemoteException;
import android.os.RemoteException;
@@ -64,6 +65,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
    private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
    private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
    private static final int DO_CLOSE_CONNECTION = 150;
    private static final int DO_CLOSE_CONNECTION = 150;
    private static final int DO_COMMIT_CONTENT = 160;
    private static final int DO_COMMIT_CONTENT = 160;
    private static final int DO_REPORT_LANGUAGE_HINT = 170;


    @GuardedBy("mLock")
    @GuardedBy("mLock")
    @Nullable
    @Nullable
@@ -217,6 +219,10 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                callback));
                callback));
    }
    }


    public void reportLanguageHint(@NonNull LocaleList languageHint) {
        dispatchMessage(obtainMessageO(DO_REPORT_LANGUAGE_HINT, languageHint));
    }

    void dispatchMessage(Message msg) {
    void dispatchMessage(Message msg) {
        // If we are calling this from the main thread, then we can call
        // If we are calling this from the main thread, then we can call
        // right through.  Otherwise, we need to send the message to the
        // right through.  Otherwise, we need to send the message to the
@@ -577,6 +583,16 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
                }
                }
                return;
                return;
            }
            }
            case DO_REPORT_LANGUAGE_HINT: {
                final LocaleList languageHint = (LocaleList) msg.obj;
                final InputConnection ic = getInputConnection();
                if (ic == null || !isActive()) {
                    Log.w(TAG, "reportLanguageHint on inactive InputConnection");
                    return;
                }
                ic.reportLanguageHint(languageHint);
                return;
            }
        }
        }
        Log.w(TAG, "Unhandled message code: " + msg.what);
        Log.w(TAG, "Unhandled message code: " + msg.what);
    }
    }
Loading