Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/webview_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,5 +261,6 @@ private void registerJavaScriptChannelNames(List<String> channelNames) {
@Override
public void dispose() {
methodChannel.setMethodCallHandler(null);
webView.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,15 @@ void unlockInputConnection() {
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.
Expand Down Expand Up @@ -84,32 +89,7 @@ public boolean checkInputConnectionProxy(final View view) {
/*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);
}

Expand All @@ -124,18 +104,52 @@ public void run() {
@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);
}
});
Expand Down
2 changes: 1 addition & 1 deletion packages/webview_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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

Expand Down