Bug 1404111 - Part 1 - Work around potential InputMethodManager bug when gaining focus. r?snorp
MozReview-Commit-ID: 2YnsMCZYckA
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -23,31 +23,33 @@ import org.mozilla.gecko.util.GeckoBundl
import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
public class GeckoView extends LayerView {
private static final String DEFAULT_SHARED_PREFERENCES_FILE = "GeckoView";
private static final String LOGTAG = "GeckoView";
private static final boolean DEBUG = false;
@@ -304,16 +306,17 @@ public class GeckoView extends LayerView
* @param delegate PermissionDelegate instance or null to use the default delegate.
*/
public void setPermissionDelegate(final PermissionDelegate delegate) {
mPermissionHandler.setListener(delegate, this);
}
private PromptDelegate mPromptDelegate;
private InputConnectionListener mInputConnectionListener;
+ private boolean mIsResettingFocus;
private GeckoViewSettings mSettings;
protected String mChromeUri;
protected int mScreenId = 0; // default to the primary screen
@WrapForJNI(dispatchTo = "proxy")
protected static final class Window extends JNIObject {
@@ -702,16 +705,55 @@ public class GeckoView extends LayerView
mEventDispatcher.dispatch("GeckoView:SetActive", msg);
}
public GeckoViewSettings getSettings() {
return mSettings;
}
@Override
+ public void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+
+ if (gainFocus && !mIsResettingFocus) {
+ ThreadUtils.postToUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isFocused()) {
+ return;
+ }
+
+ final InputMethodManager imm = InputMethods.getInputMethodManager(getContext());
+ // Bug 1404111:
+ // Through View#onFocusChanged, the InputMethodManager queues up a checkFocus
+ // call for the next spin of the message loop, so by posting this Runnable after
+ // super#onFocusChanged, the IMM should have completed its focus change handling
+ // at this point and we should be the active view for input handling.
+
+ // If however onViewDetachedFromWindow for the previously active view gets
+ // called *after* onFocusChanged, but *before* the focus change has been fully
+ // processed by the IMM with the help of checkFocus, the IMM will lose track of
+ // the currently active view, which means that we can't interact with the IME.
+ if (!imm.isActive(GeckoView.this)) {
+ // If that happens, we bring the IMM's internal state back into sync by
+ // clearing and resetting our focus.
+ mIsResettingFocus = true;
+ clearFocus();
+ // After calling clearFocus we might regain focus automatically, but we
+ // explicitly request it again in case this doesn't happen.
+ // If we've already got the focus back, this will then be a no-op anyway.
+ requestFocus();
+ mIsResettingFocus = false;
+ }
+ }
+ });
+ }
+ }
+
+ @Override
public Handler getHandler() {
if (mInputConnectionListener != null) {
return mInputConnectionListener.getHandler(super.getHandler());
}
return super.getHandler();
}
@Override