Merge "Tell IMS about missing InputConnection methods." into nyc-dev

This commit is contained in:
Yohei Yukawa
2016-03-19 00:36:20 +00:00
committed by Android (Google) Code Review
10 changed files with 403 additions and 59 deletions

View File

@@ -36,6 +36,7 @@ import android.view.InputChannel;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.view.inputmethod.InputMethodSubtype;
@@ -164,9 +165,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
return;
case DO_START_INPUT: {
SomeArgs args = (SomeArgs)msg.obj;
int missingMethods = msg.arg1;
IInputContext inputContext = (IInputContext)args.arg1;
InputConnection ic = inputContext != null
? new InputConnectionWrapper(inputContext) : null;
? new InputConnectionWrapper(inputContext, missingMethods) : null;
EditorInfo info = (EditorInfo)args.arg2;
info.makeCompatible(mTargetSdkVersion);
inputMethod.startInput(ic, info);
@@ -175,9 +177,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
case DO_RESTART_INPUT: {
SomeArgs args = (SomeArgs)msg.obj;
int missingMethods = msg.arg1;
IInputContext inputContext = (IInputContext)args.arg1;
InputConnection ic = inputContext != null
? new InputConnectionWrapper(inputContext) : null;
? new InputConnectionWrapper(inputContext, missingMethods) : null;
EditorInfo info = (EditorInfo)args.arg2;
info.makeCompatible(mTargetSdkVersion);
inputMethod.restartInput(ic, info);
@@ -246,8 +249,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
@Override
public void bindInput(InputBinding binding) {
// This IInputContext is guaranteed to implement all the methods.
final int missingMethodFlags = 0;
InputConnection ic = new InputConnectionWrapper(
IInputContext.Stub.asInterface(binding.getConnectionToken()));
IInputContext.Stub.asInterface(binding.getConnectionToken()), missingMethodFlags);
InputBinding nu = new InputBinding(ic, binding);
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
}
@@ -258,15 +263,19 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
@Override
public void startInput(IInputContext inputContext, EditorInfo attribute) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_START_INPUT,
inputContext, attribute));
public void startInput(IInputContext inputContext,
@InputConnectionInspector.MissingMethodFlags final int missingMethods,
EditorInfo attribute) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_START_INPUT,
missingMethods, inputContext, attribute));
}
@Override
public void restartInput(IInputContext inputContext, EditorInfo attribute) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_RESTART_INPUT,
inputContext, attribute));
public void restartInput(IInputContext inputContext,
@InputConnectionInspector.MissingMethodFlags final int missingMethods,
EditorInfo attribute) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_RESTART_INPUT,
missingMethods, inputContext, attribute));
}
@Override

View File

@@ -28,10 +28,24 @@ import android.view.KeyEvent;
* cursor, committing text to the text box, and sending raw key events
* to the application.
*
* <p>Applications should never directly implement this interface, but
* instead subclass from {@link BaseInputConnection}. This will ensure
* that the application does not break when new methods are added to
* the interface.</p>
* <p>Starting from API Level {@link android.os.Build.VERSION_CODES#N},
* the system can deal with the situation where the application directly
* implements this class but one or more of the following methods are
* not implemented.</p>
* <ul>
* <li>{@link #getSelectedText(int)}, which was introduced in
* {@link android.os.Build.VERSION_CODES#GINGERBREAD}.</li>
* <li>{@link #setComposingRegion(int, int)}, which was introduced
* in {@link android.os.Build.VERSION_CODES#GINGERBREAD}.</li>
* <li>{@link #commitCorrection(CorrectionInfo)}, which was introduced
* in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.</li>
* <li>{@link #requestCursorUpdates(int)}, which was introduced in
* {@link android.os.Build.VERSION_CODES#LOLLIPOP}.</li>
* <li>{@link #deleteSurroundingTextInCodePoints(int, int)}}, which
* was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
* <li>{@link #getHandler()}}, which was introduced in
* {@link android.os.Build.VERSION_CODES#N}.</li>
* </ul>
*
* <h3>Implementing an IME or an editor</h3>
* <p>Text input is the result of the synergy of two essential components:
@@ -224,7 +238,9 @@ public interface InputConnection {
* @param flags Supplies additional options controlling how the text is
* returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
* @return the text that is currently selected, if any, or null if
* no text is selected.
* no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
* later, returns false when the target application does not implement
* this method.
*/
public CharSequence getSelectedText(int flags);
@@ -371,7 +387,8 @@ public interface InputConnection {
* If this is greater than the number of existing characters between the cursor and
* the end of the text, then this method does not fail but deletes all the characters in
* that range.
* @return true on success, false if the input connection is no longer valid.
* @return true on success, false if the input connection is no longer valid. Returns
* {@code false} when the target application does not implement this method.
*/
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
@@ -461,7 +478,8 @@ public interface InputConnection {
* @param start the position in the text at which the composing region begins
* @param end the position in the text at which the composing region ends
* @return true on success, false if the input connection is no longer
* valid.
* valid. In {@link android.os.Build.VERSION_CODES#N} and later, false is returned when the
* target application does not implement this method.
*/
public boolean setComposingRegion(int start, int end);
@@ -573,6 +591,8 @@ public interface InputConnection {
*
* @param correctionInfo Detailed information about the correction.
* @return true on success, false if the input connection is no longer valid.
* In {@link android.os.Build.VERSION_CODES#N} and later, returns false
* when the target application does not implement this method.
*/
public boolean commitCorrection(CorrectionInfo correctionInfo);
@@ -785,6 +805,8 @@ public interface InputConnection {
* @return {@code true} if the request is scheduled. {@code false} to indicate that when the
* application will not call
* {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}.
* In {@link android.os.Build.VERSION_CODES#N} and later, returns {@code false} also when the
* target application does not implement this method.
*/
public boolean requestCursorUpdates(int cursorUpdateMode);

View File

@@ -0,0 +1,224 @@
/*
* Copyright (C) 2016 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.inputmethod;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* @hide
*/
public final class InputConnectionInspector {
@Retention(SOURCE)
@IntDef({MissingMethodFlags.GET_SELECTED_TEXT,
MissingMethodFlags.SET_COMPOSING_REGION,
MissingMethodFlags.COMMIT_CORRECTION,
MissingMethodFlags.REQUEST_CURSOR_UPDATES,
MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
MissingMethodFlags.GET_HANDLER,
})
public @interface MissingMethodFlags {
/**
* {@link InputConnection#getSelectedText(int)} is available in
* {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
*/
int GET_SELECTED_TEXT = 1 << 0;
/**
* {@link InputConnection#setComposingRegion(int, int)} is available in
* {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
*/
int SET_COMPOSING_REGION = 1 << 1;
/**
* {@link InputConnection#commitCorrection(CorrectionInfo)} is available in
* {@link android.os.Build.VERSION_CODES#HONEYCOMB} and later.
*/
int COMMIT_CORRECTION = 1 << 2;
/**
* {@link InputConnection#requestCursorUpdates(int)} is available in
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
*/
int REQUEST_CURSOR_UPDATES = 1 << 3;
/**
* {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
* {@link android.os.Build.VERSION_CODES#N} and later.
*/
int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 1 << 4;
/**
* {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
* {@link android.os.Build.VERSION_CODES#N} and later.
*/
int GET_HANDLER = 1 << 5;
}
private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
new WeakHashMap<>());
@MissingMethodFlags
public static int getMissingMethodFlags(@Nullable final InputConnection ic) {
if (ic == null) {
return 0;
}
// Optimization for a known class.
if (ic instanceof BaseInputConnection) {
return 0;
}
// Optimization for a known class.
if (ic instanceof InputConnectionWrapper) {
return ((InputConnectionWrapper) ic).getMissingMethodFlags();
}
return getMissingMethodFlagsInternal(ic.getClass());
}
@MissingMethodFlags
public static int getMissingMethodFlagsInternal(@NonNull final Class clazz) {
final Integer cachedFlags = sMissingMethodsMap.get(clazz);
if (cachedFlags != null) {
return cachedFlags;
}
int flags = 0;
if (!hasGetSelectedText(clazz)) {
flags |= MissingMethodFlags.GET_SELECTED_TEXT;
}
if (!hasSetComposingRegion(clazz)) {
flags |= MissingMethodFlags.SET_COMPOSING_REGION;
}
if (!hasCommitCorrection(clazz)) {
flags |= MissingMethodFlags.COMMIT_CORRECTION;
}
if (!hasRequestCursorUpdate(clazz)) {
flags |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
}
if (!hasDeleteSurroundingTextInCodePoints(clazz)) {
flags |= MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS;
}
if (!hasGetHandler(clazz)) {
flags |= MissingMethodFlags.GET_HANDLER;
}
sMissingMethodsMap.put(clazz, flags);
return flags;
}
private static boolean hasGetSelectedText(@NonNull final Class clazz) {
try {
final Method method = clazz.getMethod("getSelectedText", int.class);
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
return false;
}
}
private static boolean hasSetComposingRegion(@NonNull final Class clazz) {
try {
final Method method = clazz.getMethod("setComposingRegion", int.class, int.class);
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
return false;
}
}
private static boolean hasCommitCorrection(@NonNull final Class clazz) {
try {
final Method method = clazz.getMethod("commitCorrection", CorrectionInfo.class);
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
return false;
}
}
private static boolean hasRequestCursorUpdate(@NonNull final Class clazz) {
try {
final Method method = clazz.getMethod("requestCursorUpdates", int.class);
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
return false;
}
}
private static boolean hasDeleteSurroundingTextInCodePoints(@NonNull final Class clazz) {
try {
final Method method = clazz.getMethod("deleteSurroundingTextInCodePoints", int.class,
int.class);
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
return false;
}
}
private static boolean hasGetHandler(@NonNull final Class clazz) {
try {
final Method method = clazz.getMethod("getHandler");
return !Modifier.isAbstract(method.getModifiers());
} catch (NoSuchMethodException e) {
return false;
}
}
public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
final StringBuilder sb = new StringBuilder();
boolean isEmpty = true;
if ((flags & MissingMethodFlags.GET_SELECTED_TEXT) != 0) {
sb.append("getSelectedText(int)");
isEmpty = false;
}
if ((flags & MissingMethodFlags.SET_COMPOSING_REGION) != 0) {
if (!isEmpty) {
sb.append(",");
}
sb.append("setComposingRegion(int, int)");
isEmpty = false;
}
if ((flags & MissingMethodFlags.COMMIT_CORRECTION) != 0) {
if (!isEmpty) {
sb.append(",");
}
sb.append("commitCorrection(CorrectionInfo)");
isEmpty = false;
}
if ((flags & MissingMethodFlags.REQUEST_CURSOR_UPDATES) != 0) {
if (!isEmpty) {
sb.append(",");
}
sb.append("requestCursorUpdate(int)");
isEmpty = false;
}
if ((flags & MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS) != 0) {
if (!isEmpty) {
sb.append(",");
}
sb.append("deleteSurroundingTextInCodePoints(int, int)");
isEmpty = false;
}
if ((flags & MissingMethodFlags.GET_HANDLER) != 0) {
if (!isEmpty) {
sb.append(",");
}
sb.append("getHandler()");
}
return sb.toString();
}
}

View File

@@ -26,6 +26,8 @@ import android.view.KeyEvent;
public class InputConnectionWrapper implements InputConnection {
private InputConnection mTarget;
final boolean mMutable;
@InputConnectionInspector.MissingMethodFlags
private int mMissingMethodFlags;
/**
* Initializes a wrapper.
@@ -40,6 +42,7 @@ public class InputConnectionWrapper implements InputConnection {
public InputConnectionWrapper(InputConnection target, boolean mutable) {
mMutable = mutable;
mTarget = target;
mMissingMethodFlags = InputConnectionInspector.getMissingMethodFlags(target);
}
/**
@@ -56,6 +59,15 @@ public class InputConnectionWrapper implements InputConnection {
throw new SecurityException("not mutable");
}
mTarget = target;
mMissingMethodFlags = InputConnectionInspector.getMissingMethodFlags(target);
}
/**
* @hide
*/
@InputConnectionInspector.MissingMethodFlags
public int getMissingMethodFlags() {
return mMissingMethodFlags;
}
/**

View File

@@ -1224,6 +1224,7 @@ public final class InputMethodManager {
notifyInputConnectionFinished();
mServedInputConnection = ic;
ControlledInputConnectionWrapper servedContext;
final int missingMethodFlags;
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
mCursorSelEnd = tba.initialSelEnd;
@@ -1231,11 +1232,20 @@ public final class InputMethodManager {
mCursorCandEnd = -1;
mCursorRect.setEmpty();
mCursorAnchorInfo = null;
final Handler icHandler = ic.getHandler();
final Handler icHandler;
missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
!= 0) {
// InputConnection#getHandler() is not implemented.
icHandler = null;
} else {
icHandler = ic.getHandler();
}
servedContext = new ControlledInputConnectionWrapper(
icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
} else {
servedContext = null;
missingMethodFlags = 0;
}
if (mServedInputConnectionWrapper != null) {
mServedInputConnectionWrapper.deactivate();
@@ -1248,7 +1258,7 @@ public final class InputMethodManager {
+ Integer.toHexString(controlFlags));
final InputBindResult res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
windowFlags, tba, servedContext);
windowFlags, tba, servedContext, missingMethodFlags);
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
if (res != null) {
if (res.id != null) {
@@ -1476,7 +1486,7 @@ public final class InputMethodManager {
mService.startInputOrWindowGainedFocus(
InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
null);
null, 0 /* missingMethodFlags */);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -38,9 +38,9 @@ oneway interface IInputMethod {
void unbindInput();
void startInput(in IInputContext inputContext, in EditorInfo attribute);
void startInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute);
void restartInput(in IInputContext inputContext, in EditorInfo attribute);
void restartInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute);
void createSession(in InputChannel channel, IInputSessionCallback callback);

View File

@@ -57,7 +57,8 @@ interface IInputMethodManager {
/* @InputMethodClient.StartInputReason */ int startInputReason,
in IInputMethodClient client, in IBinder windowToken, int controlFlags,
int softInputMode, int windowFlags, in EditorInfo attribute,
IInputContext inputContext);
IInputContext inputContext,
/* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags);
void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode);

View File

@@ -27,11 +27,15 @@ import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
public class InputConnectionWrapper implements InputConnection {
private static final int MAX_WAIT_TIME_MILLIS = 2000;
private final IInputContext mIInputContext;
@MissingMethodFlags
private final int mMissingMethods;
static class InputContextCallback extends IInputContextCallback.Stub {
private static final String TAG = "InputConnectionWrapper.ICC";
public int mSeq;
@@ -191,8 +195,10 @@ public class InputConnectionWrapper implements InputConnection {
}
}
public InputConnectionWrapper(IInputContext inputContext) {
public InputConnectionWrapper(IInputContext inputContext,
@MissingMethodFlags final int missingMethods) {
mIInputContext = inputContext;
mMissingMethods = missingMethods;
}
public CharSequence getTextAfterCursor(int length, int flags) {
@@ -230,8 +236,12 @@ public class InputConnectionWrapper implements InputConnection {
}
return value;
}
public CharSequence getSelectedText(int flags) {
if (isMethodMissing(MissingMethodFlags.GET_SELECTED_TEXT)) {
// This method is not implemented.
return null;
}
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
@@ -295,6 +305,10 @@ public class InputConnectionWrapper implements InputConnection {
}
public boolean commitCompletion(CompletionInfo text) {
if (isMethodMissing(MissingMethodFlags.COMMIT_CORRECTION)) {
// This method is not implemented.
return false;
}
try {
mIInputContext.commitCompletion(text);
return true;
@@ -340,6 +354,10 @@ public class InputConnectionWrapper implements InputConnection {
}
public boolean setComposingRegion(int start, int end) {
if (isMethodMissing(MissingMethodFlags.SET_COMPOSING_REGION)) {
// This method is not implemented.
return false;
}
try {
mIInputContext.setComposingRegion(start, end);
return true;
@@ -412,6 +430,10 @@ public class InputConnectionWrapper implements InputConnection {
}
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
if (isMethodMissing(MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS)) {
// This method is not implemented.
return false;
}
try {
mIInputContext.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
return true;
@@ -440,6 +462,10 @@ public class InputConnectionWrapper implements InputConnection {
public boolean requestCursorUpdates(int cursorUpdateMode) {
boolean result = false;
if (isMethodMissing(MissingMethodFlags.REQUEST_CURSOR_UPDATES)) {
// This method is not implemented.
return false;
}
try {
InputContextCallback callback = InputContextCallback.getInstance();
mIInputContext.requestUpdateCursorAnchorInfo(cursorUpdateMode, callback.mSeq, callback);
@@ -460,4 +486,16 @@ public class InputConnectionWrapper implements InputConnection {
// Nothing should happen when called from input method.
return null;
}
private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
return (mMissingMethods & methodFlag) == methodFlag;
}
@Override
public String toString() {
return "InputConnectionWrapper{idHash=#"
+ Integer.toHexString(System.identityHashCode(this))
+ " mMissingMethods="
+ InputConnectionInspector.getMissingMethodFlagsAsString(mMissingMethods) + "}";
}
}

View File

@@ -112,6 +112,7 @@ import android.view.WindowManager;
import android.view.WindowManagerInternal;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
@@ -326,6 +327,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
*/
IInputContext mCurInputContext;
/**
* The missing method flags for the input context last provided by the current client.
*
* @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
*/
int mCurInputContextMissingMethods;
/**
* The attributes last provided by the current client.
*/
@@ -1289,11 +1297,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
final SessionState session = mCurClient.curSession;
if (initial) {
executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
MSG_START_INPUT, session, mCurInputContext, mCurAttribute));
executeOrSendMessage(session.method, mCaller.obtainMessageIOOO(
MSG_START_INPUT, mCurInputContextMissingMethods, session, mCurInputContext,
mCurAttribute));
} else {
executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
executeOrSendMessage(session.method, mCaller.obtainMessageIOOO(
MSG_RESTART_INPUT, mCurInputContextMissingMethods, session, mCurInputContext,
mCurAttribute));
}
if (mShowRequested) {
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
@@ -1306,7 +1316,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
InputBindResult startInputLocked(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
IInputMethodClient client, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
EditorInfo attribute,
int controlFlags) {
// If no method is currently selected, do nothing.
if (mCurMethodId == null) {
@@ -1333,10 +1345,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} catch (RemoteException e) {
}
return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
controlFlags);
}
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
@NonNull EditorInfo attribute, int controlFlags) {
// If no method is currently selected, do nothing.
if (mCurMethodId == null) {
@@ -1371,6 +1385,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurSeq <= 0) mCurSeq = 1;
mCurClient = cs;
mCurInputContext = inputContext;
mCurInputContextMissingMethods = missingMethods;
mCurAttribute = attribute;
// Check if the input method is changing.
@@ -1459,8 +1474,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private InputBindResult startInput(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
int controlFlags) {
IInputMethodClient client, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
EditorInfo attribute, int controlFlags) {
if (!calledFromValidUser()) {
return null;
}
@@ -1470,13 +1486,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ InputMethodClient.getStartInputReason(startInputReason)
+ " client = " + client.asBinder()
+ " inputContext=" + inputContext
+ " missingMethods="
+ InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
+ " attribute=" + attribute
+ " controlFlags=#" + Integer.toHexString(controlFlags));
}
final long ident = Binder.clearCallingIdentity();
try {
return startInputLocked(startInputReason, client, inputContext, attribute,
controlFlags);
return startInputLocked(startInputReason, client, inputContext, missingMethods,
attribute, controlFlags);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2190,19 +2208,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public InputBindResult startInputOrWindowGainedFocus(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext) {
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods) {
if (windowToken != null) {
return windowGainedFocus(startInputReason, client, windowToken, controlFlags,
softInputMode, windowFlags, attribute, inputContext);
softInputMode, windowFlags, attribute, inputContext, missingMethods);
} else {
return startInput(startInputReason, client, inputContext, attribute, controlFlags);
return startInput(startInputReason, client, inputContext, missingMethods, attribute,
controlFlags);
}
}
private InputBindResult windowGainedFocus(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext) {
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods) {
// Needs to check the validity before clearing calling identity
final boolean calledFromValidUser = calledFromValidUser();
InputBindResult res = null;
@@ -2213,6 +2234,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ InputMethodClient.getStartInputReason(startInputReason)
+ " client=" + client.asBinder()
+ " inputContext=" + inputContext
+ " missingMethods="
+ InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
+ " attribute=" + attribute
+ " controlFlags=#" + Integer.toHexString(controlFlags)
+ " softInputMode=#" + Integer.toHexString(softInputMode)
@@ -2250,8 +2273,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ " attribute=" + attribute + ", token = " + windowToken);
if (attribute != null) {
return startInputUncheckedLocked(cs, inputContext, attribute,
controlFlags);
return startInputUncheckedLocked(cs, inputContext, missingMethods,
attribute, controlFlags);
}
return null;
}
@@ -2300,8 +2323,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// is more room for the target window + IME.
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
controlFlags);
res = startInputUncheckedLocked(cs, inputContext,
missingMethods, attribute, controlFlags);
didStart = true;
}
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2326,8 +2349,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
controlFlags);
res = startInputUncheckedLocked(cs, inputContext,
missingMethods, attribute, controlFlags);
didStart = true;
}
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2336,8 +2359,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
controlFlags);
res = startInputUncheckedLocked(cs, inputContext, missingMethods,
attribute, controlFlags);
didStart = true;
}
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
@@ -2345,7 +2368,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (!didStart && attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
controlFlags);
}
}
@@ -2807,28 +2830,32 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
// ---------------------------------------------------------
case MSG_START_INPUT:
args = (SomeArgs)msg.obj;
case MSG_START_INPUT: {
int missingMethods = msg.arg1;
args = (SomeArgs) msg.obj;
try {
SessionState session = (SessionState)args.arg1;
SessionState session = (SessionState) args.arg1;
setEnabledSessionInMainThread(session);
session.method.startInput((IInputContext)args.arg2,
(EditorInfo)args.arg3);
session.method.startInput((IInputContext) args.arg2, missingMethods,
(EditorInfo) args.arg3);
} catch (RemoteException e) {
}
args.recycle();
return true;
case MSG_RESTART_INPUT:
args = (SomeArgs)msg.obj;
}
case MSG_RESTART_INPUT: {
int missingMethods = msg.arg1;
args = (SomeArgs) msg.obj;
try {
SessionState session = (SessionState)args.arg1;
SessionState session = (SessionState) args.arg1;
setEnabledSessionInMainThread(session);
session.method.restartInput((IInputContext)args.arg2,
(EditorInfo)args.arg3);
session.method.restartInput((IInputContext) args.arg2, missingMethods,
(EditorInfo) args.arg3);
} catch (RemoteException e) {
}
args.recycle();
return true;
}
// ---------------------------------------------------------

View File

@@ -222,7 +222,8 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
public InputBindResult startInputOrWindowGainedFocus(
/* @InputMethodClient.StartInputReason */ int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext)
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags)
throws RemoteException {
// TODO Auto-generated method stub
return null;