From 8af6f33b11938612f42ed10275c28b0e2e66723c Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 03:46:21 -0700 Subject: [PATCH 1/7] Clean up extraneous window inset call --- .../plugin/editing/TextInputPlugin.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index c11d264c21988..a254397267da3 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -32,6 +32,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; +import io.flutter.Log; import io.flutter.embedding.engine.systemchannels.TextInputChannel; import io.flutter.plugin.platform.PlatformViewsController; import java.util.HashMap; @@ -199,7 +200,8 @@ class ImeSyncDeferringInsetsCallback extends WindowInsetsAnimation.Callback private View view; private WindowInsets lastWindowInsets; - private boolean started = false; + private boolean animating = false; + private boolean needsSave = false; ImeSyncDeferringInsetsCallback( @NonNull View view, int overlayInsetTypes, int deferredInsetTypes) { @@ -212,34 +214,36 @@ class ImeSyncDeferringInsetsCallback extends WindowInsetsAnimation.Callback @Override public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) { this.view = view; - if (started) { + if (needsSave) { + // Store the view and insets for us in onEnd() below + lastWindowInsets = windowInsets; + needsSave = false; + } + if (animating) { // While animation is running, we consume the insets to prevent disrupting // the animation, which skips this implementation and calls the view's // onApplyWindowInsets directly to avoid being consumed here. return WindowInsets.CONSUMED; } - // Store the view and insets for us in onEnd() below - lastWindowInsets = windowInsets; - // If no animation is happening, pass the insets on to the view's own // inset handling. return view.onApplyWindowInsets(windowInsets); } @Override - public WindowInsetsAnimation.Bounds onStart( - WindowInsetsAnimation animation, WindowInsetsAnimation.Bounds bounds) { + public void onPrepare( + WindowInsetsAnimation animation) { if ((animation.getTypeMask() & deferredInsetTypes) != 0) { - started = true; + animating = true; + needsSave = true; } - return bounds; } @Override public WindowInsets onProgress( WindowInsets insets, List runningAnimations) { - if (!started) { + if (!animating || needsSave) { return insets; } boolean matching = false; @@ -280,10 +284,10 @@ public WindowInsets onProgress( @Override public void onEnd(WindowInsetsAnimation animation) { - if (started && (animation.getTypeMask() & deferredInsetTypes) != 0) { + if (animating && (animation.getTypeMask() & deferredInsetTypes) != 0) { // If we deferred the IME insets and an IME animation has finished, we need to reset // the flags - started = false; + animating = false; // And finally dispatch the deferred insets to the view now. // Ideally we would just call view.requestApplyInsets() and let the normal dispatch From d7dcfe583634af54d6d638551ba6194371222665 Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 04:00:54 -0700 Subject: [PATCH 2/7] Expose animating --- .../android/io/flutter/plugin/editing/TextInputPlugin.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index a254397267da3..4cf416450ceb9 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -298,6 +298,10 @@ public void onEnd(WindowInsetsAnimation animation) { } } } + + public boolean isAnimating() { + return animating; + } } @NonNull From a7c58a8d054c2b55bbdaea106650b03be81fb3a8 Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 04:06:41 -0700 Subject: [PATCH 3/7] tests --- .../io/flutter/plugin/editing/TextInputPluginTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java index 562f1f51dcf13..79ce2ee397227 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java @@ -677,6 +677,10 @@ public void ime_windowInsetsSync() { builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 40)); WindowInsets imeInsets1 = builder.build(); + builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 50)); + builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 40)); + WindowInsets imeInsets2 = builder.build(); + builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 200)); builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 0)); WindowInsets deferredInsets = builder.build(); @@ -696,6 +700,8 @@ public void ime_windowInsetsSync() { imeSyncCallback.onPrepare(animation); imeSyncCallback.onApplyWindowInsets(testView, deferredInsets); imeSyncCallback.onStart(animation, null); + // Only the final state call is saved, extra calls are passed on. + imeSyncCallback.onApplyWindowInsets(testView, imeInsets2); verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture()); // No change, as deferredInset is stored to be passed in onEnd() @@ -723,7 +729,7 @@ public void ime_windowInsetsSync() { imeSyncCallback.onEnd(animation); verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture()); - // Values should be of deferredInsets + // Values should be of deferredInsets, not imeInsets2 assertEquals(0, viewportMetricsCaptor.getValue().paddingBottom); assertEquals(10, viewportMetricsCaptor.getValue().paddingTop); assertEquals(200, viewportMetricsCaptor.getValue().viewInsetBottom); From 108ed964c3e3d21252a00cce356207a4f6170986 Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 04:11:33 -0700 Subject: [PATCH 4/7] Formatting --- .../android/io/flutter/plugin/editing/TextInputPlugin.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index 4cf416450ceb9..5820fa01d9076 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -32,7 +32,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; -import io.flutter.Log; import io.flutter.embedding.engine.systemchannels.TextInputChannel; import io.flutter.plugin.platform.PlatformViewsController; import java.util.HashMap; @@ -232,8 +231,7 @@ public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) { } @Override - public void onPrepare( - WindowInsetsAnimation animation) { + public void onPrepare(WindowInsetsAnimation animation) { if ((animation.getTypeMask() & deferredInsetTypes) != 0) { animating = true; needsSave = true; From f3328e811f310a7c34b8fbf11543cd5d710e6499 Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 11:59:09 -0700 Subject: [PATCH 5/7] Remove extra unused method --- .../android/io/flutter/plugin/editing/TextInputPlugin.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index 5820fa01d9076..8b2fb78c41e64 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -296,10 +296,6 @@ public void onEnd(WindowInsetsAnimation animation) { } } } - - public boolean isAnimating() { - return animating; - } } @NonNull From ee9331c7c7df2e689dbf93755555336a3a2f19b1 Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 12:14:42 -0700 Subject: [PATCH 6/7] More comments --- .../io/flutter/plugin/editing/TextInputPlugin.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index 8b2fb78c41e64..62abf762a4d68 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -199,7 +199,16 @@ class ImeSyncDeferringInsetsCallback extends WindowInsetsAnimation.Callback private View view; private WindowInsets lastWindowInsets; + // True when an animation that matches deferredInsetTypes is active. + // + // While this is active, this class will capture the initial window inset + // sent into lastWindowInsets by flagging needsSave to true, and will hold + // onto the intitial inset until the animation is completed, when it will + // re-dispatch the inset change. private boolean animating = false; + // When an animation begins, android sends a WindowInset with the final + // state of the animation. When needsSave is true, we know to capture this + // initial WindowInset. private boolean needsSave = false; ImeSyncDeferringInsetsCallback( @@ -214,7 +223,10 @@ class ImeSyncDeferringInsetsCallback extends WindowInsetsAnimation.Callback public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) { this.view = view; if (needsSave) { - // Store the view and insets for us in onEnd() below + // Store the view and insets for us in onEnd() below. This captured inset + // is not part of the animation and instead, represents the final state + // of the inset after the animation is completed. Thus, we defer the processing + // of this WindowInset until the animation completes. lastWindowInsets = windowInsets; needsSave = false; } From b7390ea1aee9959039c71e8e30b73e80dec4493e Mon Sep 17 00:00:00 2001 From: garyqian Date: Wed, 16 Sep 2020 12:17:52 -0700 Subject: [PATCH 7/7] More comments --- .../test/io/flutter/plugin/editing/TextInputPluginTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java index 79ce2ee397227..b038eb56000f3 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java @@ -669,6 +669,8 @@ public void ime_windowInsetsSync() { WindowInsets.Builder builder = new WindowInsets.Builder(); WindowInsets noneInsets = builder.build(); + // imeInsets0, 1, and 2 contain unique IME bottom insets, and are used + // to distinguish which insets were sent at each stage. builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 100)); builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 40)); WindowInsets imeInsets0 = builder.build();