[webview_flutter] Fix input bug on route changes (#1853)
Fixes bug where the InputConnection proxy view was persisting across
multiple WebView creation calls.
diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md
index de0fba5..bb09f98 100644
--- a/packages/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.10+2
+
+* Fix InputConnection being lost when combined with route transitions.
+
## 0.3.10+1
* Add support for simultaenous Flutter `TextInput` and WebView text fields.
diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java
index 327434d..8389877 100644
--- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java
+++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java
@@ -261,5 +261,6 @@
@Override
public void dispose() {
methodChannel.setMethodCallHandler(null);
+ webView.dispose();
}
}
diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
index 1748be1..da4d81e 100644
--- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
+++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
@@ -53,10 +53,15 @@
imm.restartInput(containerView);
}
+ /** Restore the original InputConnection, if needed. */
+ void dispose() {
+ resetInputConnection();
+ }
+
/**
* Creates an InputConnection from the IME thread when needed.
*
- * <p>We only need to create a {@link ThreadedInputConnectionProxy} and create an
+ * <p>We only need to create a {@link ThreadedInputConnectionProxyAdapterView} and create an
* InputConnectionProxy on the IME thread when WebView is doing the same thing. So we rely on the
* system calling this method for WebView's proxy view in order to know when we need to create our
* own.
@@ -84,32 +89,7 @@
/*containerView=*/ containerView,
/*targetView=*/ view,
/*imeHandler=*/ view.getHandler());
- final View container = this;
- proxyAdapterView.requestFocus();
- // This is the crucial trick that gets the InputConnection creation to happen on the correct
- // thread.
- // https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java?l=169&rcl=f0698ee3e4483fad5b0c34159276f71cfaf81f3a
- post(
- new Runnable() {
- @Override
- public void run() {
- InputMethodManager imm =
- (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
- // This is a hack to make InputMethodManager believe that the proxy view now has focus.
- // As a result, InputMethodManager will think that proxyAdapterView is focused, and will
- // call getHandler() of the view when creating input connection.
-
- // Step 1: Set proxyAdapterView as InputMethodManager#mNextServedView. This does not
- // affect the real window focus.
- proxyAdapterView.onWindowFocusChanged(true);
-
- // Step 2: Have InputMethodManager focus in on proxyAdapterView. As a result, IMM will
- // call onCreateInputConnection() on proxyAdapterView on the same thread as
- // proxyAdapterView.getHandler(). It will also call subsequent InputConnection methods
- // on this IME thread.
- imm.isActive(containerView);
- }
- });
+ setInputConnectionTarget(/*targetView=*/ proxyAdapterView);
return super.checkInputConnectionProxy(view);
}
@@ -124,18 +104,52 @@
@Override
public void clearFocus() {
super.clearFocus();
+ resetInputConnection();
+ }
+
+ /**
+ * Ensure that input creation happens back on {@link #containerView}.
+ *
+ * <p>The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's
+ * thread for all connections. We undo it here so users will be able to go back to typing in
+ * Flutter UIs as expected.
+ */
+ private void resetInputConnection() {
if (proxyAdapterView == null) {
// No need to reset the InputConnection to the default thread if we've never changed it.
return;
}
- containerView.requestFocus();
+ setInputConnectionTarget(/*targetView=*/ containerView);
+ }
+
+ /**
+ * This is the crucial trick that gets the InputConnection creation to happen on the correct
+ * thread pre Android N.
+ * https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java?l=169&rcl=f0698ee3e4483fad5b0c34159276f71cfaf81f3a
+ *
+ * <p>{@code targetView} should have a {@link View#getHandler} method with the thread that future
+ * InputConnections should be created on.
+ */
+ private void setInputConnectionTarget(final View targetView) {
+ targetView.requestFocus();
containerView.post(
new Runnable() {
@Override
public void run() {
- containerView.onWindowFocusChanged(true);
InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
+ // This is a hack to make InputMethodManager believe that the target view now has focus.
+ // As a result, InputMethodManager will think that targetView is focused, and will call
+ // getHandler() of the view when creating input connection.
+
+ // Step 1: Set targetView as InputMethodManager#mNextServedView. This does not affect
+ // the real window focus.
+ targetView.onWindowFocusChanged(true);
+
+ // Step 2: Have InputMethodManager focus in on targetView. As a result, IMM will call
+ // onCreateInputConnection() on targetView on the same thread as
+ // targetView.getHandler(). It will also call subsequent InputConnection methods on this
+ // thread. This is the IME thread in cases where targetView is our proxyAdapterView.
imm.isActive(containerView);
}
});
diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml
index 236a42e..b1aa092 100644
--- a/packages/webview_flutter/pubspec.yaml
+++ b/packages/webview_flutter/pubspec.yaml
@@ -1,6 +1,6 @@
name: webview_flutter
description: A Flutter plugin that provides a WebView widget on Android and iOS.
-version: 0.3.10+1
+version: 0.3.10+2
author: Flutter Team <flutter-dev@googlegroups.com>
homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter