Loading core/java/android/view/ImeFocusController.java +5 −5 Original line number Diff line number Diff line Loading @@ -125,10 +125,10 @@ public final class ImeFocusController { final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); // Starting new input when the next focused view is same as served view but the // editor is not aligned with the same editor or editor is inactive. final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView; if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) { // Starting new input when the next focused view is same as served view but the currently // active connection (if any) is not associated with it. final boolean nextFocusIsServedView = mServedView == viewForWindowFocus; if (nextFocusIsServedView && !immDelegate.hasActiveConnection(viewForWindowFocus)) { forceFocus = true; } Loading Loading @@ -254,7 +254,7 @@ public final class ImeFocusController { void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); boolean isRestartOnNextWindowFocus(boolean reset); boolean isSameEditorAndAcceptingText(View view); boolean hasActiveConnection(View view); } public View getServedView() { Loading core/java/android/view/inputmethod/InputMethodManager.java +26 −31 Original line number Diff line number Diff line Loading @@ -19,8 +19,8 @@ package android.view.inputmethod; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION; import android.annotation.DrawableRes; import android.annotation.NonNull; Loading Loading @@ -89,6 +89,7 @@ import com.android.internal.view.InputBindResult; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -610,14 +611,13 @@ public final class InputMethodManager { @Override public void startInputAsyncOnWindowFocusGain(View focusedView, @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) { final boolean forceNewFocus1 = forceNewFocus; final int startInputFlags = getStartInputFlags(focusedView, 0); final ImeFocusController controller = getFocusController(); if (controller == null) { return; } if (controller.checkFocus(forceNewFocus1, false)) { if (controller.checkFocus(forceNewFocus, false)) { // 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 Loading @@ -633,15 +633,15 @@ public final class InputMethodManager { // we'll just do a window focus gain and call it a day. try { View servedView = controller.getServedView(); boolean nextFocusSameEditor = servedView != null && servedView == focusedView && isSameEditorAndAcceptingText(focusedView); boolean nextFocusHasConnection = servedView != null && servedView == focusedView && hasActiveConnection(focusedView); if (DEBUG) { Log.v(TAG, "Reporting focus gain, without startInput" + ", nextFocusIsServedView=" + nextFocusSameEditor); + ", nextFocusIsServedView=" + nextFocusHasConnection); } final int startInputReason = nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR; nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; mService.startInputOrWindowGainedFocus( startInputReason, mClient, focusedView.getWindowToken(), startInputFlags, softInputMode, Loading Loading @@ -701,33 +701,24 @@ public final class InputMethodManager { } /** * For {@link ImeFocusController} to check if the given focused view aligns with the same * editor and the editor is active to accept the text input. * Checks whether the active input connection (if any) is for the given view. * * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to * ImeFocusController. * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance, * so that we we can directly check if the current focused view aligned with the same editor * in the window without using this checking. * * Note that this method is only use for fixing start new input may ignored issue * Note that this method is only intended for restarting input after focus gain * (e.g. b/160391516), DO NOT leverage this method to do another check. */ public boolean isSameEditorAndAcceptingText(View view) { @Override public boolean hasActiveConnection(View view) { synchronized (mH) { if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) { if (!hasServedByInputMethodLocked(view)) { return false; } final EditorInfo ic = mCurrentTextBoxAttribute; // This sameEditor checking is based on using object hash comparison to check if // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the // hash code is same as the given focused view. final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId && view.getAutofillId() == ic.autofillId && view.getContext().getOpPackageName() == ic.packageName; return sameEditor && mServedInputConnectionWrapper != null && mServedInputConnectionWrapper.isActive(); return mServedInputConnectionWrapper != null && mServedInputConnectionWrapper.isActive() && mServedInputConnectionWrapper.mServedView.get() == view; } } } Loading Loading @@ -980,11 +971,13 @@ public final class InputMethodManager { private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper { private final InputMethodManager mParentInputMethodManager; private final WeakReference<View> mServedView; public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, final InputMethodManager inputMethodManager) { ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn, InputMethodManager inputMethodManager, View servedView) { super(mainLooper, conn); mParentInputMethodManager = inputMethodManager; mServedView = new WeakReference<>(servedView); } @Override Loading @@ -1007,6 +1000,7 @@ public final class InputMethodManager { + "connection=" + getInputConnection() + " finished=" + isFinished() + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive + " mServedView=" + mServedView.get() + "}"; } } Loading Loading @@ -1187,7 +1181,8 @@ public final class InputMethodManager { mMainLooper = looper; mH = new H(looper); mDisplayId = displayId; mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this); mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this, null); } /** Loading Loading @@ -1968,7 +1963,7 @@ public final class InputMethodManager { icHandler = ic.getHandler(); } servedContext = new ControlledInputConnectionWrapper( icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this); icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view); } else { servedContext = null; missingMethodFlags = 0; Loading core/java/com/android/internal/inputmethod/InputMethodDebug.java +4 −4 Original line number Diff line number Diff line Loading @@ -46,10 +46,10 @@ public final class InputMethodDebug { return "UNSPECIFIED"; case StartInputReason.WINDOW_FOCUS_GAIN: return "WINDOW_FOCUS_GAIN"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR: return "WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR: return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION: return "WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION: return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION"; case StartInputReason.APP_CALLED_RESTART_INPUT_API: return "APP_CALLED_RESTART_INPUT_API"; case StartInputReason.CHECK_FOCUS: Loading core/java/com/android/internal/inputmethod/StartInputReason.java +4 −4 Original line number Diff line number Diff line Loading @@ -30,8 +30,8 @@ import java.lang.annotation.Retention; @IntDef(value = { StartInputReason.UNSPECIFIED, StartInputReason.WINDOW_FOCUS_GAIN, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION, StartInputReason.APP_CALLED_RESTART_INPUT_API, StartInputReason.CHECK_FOCUS, StartInputReason.BOUND_TO_IMMS, Loading @@ -54,13 +54,13 @@ public @interface StartInputReason { * view and its input connection remains. {@link android.view.inputmethod.InputMethodManager} * just reports this window focus change event to sync IME input target for system. */ int WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR = 2; int WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION = 2; /** * {@link android.view.Window} gained focus but there is no {@link android.view.View} that is * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports * this window focus change event for logging. */ int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR = 3; int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION = 3; /** * {@link android.view.inputmethod.InputMethodManager#restartInput(android.view.View)} is * either explicitly called by the application or indirectly called by some Framework class Loading Loading
core/java/android/view/ImeFocusController.java +5 −5 Original line number Diff line number Diff line Loading @@ -125,10 +125,10 @@ public final class ImeFocusController { final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); // Starting new input when the next focused view is same as served view but the // editor is not aligned with the same editor or editor is inactive. final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView; if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) { // Starting new input when the next focused view is same as served view but the currently // active connection (if any) is not associated with it. final boolean nextFocusIsServedView = mServedView == viewForWindowFocus; if (nextFocusIsServedView && !immDelegate.hasActiveConnection(viewForWindowFocus)) { forceFocus = true; } Loading Loading @@ -254,7 +254,7 @@ public final class ImeFocusController { void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); boolean isRestartOnNextWindowFocus(boolean reset); boolean isSameEditorAndAcceptingText(View view); boolean hasActiveConnection(View view); } public View getServedView() { Loading
core/java/android/view/inputmethod/InputMethodManager.java +26 −31 Original line number Diff line number Diff line Loading @@ -19,8 +19,8 @@ package android.view.inputmethod; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION; import android.annotation.DrawableRes; import android.annotation.NonNull; Loading Loading @@ -89,6 +89,7 @@ import com.android.internal.view.InputBindResult; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -610,14 +611,13 @@ public final class InputMethodManager { @Override public void startInputAsyncOnWindowFocusGain(View focusedView, @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) { final boolean forceNewFocus1 = forceNewFocus; final int startInputFlags = getStartInputFlags(focusedView, 0); final ImeFocusController controller = getFocusController(); if (controller == null) { return; } if (controller.checkFocus(forceNewFocus1, false)) { if (controller.checkFocus(forceNewFocus, false)) { // 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 Loading @@ -633,15 +633,15 @@ public final class InputMethodManager { // we'll just do a window focus gain and call it a day. try { View servedView = controller.getServedView(); boolean nextFocusSameEditor = servedView != null && servedView == focusedView && isSameEditorAndAcceptingText(focusedView); boolean nextFocusHasConnection = servedView != null && servedView == focusedView && hasActiveConnection(focusedView); if (DEBUG) { Log.v(TAG, "Reporting focus gain, without startInput" + ", nextFocusIsServedView=" + nextFocusSameEditor); + ", nextFocusIsServedView=" + nextFocusHasConnection); } final int startInputReason = nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR; nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; mService.startInputOrWindowGainedFocus( startInputReason, mClient, focusedView.getWindowToken(), startInputFlags, softInputMode, Loading Loading @@ -701,33 +701,24 @@ public final class InputMethodManager { } /** * For {@link ImeFocusController} to check if the given focused view aligns with the same * editor and the editor is active to accept the text input. * Checks whether the active input connection (if any) is for the given view. * * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to * ImeFocusController. * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance, * so that we we can directly check if the current focused view aligned with the same editor * in the window without using this checking. * * Note that this method is only use for fixing start new input may ignored issue * Note that this method is only intended for restarting input after focus gain * (e.g. b/160391516), DO NOT leverage this method to do another check. */ public boolean isSameEditorAndAcceptingText(View view) { @Override public boolean hasActiveConnection(View view) { synchronized (mH) { if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) { if (!hasServedByInputMethodLocked(view)) { return false; } final EditorInfo ic = mCurrentTextBoxAttribute; // This sameEditor checking is based on using object hash comparison to check if // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the // hash code is same as the given focused view. final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId && view.getAutofillId() == ic.autofillId && view.getContext().getOpPackageName() == ic.packageName; return sameEditor && mServedInputConnectionWrapper != null && mServedInputConnectionWrapper.isActive(); return mServedInputConnectionWrapper != null && mServedInputConnectionWrapper.isActive() && mServedInputConnectionWrapper.mServedView.get() == view; } } } Loading Loading @@ -980,11 +971,13 @@ public final class InputMethodManager { private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper { private final InputMethodManager mParentInputMethodManager; private final WeakReference<View> mServedView; public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, final InputMethodManager inputMethodManager) { ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn, InputMethodManager inputMethodManager, View servedView) { super(mainLooper, conn); mParentInputMethodManager = inputMethodManager; mServedView = new WeakReference<>(servedView); } @Override Loading @@ -1007,6 +1000,7 @@ public final class InputMethodManager { + "connection=" + getInputConnection() + " finished=" + isFinished() + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive + " mServedView=" + mServedView.get() + "}"; } } Loading Loading @@ -1187,7 +1181,8 @@ public final class InputMethodManager { mMainLooper = looper; mH = new H(looper); mDisplayId = displayId; mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this); mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this, null); } /** Loading Loading @@ -1968,7 +1963,7 @@ public final class InputMethodManager { icHandler = ic.getHandler(); } servedContext = new ControlledInputConnectionWrapper( icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this); icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view); } else { servedContext = null; missingMethodFlags = 0; Loading
core/java/com/android/internal/inputmethod/InputMethodDebug.java +4 −4 Original line number Diff line number Diff line Loading @@ -46,10 +46,10 @@ public final class InputMethodDebug { return "UNSPECIFIED"; case StartInputReason.WINDOW_FOCUS_GAIN: return "WINDOW_FOCUS_GAIN"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR: return "WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR: return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION: return "WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION"; case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION: return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION"; case StartInputReason.APP_CALLED_RESTART_INPUT_API: return "APP_CALLED_RESTART_INPUT_API"; case StartInputReason.CHECK_FOCUS: Loading
core/java/com/android/internal/inputmethod/StartInputReason.java +4 −4 Original line number Diff line number Diff line Loading @@ -30,8 +30,8 @@ import java.lang.annotation.Retention; @IntDef(value = { StartInputReason.UNSPECIFIED, StartInputReason.WINDOW_FOCUS_GAIN, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION, StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION, StartInputReason.APP_CALLED_RESTART_INPUT_API, StartInputReason.CHECK_FOCUS, StartInputReason.BOUND_TO_IMMS, Loading @@ -54,13 +54,13 @@ public @interface StartInputReason { * view and its input connection remains. {@link android.view.inputmethod.InputMethodManager} * just reports this window focus change event to sync IME input target for system. */ int WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR = 2; int WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION = 2; /** * {@link android.view.Window} gained focus but there is no {@link android.view.View} that is * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports * this window focus change event for logging. */ int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR = 3; int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION = 3; /** * {@link android.view.inputmethod.InputMethodManager#restartInput(android.view.View)} is * either explicitly called by the application or indirectly called by some Framework class Loading