* commit '133dc2d7aecc68990c363c861716b134910a4ced': Fix issue #6048808: sometimes auto-correct is inactive
This commit is contained in:
@ -26,7 +26,6 @@ import com.android.internal.view.IInputMethodSession;
|
|||||||
import com.android.internal.view.InputBindResult;
|
import com.android.internal.view.InputBindResult;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -198,7 +197,31 @@ public final class InputMethodManager {
|
|||||||
|
|
||||||
static final Object mInstanceSync = new Object();
|
static final Object mInstanceSync = new Object();
|
||||||
static InputMethodManager mInstance;
|
static InputMethodManager mInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide Flag for IInputMethodManager.windowGainedFocus: a view in
|
||||||
|
* the window has input focus.
|
||||||
|
*/
|
||||||
|
public static final int CONTROL_WINDOW_VIEW_HAS_FOCUS = 1<<0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide Flag for IInputMethodManager.windowGainedFocus: the focus
|
||||||
|
* is a text editor.
|
||||||
|
*/
|
||||||
|
public static final int CONTROL_WINDOW_IS_TEXT_EDITOR = 1<<1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide Flag for IInputMethodManager.windowGainedFocus: this is the first
|
||||||
|
* time the window has gotten focus.
|
||||||
|
*/
|
||||||
|
public static final int CONTROL_WINDOW_FIRST = 1<<2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide Flag for IInputMethodManager.startInput: this is the first
|
||||||
|
* time the window has gotten focus.
|
||||||
|
*/
|
||||||
|
public static final int CONTROL_START_INITIAL = 1<<8;
|
||||||
|
|
||||||
final IInputMethodManager mService;
|
final IInputMethodManager mService;
|
||||||
final Looper mMainLooper;
|
final Looper mMainLooper;
|
||||||
|
|
||||||
@ -216,7 +239,7 @@ public final class InputMethodManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whenever this client becomes inactive, to know we need to reset
|
* Set whenever this client becomes inactive, to know we need to reset
|
||||||
* state with the IME then next time we receive focus.
|
* state with the IME the next time we receive focus.
|
||||||
*/
|
*/
|
||||||
boolean mHasBeenInactive = true;
|
boolean mHasBeenInactive = true;
|
||||||
|
|
||||||
@ -242,11 +265,6 @@ public final class InputMethodManager {
|
|||||||
* we get around to updating things.
|
* we get around to updating things.
|
||||||
*/
|
*/
|
||||||
View mNextServedView;
|
View mNextServedView;
|
||||||
/**
|
|
||||||
* True if we should restart input in the next served view, even if the
|
|
||||||
* view hasn't actually changed from the current serve view.
|
|
||||||
*/
|
|
||||||
boolean mNextServedNeedsStart;
|
|
||||||
/**
|
/**
|
||||||
* This is set when we are in the process of connecting, to determine
|
* This is set when we are in the process of connecting, to determine
|
||||||
* when we have actually finished.
|
* when we have actually finished.
|
||||||
@ -331,7 +349,7 @@ public final class InputMethodManager {
|
|||||||
mCurId = res.id;
|
mCurId = res.id;
|
||||||
mBindSequence = res.sequence;
|
mBindSequence = res.sequence;
|
||||||
}
|
}
|
||||||
startInputInner();
|
startInputInner(null, 0, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case MSG_UNBIND: {
|
case MSG_UNBIND: {
|
||||||
@ -362,7 +380,7 @@ public final class InputMethodManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startInput) {
|
if (startInput) {
|
||||||
startInputInner();
|
startInputInner(null, 0, 0, 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -952,10 +970,11 @@ public final class InputMethodManager {
|
|||||||
mServedConnecting = true;
|
mServedConnecting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
startInputInner();
|
startInputInner(null, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startInputInner() {
|
boolean startInputInner(IBinder windowGainingFocus, int controlFlags, int softInputMode,
|
||||||
|
int windowFlags) {
|
||||||
final View view;
|
final View view;
|
||||||
synchronized (mH) {
|
synchronized (mH) {
|
||||||
view = mServedView;
|
view = mServedView;
|
||||||
@ -964,7 +983,7 @@ public final class InputMethodManager {
|
|||||||
if (DEBUG) Log.v(TAG, "Starting input: view=" + view);
|
if (DEBUG) Log.v(TAG, "Starting input: view=" + view);
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
|
if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -977,7 +996,7 @@ public final class InputMethodManager {
|
|||||||
// If the view doesn't have a handler, something has changed out
|
// If the view doesn't have a handler, something has changed out
|
||||||
// from under us, so just bail.
|
// from under us, so just bail.
|
||||||
if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!");
|
if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (vh.getLooper() != Looper.myLooper()) {
|
if (vh.getLooper() != Looper.myLooper()) {
|
||||||
// The view is running on a different thread than our own, so
|
// The view is running on a different thread than our own, so
|
||||||
@ -985,10 +1004,10 @@ public final class InputMethodManager {
|
|||||||
if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
|
if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
|
||||||
vh.post(new Runnable() {
|
vh.post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
startInputInner();
|
startInputInner(null, 0, 0, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Okay we are now ready to call into the served view and have it
|
// Okay we are now ready to call into the served view and have it
|
||||||
@ -1008,12 +1027,14 @@ public final class InputMethodManager {
|
|||||||
if (DEBUG) Log.v(TAG,
|
if (DEBUG) Log.v(TAG,
|
||||||
"Starting input: finished by someone else (view="
|
"Starting input: finished by someone else (view="
|
||||||
+ mServedView + " conn=" + mServedConnecting + ")");
|
+ mServedView + " conn=" + mServedConnecting + ")");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we already have a text box, then this view is already
|
// If we already have a text box, then this view is already
|
||||||
// connected so we want to restart it.
|
// connected so we want to restart it.
|
||||||
final boolean initial = mCurrentTextBoxAttribute == null;
|
if (mCurrentTextBoxAttribute == null) {
|
||||||
|
controlFlags |= CONTROL_START_INITIAL;
|
||||||
|
}
|
||||||
|
|
||||||
// Hook 'em up and let 'er rip.
|
// Hook 'em up and let 'er rip.
|
||||||
mCurrentTextBoxAttribute = tba;
|
mCurrentTextBoxAttribute = tba;
|
||||||
@ -1033,9 +1054,17 @@ public final class InputMethodManager {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
|
if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
|
||||||
+ ic + " tba=" + tba + " initial=" + initial);
|
+ ic + " tba=" + tba + " controlFlags=#"
|
||||||
InputBindResult res = mService.startInput(mClient,
|
+ Integer.toHexString(controlFlags));
|
||||||
servedContext, tba, initial, true);
|
InputBindResult res;
|
||||||
|
if (windowGainingFocus != null) {
|
||||||
|
res = mService.windowGainedFocus(mClient, windowGainingFocus,
|
||||||
|
controlFlags, softInputMode, windowFlags,
|
||||||
|
tba, servedContext);
|
||||||
|
} else {
|
||||||
|
res = mService.startInput(mClient,
|
||||||
|
servedContext, tba, controlFlags);
|
||||||
|
}
|
||||||
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
|
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
if (res.id != null) {
|
if (res.id != null) {
|
||||||
@ -1044,7 +1073,7 @@ public final class InputMethodManager {
|
|||||||
} else if (mCurMethod == null) {
|
} else if (mCurMethod == null) {
|
||||||
// This means there is no input method available.
|
// This means there is no input method available.
|
||||||
if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
|
if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mCurMethod != null && mCompletions != null) {
|
if (mCurMethod != null && mCompletions != null) {
|
||||||
@ -1057,6 +1086,8 @@ public final class InputMethodManager {
|
|||||||
Log.w(TAG, "IME died: " + mCurId, e);
|
Log.w(TAG, "IME died: " + mCurId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1133,27 +1164,26 @@ public final class InputMethodManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void checkFocus() {
|
public void checkFocus() {
|
||||||
if (checkFocusNoStartInput()) {
|
if (checkFocusNoStartInput(false)) {
|
||||||
startInputInner();
|
startInputInner(null, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkFocusNoStartInput() {
|
private boolean checkFocusNoStartInput(boolean forceNewFocus) {
|
||||||
// This is called a lot, so short-circuit before locking.
|
// This is called a lot, so short-circuit before locking.
|
||||||
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
|
if (mServedView == mNextServedView && !forceNewFocus) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputConnection ic = null;
|
InputConnection ic = null;
|
||||||
synchronized (mH) {
|
synchronized (mH) {
|
||||||
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
|
if (mServedView == mNextServedView && !forceNewFocus) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
|
if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
|
||||||
+ " next=" + mNextServedView
|
+ " next=" + mNextServedView
|
||||||
+ " restart=" + mNextServedNeedsStart);
|
+ " forceNewFocus=" + forceNewFocus);
|
||||||
|
|
||||||
mNextServedNeedsStart = false;
|
|
||||||
if (mNextServedView == null) {
|
if (mNextServedView == null) {
|
||||||
finishInputLocked();
|
finishInputLocked();
|
||||||
// In this case, we used to have a focused view on the window,
|
// In this case, we used to have a focused view on the window,
|
||||||
@ -1184,13 +1214,14 @@ public final class InputMethodManager {
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by ViewAncestor when its window gets input focus.
|
* Called by ViewAncestor when its window gets input focus.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void onWindowFocus(View rootView, View focusedView, int softInputMode,
|
public void onWindowFocus(View rootView, View focusedView, int softInputMode,
|
||||||
boolean first, int windowFlags) {
|
boolean first, int windowFlags) {
|
||||||
|
boolean forceNewFocus = false;
|
||||||
synchronized (mH) {
|
synchronized (mH) {
|
||||||
if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
|
if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
|
||||||
+ " softInputMode=" + softInputMode
|
+ " softInputMode=" + softInputMode
|
||||||
@ -1199,26 +1230,41 @@ public final class InputMethodManager {
|
|||||||
if (mHasBeenInactive) {
|
if (mHasBeenInactive) {
|
||||||
if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh");
|
if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh");
|
||||||
mHasBeenInactive = false;
|
mHasBeenInactive = false;
|
||||||
mNextServedNeedsStart = true;
|
forceNewFocus = true;
|
||||||
}
|
}
|
||||||
focusInLocked(focusedView != null ? focusedView : rootView);
|
focusInLocked(focusedView != null ? focusedView : rootView);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean startInput = checkFocusNoStartInput();
|
int controlFlags = 0;
|
||||||
|
if (focusedView != null) {
|
||||||
synchronized (mH) {
|
controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;
|
||||||
try {
|
if (focusedView.onCheckIsTextEditor()) {
|
||||||
final boolean isTextEditor = focusedView != null &&
|
controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;
|
||||||
focusedView.onCheckIsTextEditor();
|
|
||||||
mService.windowGainedFocus(mClient, rootView.getWindowToken(),
|
|
||||||
focusedView != null, isTextEditor, softInputMode, first,
|
|
||||||
windowFlags);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (first) {
|
||||||
if (startInput) {
|
controlFlags |= CONTROL_WINDOW_FIRST;
|
||||||
startInputInner();
|
}
|
||||||
|
|
||||||
|
if (checkFocusNoStartInput(forceNewFocus)) {
|
||||||
|
// We need to restart input on the current focus view. This
|
||||||
|
// should be done in conjunction with telling the system service
|
||||||
|
// about the window gaining focus, to help make the transition
|
||||||
|
// smooth.
|
||||||
|
if (startInputInner(rootView.getWindowToken(),
|
||||||
|
controlFlags, softInputMode, windowFlags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For some reason we didn't do a startInput + windowFocusGain, so
|
||||||
|
// we'll just do a window focus gain and call it a day.
|
||||||
|
synchronized (mH) {
|
||||||
|
try {
|
||||||
|
mService.windowGainedFocus(mClient, rootView.getWindowToken(),
|
||||||
|
controlFlags, softInputMode, windowFlags, null, null);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1649,8 +1695,7 @@ public final class InputMethodManager {
|
|||||||
p.println(" mCurMethod=" + mCurMethod);
|
p.println(" mCurMethod=" + mCurMethod);
|
||||||
p.println(" mCurRootView=" + mCurRootView);
|
p.println(" mCurRootView=" + mCurRootView);
|
||||||
p.println(" mServedView=" + mServedView);
|
p.println(" mServedView=" + mServedView);
|
||||||
p.println(" mNextServedNeedsStart=" + mNextServedNeedsStart
|
p.println(" mNextServedView=" + mNextServedView);
|
||||||
+ " mNextServedView=" + mNextServedView);
|
|
||||||
p.println(" mServedConnecting=" + mServedConnecting);
|
p.println(" mServedConnecting=" + mServedConnecting);
|
||||||
if (mCurrentTextBoxAttribute != null) {
|
if (mCurrentTextBoxAttribute != null) {
|
||||||
p.println(" mCurrentTextBoxAttribute:");
|
p.println(" mCurrentTextBoxAttribute:");
|
||||||
|
@ -43,16 +43,17 @@ interface IInputMethodManager {
|
|||||||
void removeClient(in IInputMethodClient client);
|
void removeClient(in IInputMethodClient client);
|
||||||
|
|
||||||
InputBindResult startInput(in IInputMethodClient client,
|
InputBindResult startInput(in IInputMethodClient client,
|
||||||
IInputContext inputContext, in EditorInfo attribute,
|
IInputContext inputContext, in EditorInfo attribute, int controlFlags);
|
||||||
boolean initial, boolean needResult);
|
|
||||||
void finishInput(in IInputMethodClient client);
|
void finishInput(in IInputMethodClient client);
|
||||||
boolean showSoftInput(in IInputMethodClient client, int flags,
|
boolean showSoftInput(in IInputMethodClient client, int flags,
|
||||||
in ResultReceiver resultReceiver);
|
in ResultReceiver resultReceiver);
|
||||||
boolean hideSoftInput(in IInputMethodClient client, int flags,
|
boolean hideSoftInput(in IInputMethodClient client, int flags,
|
||||||
in ResultReceiver resultReceiver);
|
in ResultReceiver resultReceiver);
|
||||||
void windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
|
// Report that a window has gained focus. If 'attribute' is non-null,
|
||||||
boolean viewHasFocus, boolean isTextEditor,
|
// this will also do a startInput.
|
||||||
int softInputMode, boolean first, int windowFlags);
|
InputBindResult windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
|
||||||
|
int controlFlags, int softInputMode, int windowFlags,
|
||||||
|
in EditorInfo attribute, IInputContext inputContext);
|
||||||
|
|
||||||
void showInputMethodPickerFromClient(in IInputMethodClient client);
|
void showInputMethodPickerFromClient(in IInputMethodClient client);
|
||||||
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
|
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
|
||||||
|
@ -780,7 +780,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
|
InputBindResult attachNewInputLocked(boolean initial) {
|
||||||
if (!mBoundToMethod) {
|
if (!mBoundToMethod) {
|
||||||
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
|
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
|
||||||
MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
|
MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
|
||||||
@ -798,14 +798,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
|
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
|
||||||
showCurrentInputLocked(getAppShowFlags(), null);
|
showCurrentInputLocked(getAppShowFlags(), null);
|
||||||
}
|
}
|
||||||
return needResult
|
return new InputBindResult(session.session, mCurId, mCurSeq);
|
||||||
? new InputBindResult(session.session, mCurId, mCurSeq)
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputBindResult startInputLocked(IInputMethodClient client,
|
InputBindResult startInputLocked(IInputMethodClient client,
|
||||||
IInputContext inputContext, EditorInfo attribute,
|
IInputContext inputContext, EditorInfo attribute, int controlFlags) {
|
||||||
boolean initial, boolean needResult) {
|
|
||||||
// If no method is currently selected, do nothing.
|
// If no method is currently selected, do nothing.
|
||||||
if (mCurMethodId == null) {
|
if (mCurMethodId == null) {
|
||||||
return mNoBinding;
|
return mNoBinding;
|
||||||
@ -831,6 +828,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputBindResult startInputUncheckedLocked(ClientState cs,
|
||||||
|
IInputContext inputContext, EditorInfo attribute, int controlFlags) {
|
||||||
|
// If no method is currently selected, do nothing.
|
||||||
|
if (mCurMethodId == null) {
|
||||||
|
return mNoBinding;
|
||||||
|
}
|
||||||
|
|
||||||
if (mCurClient != cs) {
|
if (mCurClient != cs) {
|
||||||
// If the client is changing, we need to switch over to the new
|
// If the client is changing, we need to switch over to the new
|
||||||
// one.
|
// one.
|
||||||
@ -861,7 +868,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
if (cs.curSession != null) {
|
if (cs.curSession != null) {
|
||||||
// Fast case: if we are already connected to the input method,
|
// Fast case: if we are already connected to the input method,
|
||||||
// then just return it.
|
// then just return it.
|
||||||
return attachNewInputLocked(initial, needResult);
|
return attachNewInputLocked(
|
||||||
|
(controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
|
||||||
}
|
}
|
||||||
if (mHaveConnection) {
|
if (mHaveConnection) {
|
||||||
if (mCurMethod != null) {
|
if (mCurMethod != null) {
|
||||||
@ -942,13 +950,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputBindResult startInput(IInputMethodClient client,
|
public InputBindResult startInput(IInputMethodClient client,
|
||||||
IInputContext inputContext, EditorInfo attribute,
|
IInputContext inputContext, EditorInfo attribute, int controlFlags) {
|
||||||
boolean initial, boolean needResult) {
|
|
||||||
synchronized (mMethodMap) {
|
synchronized (mMethodMap) {
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return startInputLocked(client, inputContext, attribute,
|
return startInputLocked(client, inputContext, attribute, controlFlags);
|
||||||
initial, needResult);
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
@ -991,7 +997,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
mCurClient.curSession = new SessionState(mCurClient,
|
mCurClient.curSession = new SessionState(mCurClient,
|
||||||
method, session);
|
method, session);
|
||||||
mCurClient.sessionRequested = false;
|
mCurClient.sessionRequested = false;
|
||||||
InputBindResult res = attachNewInputLocked(true, true);
|
InputBindResult res = attachNewInputLocked(true);
|
||||||
if (res.method != null) {
|
if (res.method != null) {
|
||||||
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
|
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
|
||||||
MSG_BIND_METHOD, mCurClient.client, res));
|
MSG_BIND_METHOD, mCurClient.client, res));
|
||||||
@ -1476,36 +1482,45 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowGainedFocus(IInputMethodClient client, IBinder windowToken,
|
public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
|
||||||
boolean viewHasFocus, boolean isTextEditor, int softInputMode,
|
int controlFlags, int softInputMode, int windowFlags,
|
||||||
boolean first, int windowFlags) {
|
EditorInfo attribute, IInputContext inputContext) {
|
||||||
|
InputBindResult res = null;
|
||||||
long ident = Binder.clearCallingIdentity();
|
long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mMethodMap) {
|
synchronized (mMethodMap) {
|
||||||
if (DEBUG) Slog.v(TAG, "windowGainedFocus: " + client.asBinder()
|
if (DEBUG) Slog.v(TAG, "windowGainedFocus: " + client.asBinder()
|
||||||
+ " viewHasFocus=" + viewHasFocus
|
+ " controlFlags=#" + Integer.toHexString(controlFlags)
|
||||||
+ " isTextEditor=" + isTextEditor
|
|
||||||
+ " softInputMode=#" + Integer.toHexString(softInputMode)
|
+ " softInputMode=#" + Integer.toHexString(softInputMode)
|
||||||
+ " first=" + first + " flags=#"
|
+ " windowFlags=#" + Integer.toHexString(windowFlags));
|
||||||
+ Integer.toHexString(windowFlags));
|
|
||||||
|
|
||||||
if (mCurClient == null || client == null
|
ClientState cs = mClients.get(client.asBinder());
|
||||||
|| mCurClient.client.asBinder() != client.asBinder()) {
|
if (cs == null) {
|
||||||
try {
|
throw new IllegalArgumentException("unknown client "
|
||||||
// We need to check if this is the current client with
|
+ client.asBinder());
|
||||||
// focus in the window manager, to allow this call to
|
}
|
||||||
// be made before input is started in it.
|
|
||||||
if (!mIWindowManager.inputMethodClientHasFocus(client)) {
|
try {
|
||||||
Slog.w(TAG, "Client not active, ignoring focus gain of: " + client);
|
if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
|
||||||
return;
|
// Check with the window manager to make sure this client actually
|
||||||
}
|
// has a window with focus. If not, reject. This is thread safe
|
||||||
} catch (RemoteException e) {
|
// because if the focus changes some time before or after, the
|
||||||
|
// next client receiving focus that has any interest in input will
|
||||||
|
// be calling through here after that change happens.
|
||||||
|
Slog.w(TAG, "Focus gain on non-focused client " + cs.client
|
||||||
|
+ " (uid=" + cs.uid + " pid=" + cs.pid + ")");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCurFocusedWindow == windowToken) {
|
if (mCurFocusedWindow == windowToken) {
|
||||||
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
|
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
|
||||||
return;
|
if (attribute != null) {
|
||||||
|
return startInputUncheckedLocked(cs, inputContext, attribute,
|
||||||
|
controlFlags);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
mCurFocusedWindow = windowToken;
|
mCurFocusedWindow = windowToken;
|
||||||
|
|
||||||
@ -1521,6 +1536,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
== WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
== WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
||||||
|| mRes.getConfiguration().isLayoutSizeAtLeast(
|
|| mRes.getConfiguration().isLayoutSizeAtLeast(
|
||||||
Configuration.SCREENLAYOUT_SIZE_LARGE);
|
Configuration.SCREENLAYOUT_SIZE_LARGE);
|
||||||
|
final boolean isTextEditor =
|
||||||
|
(controlFlags&InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0;
|
||||||
|
|
||||||
|
// We want to start input before showing the IME, but after closing
|
||||||
|
// it. We want to do this after closing it to help the IME disappear
|
||||||
|
// more quickly (not get stuck behind it initializing itself for the
|
||||||
|
// new focused input, even if its window wants to hide the IME).
|
||||||
|
boolean didStart = false;
|
||||||
|
|
||||||
switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
|
switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
|
||||||
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
|
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
|
||||||
@ -1536,12 +1559,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
|
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
|
||||||
// There is a focus view, and we are navigating forward
|
// There is a focus view, and we are navigating forward
|
||||||
// into the window, so show the input window for the user.
|
// into the window, so show the input window for the user.
|
||||||
// We only do this automatically if the window an resize
|
// We only do this automatically if the window can resize
|
||||||
// to accomodate the IME (so what the user sees will give
|
// to accommodate the IME (so what the user sees will give
|
||||||
// them good context without input information being obscured
|
// them good context without input information being obscured
|
||||||
// by the IME) or if running on a large screen where there
|
// by the IME) or if running on a large screen where there
|
||||||
// is more room for the target window + IME.
|
// is more room for the target window + IME.
|
||||||
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
|
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
|
||||||
|
if (attribute != null) {
|
||||||
|
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||||
|
controlFlags);
|
||||||
|
didStart = true;
|
||||||
|
}
|
||||||
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
|
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1563,18 +1591,35 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
if ((softInputMode &
|
if ((softInputMode &
|
||||||
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
|
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
|
||||||
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
|
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
|
||||||
|
if (attribute != null) {
|
||||||
|
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||||
|
controlFlags);
|
||||||
|
didStart = true;
|
||||||
|
}
|
||||||
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
|
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
|
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
|
||||||
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
|
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
|
||||||
|
if (attribute != null) {
|
||||||
|
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||||
|
controlFlags);
|
||||||
|
didStart = true;
|
||||||
|
}
|
||||||
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
|
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!didStart && attribute != null) {
|
||||||
|
res = startInputUncheckedLocked(cs, inputContext, attribute,
|
||||||
|
controlFlags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user