Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close connection on keyboard close #41500

Merged
Expand Up @@ -367,6 +367,14 @@ public void performPrivateCommand(
"TextInputClient.performPrivateCommand", Arrays.asList(inputClientId, json));
}

/** Instructs Flutter to execute a "onConnectionClosed" action. */
public void onConnectionClosed(int inputClientId) {
Log.v(TAG, "Sending 'onConnectionClosed' message.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because other function in TextInputChannel has same log.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! LGTM!

channel.invokeMethod(
"TextInputClient.onConnectionClosed",
Arrays.asList(inputClientId, "TextInputClient.onConnectionClosed"));
}

/**
* Sets the {@link TextInputMethodHandler} which receives all events and requests that are parsed
* from the underlying platform channel.
Expand Down
Expand Up @@ -14,6 +14,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.util.List;

// Loosely based off of
Expand Down Expand Up @@ -41,7 +43,9 @@
// a no-op. When onEnd indicates the end of the animation, the deferred call is
// dispatched again, this time avoiding any flicker since the animation is now
// complete.
@VisibleForTesting

// This class should have "package private" visibility cause it's called from TextInputPlugin.
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
@TargetApi(30)
@RequiresApi(30)
@SuppressLint({"NewApi", "Override"})
Expand All @@ -54,6 +58,7 @@ class ImeSyncDeferringInsetsCallback {
private WindowInsets lastWindowInsets;
private AnimationCallback animationCallback;
private InsetsListener insetsListener;
private ImeVisibleListener imeVisibleListener;

// True when an animation that matches deferredInsetTypes is active.
//
Expand Down Expand Up @@ -88,6 +93,11 @@ void remove() {
view.setOnApplyWindowInsetsListener(null);
}

// Set a listener to be notified when the IME visibility changes.
void setImeVisibleListener(ImeVisibleListener imeVisibleListener) {
this.imeVisibleListener = imeVisibleListener;
}

@VisibleForTesting
View.OnApplyWindowInsetsListener getInsetsListener() {
return insetsListener;
Expand All @@ -98,6 +108,11 @@ WindowInsetsAnimation.Callback getAnimationCallback() {
return animationCallback;
}

@VisibleForTesting
ImeVisibleListener getImeVisibleListener() {
return imeVisibleListener;
}

// WindowInsetsAnimation.Callback was introduced in API level 30. The callback
// subclass is separated into an inner class in order to avoid warnings from
// the Android class loader on older platforms.
Expand All @@ -115,6 +130,20 @@ public void onPrepare(WindowInsetsAnimation animation) {
}
}

@NonNull
@Override
public WindowInsetsAnimation.Bounds onStart(
@NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) {
// Observe changes to software keyboard visibility and notify listener when animation start.
// See https://developer.android.com/develop/ui/views/layout/sw-keyboard.
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(view);
if (insets != null && imeVisibleListener != null) {
boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
imeVisibleListener.onImeVisibleChanged(imeVisible);
}
return super.onStart(animation, bounds);
}

@Override
public WindowInsets onProgress(
WindowInsets insets, List<WindowInsetsAnimation> runningAnimations) {
Expand Down Expand Up @@ -199,4 +228,9 @@ public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
return view.onApplyWindowInsets(windowInsets);
}
}

// Listener for IME visibility changes.
public interface ImeVisibleListener {
void onImeVisibleChanged(boolean visible);
}
}
Expand Up @@ -94,6 +94,17 @@ public TextInputPlugin(
WindowInsets.Type.ime() // Deferred, insets that will animate
);
imeSyncCallback.install();

// When the IME is hidden, we need to notify the framework that close connection.
imeSyncCallback.setImeVisibleListener(
new ImeSyncDeferringInsetsCallback.ImeVisibleListener() {
@Override
public void onImeVisibleChanged(boolean visible) {
if (!visible) {
onConnectionClosed();
}
}
});
}

this.textInputChannel = textInputChannel;
Expand Down Expand Up @@ -838,4 +849,8 @@ public void autofill(@NonNull SparseArray<AutofillValue> values) {
textInputChannel.updateEditingStateWithTag(inputTarget.id, editingValues);
}
// -------- End: Autofill -------

public void onConnectionClosed() {
textInputChannel.onConnectionClosed(inputTarget.id);
}
}
Expand Up @@ -2118,6 +2118,19 @@ public void ime_windowInsetsSync() {
assertEquals(0, viewportMetricsCaptor.getValue().viewInsetTop);
}

@Test
@TargetApi(30)
@Config(sdk = 30)
public void onConnectionClosed_imeInvisible() {
View testView = new View(ctx);
TextInputChannel textInputChannel = spy(new TextInputChannel(mock(DartExecutor.class)));
TextInputPlugin textInputPlugin =
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
ImeSyncDeferringInsetsCallback imeSyncCallback = textInputPlugin.getImeSyncCallback();
imeSyncCallback.getImeVisibleListener().onImeVisibleChanged(false);
verify(textInputChannel, times(1)).onConnectionClosed(anyInt());
}

interface EventHandler {
void sendAppPrivateCommand(View view, String action, Bundle data);
}
Expand Down