Merge "Track event flow to IMMS#setImeWindowStatus"
This commit is contained in:
@@ -166,8 +166,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
||||
final SomeArgs args = (SomeArgs) msg.obj;
|
||||
final int missingMethods = msg.arg1;
|
||||
final boolean restarting = msg.arg2 != 0;
|
||||
final IInputContext inputContext = (IInputContext) args.arg1;
|
||||
final EditorInfo info = (EditorInfo) args.arg2;
|
||||
final IBinder startInputToken = (IBinder) args.arg1;
|
||||
final IInputContext inputContext = (IInputContext) args.arg2;
|
||||
final EditorInfo info = (EditorInfo) args.arg3;
|
||||
final InputConnection ic = inputContext != null
|
||||
? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null;
|
||||
info.makeCompatible(mTargetSdkVersion);
|
||||
@@ -176,6 +177,8 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
||||
} else {
|
||||
inputMethod.startInput(ic, info);
|
||||
}
|
||||
inputMethod.dispatchStartInputWithToken(ic, info, true /* initial */,
|
||||
startInputToken);
|
||||
args.recycle();
|
||||
return;
|
||||
}
|
||||
@@ -255,11 +258,11 @@ class IInputMethodWrapper extends IInputMethod.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startInput(IInputContext inputContext,
|
||||
public void startInput(IBinder startInputToken, IInputContext inputContext,
|
||||
@InputConnectionInspector.MissingMethodFlags final int missingMethods,
|
||||
EditorInfo attribute, boolean restarting) {
|
||||
mCaller.executeOrSendMessage(mCaller.obtainMessageIIOO(DO_START_INPUT,
|
||||
missingMethods, restarting ? 1 : 0, inputContext, attribute));
|
||||
mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOO(DO_START_INPUT,
|
||||
missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.annotation.DrawableRes;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
@@ -291,7 +292,20 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
boolean mCandidatesViewStarted;
|
||||
InputConnection mStartedInputConnection;
|
||||
EditorInfo mInputEditorInfo;
|
||||
|
||||
|
||||
/**
|
||||
* A token to keep tracking the last IPC that triggered
|
||||
* {@link #doStartInput(InputConnection, EditorInfo, boolean)}. If
|
||||
* {@link #doStartInput(InputConnection, EditorInfo, boolean)} was not caused by IPCs from
|
||||
* {@link com.android.server.InputMethodManagerService}, this needs to remain unchanged.
|
||||
*
|
||||
* <p>Some IPCs to {@link com.android.server.InputMethodManagerService} require this token to
|
||||
* disentangle event flows for various purposes such as better window animation and providing
|
||||
* fine-grained debugging information.</p>
|
||||
*/
|
||||
@Nullable
|
||||
private IBinder mStartInputToken;
|
||||
|
||||
int mShowInputFlags;
|
||||
boolean mShowInputRequested;
|
||||
boolean mLastShowInputRequested;
|
||||
@@ -415,6 +429,23 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
doStartInput(ic, attribute, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
|
||||
@NonNull EditorInfo editorInfo, boolean restarting,
|
||||
@NonNull IBinder startInputToken) {
|
||||
mStartInputToken = startInputToken;
|
||||
|
||||
// This needs to be dispatched to interface methods rather than doStartInput().
|
||||
// Otherwise IME developers who have overridden those interface methods will lose
|
||||
// notifications.
|
||||
super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting,
|
||||
startInputToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request by the system to hide the soft input area.
|
||||
*/
|
||||
@@ -454,8 +485,8 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
clearInsetOfPreviousIme();
|
||||
// If user uses hard keyboard, IME button should always be shown.
|
||||
boolean showing = isInputViewShown();
|
||||
mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
|
||||
mBackDisposition);
|
||||
mImm.setImeWindowStatus(mToken, mStartInputToken,
|
||||
IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
|
||||
if (resultReceiver != null) {
|
||||
resultReceiver.send(wasVis != isInputViewShown()
|
||||
? InputMethodManager.RESULT_SHOWN
|
||||
@@ -926,8 +957,8 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
}
|
||||
// If user uses hard keyboard, IME button should always be shown.
|
||||
boolean showing = onEvaluateInputViewShown();
|
||||
mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
|
||||
mBackDisposition);
|
||||
mImm.setImeWindowStatus(mToken, mStartInputToken,
|
||||
IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1653,7 +1684,8 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
|
||||
final int nextImeWindowStatus = IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0);
|
||||
if (previousImeWindowStatus != nextImeWindowStatus) {
|
||||
mImm.setImeWindowStatus(mToken, nextImeWindowStatus, mBackDisposition);
|
||||
mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus,
|
||||
mBackDisposition);
|
||||
}
|
||||
if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
|
||||
if (DEBUG) Log.v(TAG, "showWindow: showing!");
|
||||
@@ -1678,7 +1710,7 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
}
|
||||
|
||||
private void doHideWindow() {
|
||||
mImm.setImeWindowStatus(mToken, 0, mBackDisposition);
|
||||
mImm.setImeWindowStatus(mToken, mStartInputToken, 0, mBackDisposition);
|
||||
hideWindow();
|
||||
}
|
||||
|
||||
@@ -2643,7 +2675,8 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
p.println(" mInputStarted=" + mInputStarted
|
||||
+ " mInputViewStarted=" + mInputViewStarted
|
||||
+ " mCandidatesViewStarted=" + mCandidatesViewStarted);
|
||||
|
||||
p.println(" mStartInputToken=" + mStartInputToken);
|
||||
|
||||
if (mInputEditorInfo != null) {
|
||||
p.println(" mInputEditorInfo:");
|
||||
mInputEditorInfo.dump(p, " ");
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.view.inputmethod;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
@@ -147,6 +149,44 @@ public interface InputMethod {
|
||||
*/
|
||||
public void restartInput(InputConnection inputConnection, EditorInfo attribute);
|
||||
|
||||
/**
|
||||
* This method is called when {@code {@link #startInput(InputConnection, EditorInfo)} or
|
||||
* {@code {@link #restartInput(InputConnection, EditorInfo)} needs to be dispatched.
|
||||
*
|
||||
* <p>Note: This method is hidden because the {@code startInputToken} that this method is
|
||||
* dealing with is one of internal details, which should not be exposed to the IME developers.
|
||||
* If you override this method, you are responsible for not breaking existing IMEs that expect
|
||||
* {@link #startInput(InputConnection, EditorInfo)} to be still called back.</p>
|
||||
*
|
||||
* @param inputConnection optional specific input connection for communicating with the text
|
||||
* box; if {@code null}, you should use the generic bound input
|
||||
* connection
|
||||
* @param editorInfo information about the text box (typically, an EditText) that requests input
|
||||
* @param restarting {@code false} if this corresponds to
|
||||
* {@link #startInput(InputConnection, EditorInfo)}. Otherwise this
|
||||
* corresponds to {@link #restartInput(InputConnection, EditorInfo)}.
|
||||
* @param startInputToken a token that identifies a logical session that starts with this method
|
||||
* call. Some internal IPCs such as {@link
|
||||
* InputMethodManager#setImeWindowStatus(IBinder, IBinder, int, int)}
|
||||
* require this token to work, and you have to keep the token alive until
|
||||
* the next {@link #startInput(InputConnection, EditorInfo, IBinder)} as
|
||||
* long as your implementation of {@link InputMethod} relies on such
|
||||
* IPCs
|
||||
* @see #startInput(InputConnection, EditorInfo)
|
||||
* @see #restartInput(InputConnection, EditorInfo)
|
||||
* @see EditorInfo
|
||||
* @hide
|
||||
*/
|
||||
default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
|
||||
@NonNull EditorInfo editorInfo, boolean restarting,
|
||||
@NonNull IBinder startInputToken) {
|
||||
if (restarting) {
|
||||
restartInput(inputConnection, editorInfo);
|
||||
} else {
|
||||
startInput(inputConnection, editorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link InputMethodSession} that can be handed to client
|
||||
* applications for interacting with the input method. You can later
|
||||
|
||||
@@ -739,9 +739,10 @@ public final class InputMethodManager {
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) {
|
||||
public void setImeWindowStatus(IBinder imeToken, IBinder startInputToken, int vis,
|
||||
int backDisposition) {
|
||||
try {
|
||||
mService.setImeWindowStatus(imeToken, vis, backDisposition);
|
||||
mService.setImeWindowStatus(imeToken, startInputToken, vis, backDisposition);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
@@ -173,6 +173,16 @@ public class HandlerCaller {
|
||||
return mH.obtainMessage(what, arg1, arg2, args);
|
||||
}
|
||||
|
||||
public Message obtainMessageIIOOOO(int what, int arg1, int arg2, Object arg3, Object arg4,
|
||||
Object arg5, Object arg6) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = arg3;
|
||||
args.arg2 = arg4;
|
||||
args.arg3 = arg5;
|
||||
args.arg4 = arg6;
|
||||
return mH.obtainMessage(what, arg1, arg2, args);
|
||||
}
|
||||
|
||||
public Message obtainMessageOO(int what, Object arg1, Object arg2) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = arg1;
|
||||
|
||||
@@ -38,8 +38,8 @@ oneway interface IInputMethod {
|
||||
|
||||
void unbindInput();
|
||||
|
||||
void startInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute,
|
||||
boolean restarting);
|
||||
void startInput(in IBinder startInputToken, in IInputContext inputContext, int missingMethods,
|
||||
in EditorInfo attribute, boolean restarting);
|
||||
|
||||
void createSession(in InputChannel channel, IInputSessionCallback callback);
|
||||
|
||||
|
||||
@@ -70,7 +70,8 @@ interface IInputMethodManager {
|
||||
void hideMySoftInput(in IBinder token, int flags);
|
||||
void showMySoftInput(in IBinder token, int flags);
|
||||
void updateStatusIcon(in IBinder token, String packageName, int iconId);
|
||||
void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
|
||||
void setImeWindowStatus(in IBinder token, in IBinder startInputToken, int vis,
|
||||
int backDisposition);
|
||||
void registerSuggestionSpansForNotification(in SuggestionSpan[] spans);
|
||||
boolean notifySuggestionPicked(in SuggestionSpan span, String originalString, int index);
|
||||
InputMethodSubtype getCurrentInputMethodSubtype();
|
||||
|
||||
@@ -124,6 +124,7 @@ import android.view.WindowManager;
|
||||
import android.view.WindowManagerInternal;
|
||||
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.InputMethodInfo;
|
||||
@@ -152,6 +153,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* This class provides a system service that manages input methods.
|
||||
@@ -506,6 +508,36 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
@HardKeyboardBehavior
|
||||
private final int mHardKeyboardBehavior;
|
||||
|
||||
/**
|
||||
* Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
|
||||
* internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
|
||||
* will not affect those tasks that are already posted.
|
||||
*
|
||||
* <p>Posting {@link #MSG_START_INPUT} message basically means that
|
||||
* {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
|
||||
* back in the current IME process shortly, which will also affect what the current IME starts
|
||||
* receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
|
||||
* snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
|
||||
* logical input session between the client application and the current IME.</p>
|
||||
*
|
||||
* <p>Be careful to not keep strong references to this object forever, which can prevent
|
||||
* {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
|
||||
* </p>
|
||||
*/
|
||||
private static class StartInputInfo {
|
||||
@NonNull
|
||||
final IBinder mImeToken;
|
||||
@Nullable
|
||||
final IBinder mTargetWindow;
|
||||
|
||||
StartInputInfo(@NonNull IBinder imeToken, @Nullable IBinder targetWindow) {
|
||||
mImeToken = imeToken;
|
||||
mTargetWindow = targetWindow;
|
||||
}
|
||||
}
|
||||
|
||||
private WeakHashMap<IBinder, StartInputInfo> mStartInputMap = new WeakHashMap<>();
|
||||
|
||||
class SettingsObserver extends ContentObserver {
|
||||
int mUserId;
|
||||
boolean mRegistered = false;
|
||||
@@ -1345,10 +1377,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
|
||||
mBoundToMethod = true;
|
||||
}
|
||||
|
||||
final Binder startInputToken = new Binder();
|
||||
final StartInputInfo info = new StartInputInfo(mCurToken, mCurFocusedWindow);
|
||||
mStartInputMap.put(startInputToken, info);
|
||||
|
||||
final SessionState session = mCurClient.curSession;
|
||||
executeOrSendMessage(session.method, mCaller.obtainMessageIIOOO(
|
||||
executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
|
||||
MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
|
||||
session, mCurInputContext, mCurAttribute));
|
||||
startInputToken, session, mCurInputContext, mCurAttribute));
|
||||
if (mShowRequested) {
|
||||
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
|
||||
showCurrentInputLocked(getAppShowFlags(), null);
|
||||
@@ -1816,12 +1853,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
|
||||
public void setImeWindowStatus(IBinder token, IBinder startInputToken, int vis,
|
||||
int backDisposition) {
|
||||
if (startInputToken == null) {
|
||||
throw new InvalidParameterException("startInputToken cannot be null");
|
||||
}
|
||||
|
||||
if (!calledWithValidToken(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mMethodMap) {
|
||||
final StartInputInfo info = mStartInputMap.get(startInputToken);
|
||||
if (info == null) {
|
||||
throw new InvalidParameterException("Unknown startInputToken=" + startInputToken);
|
||||
}
|
||||
mImeWindowVis = vis;
|
||||
mBackDisposition = backDisposition;
|
||||
updateSystemUiLocked(token, vis, backDisposition);
|
||||
@@ -2901,12 +2947,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
final int missingMethods = msg.arg1;
|
||||
final boolean restarting = msg.arg2 != 0;
|
||||
args = (SomeArgs) msg.obj;
|
||||
final SessionState session = (SessionState) args.arg1;
|
||||
final IInputContext inputContext = (IInputContext) args.arg2;
|
||||
final EditorInfo editorInfo = (EditorInfo) args.arg3;
|
||||
final IBinder startInputToken = (IBinder) args.arg1;
|
||||
final SessionState session = (SessionState) args.arg2;
|
||||
final IInputContext inputContext = (IInputContext) args.arg3;
|
||||
final EditorInfo editorInfo = (EditorInfo) args.arg4;
|
||||
try {
|
||||
setEnabledSessionInMainThread(session);
|
||||
session.method.startInput(inputContext, missingMethods, editorInfo, restarting);
|
||||
session.method.startInput(startInputToken, inputContext, missingMethods,
|
||||
editorInfo, restarting);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
args.recycle();
|
||||
|
||||
@@ -135,7 +135,8 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImeWindowStatus(IBinder arg0, int arg1, int arg2) throws RemoteException {
|
||||
public void setImeWindowStatus(IBinder arg0, IBinder arg1, int arg2, int arg3)
|
||||
throws RemoteException {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user