Clear IMM#mCurRootView when needed
This clears the mCurRootView property from InputMethodManager when it becomes inactive or loses window focus. Before, when going from an app that had the IME shown straight to the launcher home screen, and tapping on the Google search bar, this would attempt to show the IME but would sometimes fail. This is because the show flow would progress further than normal, due to the leftover mCurRootView value in the launcher process. Clearing this value ensures the erronous flow is cancelled early, and due to a subsequent retry, can always succeed in showing the IME. Test: atest android.view.inputmethod.cts.FocusHandlingTest#testClearCurRootViewWhenDifferentProcessBecomesActive Bug: 276742733 Change-Id: Id08dece0a6b7531da6d6f8c456cd2e1d6489a9be
This commit is contained in:
@@ -3783,6 +3783,7 @@ package android.view.inputmethod {
|
||||
method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
|
||||
method public boolean hasActiveInputConnection(@Nullable android.view.View);
|
||||
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests();
|
||||
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
|
||||
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
|
||||
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long);
|
||||
field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
|
||||
|
||||
@@ -86,9 +86,12 @@ public final class ImeFocusController {
|
||||
void onPreWindowFocus(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) {
|
||||
mHasImeFocus = WindowManager.LayoutParams.mayUseInputMethod(windowAttribute.flags);
|
||||
if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) {
|
||||
return;
|
||||
if (!hasWindowFocus) {
|
||||
getImmDelegate().onWindowLostFocus(mViewRootImpl);
|
||||
}
|
||||
} else {
|
||||
getImmDelegate().onPreWindowGainedFocus(mViewRootImpl);
|
||||
}
|
||||
getImmDelegate().onPreWindowGainedFocus(mViewRootImpl);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@@ -163,6 +166,7 @@ public final class ImeFocusController {
|
||||
void onPreWindowGainedFocus(ViewRootImpl viewRootImpl);
|
||||
void onPostWindowGainedFocus(View viewForWindowFocus,
|
||||
@NonNull WindowManager.LayoutParams windowAttribute);
|
||||
void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl);
|
||||
void onViewFocusChanged(@NonNull View view, boolean hasFocus);
|
||||
void onScheduledCheckFocus(@NonNull ViewRootImpl viewRootImpl);
|
||||
void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl);
|
||||
|
||||
@@ -482,12 +482,20 @@ public final class InputMethodManager {
|
||||
private View mNextServedView;
|
||||
|
||||
/**
|
||||
* This is the root view of the overall window that currently has input
|
||||
* method focus.
|
||||
* The latest {@link ViewRootImpl} that has, or most recently had, input method focus.
|
||||
*
|
||||
* <p>This value will be cleared when it becomes inactive and no longer has window focus.
|
||||
*/
|
||||
@Nullable
|
||||
@GuardedBy("mH")
|
||||
ViewRootImpl mCurRootView;
|
||||
|
||||
/**
|
||||
* Whether the {@link #mCurRootView} currently has window focus.
|
||||
*/
|
||||
@GuardedBy("mH")
|
||||
boolean mCurRootViewWindowFocused;
|
||||
|
||||
/**
|
||||
* This is set when we are in the process of connecting, to determine
|
||||
* when we have actually finished.
|
||||
@@ -745,6 +753,7 @@ public final class InputMethodManager {
|
||||
public void onPreWindowGainedFocus(ViewRootImpl viewRootImpl) {
|
||||
synchronized (mH) {
|
||||
setCurrentRootViewLocked(viewRootImpl);
|
||||
mCurRootViewWindowFocused = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,6 +830,17 @@ public final class InputMethodManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl) {
|
||||
synchronized (mH) {
|
||||
if (mCurRootView == viewRootImpl) {
|
||||
mCurRootViewWindowFocused = false;
|
||||
|
||||
clearCurRootViewIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewFocusChanged(@Nullable View view, boolean hasFocus) {
|
||||
onViewFocusChangedInternal(view, hasFocus);
|
||||
@@ -1114,6 +1134,10 @@ public final class InputMethodManager {
|
||||
// Note that finishComposingText() is allowed to run
|
||||
// even when we are not active.
|
||||
mFallbackInputConnection.finishComposingTextFromImm();
|
||||
|
||||
if (clearCurRootViewIfNeeded()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check focus again in case that "onWindowFocus" is called before
|
||||
// handling this message.
|
||||
@@ -1756,8 +1780,7 @@ public final class InputMethodManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given view is the currently active view for the
|
||||
* input method.
|
||||
* Return {@code true} if the given view is the currently active view for the input method.
|
||||
*/
|
||||
public boolean isActive(View view) {
|
||||
// Re-dispatch if there is a context mismatch.
|
||||
@@ -1773,7 +1796,7 @@ public final class InputMethodManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if any view is currently active in the input method.
|
||||
* Return {@code true} if any view is currently active for the input method.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
checkFocus();
|
||||
@@ -1782,6 +1805,20 @@ public final class InputMethodManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given view's {@link ViewRootImpl} is the currently active one
|
||||
* for the {@code InputMethodManager}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
|
||||
public boolean isCurrentRootView(@NonNull View attachedView) {
|
||||
synchronized (mH) {
|
||||
return mCurRootView == attachedView.getViewRootImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the currently served view is accepting full text edits.
|
||||
* If {@code false}, it has no input connection, so it can only handle raw key events.
|
||||
@@ -1908,6 +1945,24 @@ public final class InputMethodManager {
|
||||
mImeDispatcher.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the {@link #mCurRootView} if it's no longer window focused and the connection is
|
||||
* no longer active.
|
||||
*
|
||||
* @return {@code} true iff it was cleared.
|
||||
*/
|
||||
@GuardedBy("mH")
|
||||
private boolean clearCurRootViewIfNeeded() {
|
||||
if (!mActive && !mCurRootViewWindowFocused) {
|
||||
finishInputLocked();
|
||||
mDelegate.setCurrentRootViewLocked(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void displayCompletions(View view, CompletionInfo[] completions) {
|
||||
// Re-dispatch if there is a context mismatch.
|
||||
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
|
||||
|
||||
Reference in New Issue
Block a user