From 515e73506ffbb06fb3ea48e8be723859e4477f99 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Sat, 15 Jan 2022 18:50:35 +0800 Subject: [PATCH 1/5] Remove/Add FlutterSurfaceView at onStop/onStart --- .../FlutterActivityAndFragmentDelegate.java | 2 ++ .../io/flutter/embedding/android/FlutterView.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 8665af6185743..b18aee83c72cd 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -388,6 +388,7 @@ void onStart() { Log.v(TAG, "onStart()"); ensureAlive(); doInitialFlutterViewRun(); + flutterView.onStart(); } /** @@ -574,6 +575,7 @@ void onStop() { Log.v(TAG, "onStop()"); ensureAlive(); flutterEngine.getLifecycleChannel().appIsPaused(); + flutterView.onStop(); } /** diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 6e858204d9dd4..9f0fab8611dfa 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1420,6 +1420,20 @@ public void autofill(SparseArray values) { textInputPlugin.autofill(values); } + // TODO add comment + /* package */ void onStart() { + if (flutterSurfaceView != null && flutterSurfaceView.getParent() == null) { + addView(flutterSurfaceView); + } + } + + // TODO add comment + /* package */ void onStop() { + if (flutterSurfaceView != null && flutterSurfaceView.getParent() != null) { + removeView(flutterSurfaceView); + } + } + /** * Listener that is notified when a {@link io.flutter.embedding.engine.FlutterEngine} is attached * to/detached from a given {@code FlutterView}. From e144a6b7b61c448f28cede0417bd84dd206d1cbf Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Sun, 16 Jan 2022 11:57:06 +0800 Subject: [PATCH 2/5] Fix unittests --- .../android/FlutterActivityAndFragmentDelegateTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 43414b4ff65d7..864a86aa35b96 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -484,6 +484,7 @@ public void itForwardsOnRequestPermissionsResultToFlutterEngine() { // --- Execute the behavior under test --- // The FlutterEngine is set up in onAttach(). delegate.onAttach(RuntimeEnvironment.application); + delegate.onCreateView(null, null, null, 0, true); // Emulate app start. delegate.onStart(); @@ -511,6 +512,7 @@ public void itForwardsOnRequestPermissionsResultToFlutterEngine() { // --- Execute the behavior under test --- // The FlutterEngine is set up in onAttach(). delegate.onAttach(RuntimeEnvironment.application); + delegate.onCreateView(null, null, null, 0, true); // Emulate app start. delegate.onStart(); @@ -538,6 +540,7 @@ public void itForwardsOnRequestPermissionsResultToFlutterEngine() { // --- Execute the behavior under test --- // The FlutterEngine is set up in onAttach(). delegate.onAttach(RuntimeEnvironment.application); + delegate.onCreateView(null, null, null, 0, true); // Emulate app start. delegate.onStart(); @@ -565,6 +568,7 @@ public void itForwardsOnRequestPermissionsResultToFlutterEngine() { // --- Execute the behavior under test --- // The FlutterEngine is set up in onAttach(). delegate.onAttach(RuntimeEnvironment.application); + delegate.onCreateView(null, null, null, 0, true); // Emulate app start. delegate.onStart(); @@ -590,6 +594,7 @@ public void itSendsdefaultInitialRouteOnStartIfNotDeepLinkingFromIntent() { // --- Execute the behavior under test --- // The FlutterEngine is set up in onAttach(). delegate.onAttach(RuntimeEnvironment.application); + delegate.onCreateView(null, null, null, 0, true); // Emulate app start. delegate.onStart(); From b44cfceccaee7d9429f451fe6a44bf45ebd6e540 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Sun, 16 Jan 2022 23:51:14 +0800 Subject: [PATCH 3/5] Tweak the code add add some unit tests --- .../FlutterActivityAndFragmentDelegate.java | 2 +- .../flutter/embedding/android/FlutterView.java | 12 ++++++------ ...FlutterActivityAndFragmentDelegateTest.java | 18 ++++++++++++++++++ .../embedding/android/FlutterViewTest.java | 12 ++++++++++++ 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index b18aee83c72cd..a0b74bedf983b 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -74,7 +74,7 @@ // to this FlutterActivityAndFragmentDelegate. @NonNull private Host host; @Nullable private FlutterEngine flutterEngine; - @Nullable private FlutterView flutterView; + @VisibleForTesting @Nullable FlutterView flutterView; @Nullable private PlatformPlugin platformPlugin; @VisibleForTesting @Nullable OnPreDrawListener activePreDrawListener; private boolean isFlutterEngineFromHost; diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 9f0fab8611dfa..781c2357dcc2d 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1420,17 +1420,17 @@ public void autofill(SparseArray values) { textInputPlugin.autofill(values); } - // TODO add comment + // Invoke this from {@code FlutterActivityAndFragmentDelegate#onStart()} /* package */ void onStart() { - if (flutterSurfaceView != null && flutterSurfaceView.getParent() == null) { - addView(flutterSurfaceView); + if (flutterSurfaceView != null) { + flutterSurfaceView.setVisibility(View.VISIBLE); } } - // TODO add comment + // Invoke this from {@code FlutterActivityAndFragmentDelegate#onStop()} /* package */ void onStop() { - if (flutterSurfaceView != null && flutterSurfaceView.getParent() != null) { - removeView(flutterSurfaceView); + if (flutterSurfaceView != null) { + flutterSurfaceView.setVisibility(View.GONE); } } diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 864a86aa35b96..90b794e9d2640 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -983,6 +983,24 @@ public void itThrowsWhenDelayingTheFirstDrawAndUsingATextureView() { }); } + @Test + public void itNotifiesFlutterViewWhenOnStartAndOnStop() { + // ---- Test setup ---- + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + + // --- Execute the behavior under test --- + delegate.onAttach(RuntimeEnvironment.application); + delegate.onCreateView(null, null, null, 0, true); + delegate.flutterView = mock(FlutterView.class); + delegate.onStart(); + // Verify that the onStart of flutterView was called. + verify(delegate.flutterView, times(1)).onStart(); + delegate.onStop(); + // Verify that the onStop of flutterView was called. + verify(delegate.flutterView, times(1)).onStop(); + } + @Test public void itDoesNotDelayTheFirstDrawWhenRequestedAndWithAProvidedSplashScreen() { when(mockHost.provideSplashScreen()) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index 7a99f5fe04cdf..f2650ffef2629 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -687,6 +687,18 @@ public void itRegistersAndUnregistersToWindowManager() { verify(windowInfoRepo, times(1)).removeWindowLayoutInfoListener(any()); } + @Test + public void itChangesSurfaceViewVisibilityWhenOnStartAndOnStop() { + Context context = Robolectric.setupActivity(Activity.class); + FlutterView flutterView = spy(new FlutterView(context)); + FlutterSurfaceView flutterSurfaceView = (FlutterSurfaceView) flutterView.renderSurface; + assertEquals(View.VISIBLE, flutterSurfaceView.getVisibility()); + flutterView.onStop(); + assertEquals(View.GONE, flutterSurfaceView.getVisibility()); + flutterView.onStart(); + assertEquals(View.VISIBLE, flutterSurfaceView.getVisibility()); + } + @Test public void itSendsHingeDisplayFeatureToFlutter() { Context context = Robolectric.setupActivity(Activity.class); From 644f990f0dd599c0c9b203275d1f3729af9fc5ff Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Wed, 19 Jan 2022 11:38:48 +0800 Subject: [PATCH 4/5] Change visibility of FlutterView when onStop/onStart --- .../FlutterActivityAndFragmentDelegate.java | 4 ++-- .../io/flutter/embedding/android/FlutterView.java | 14 -------------- .../FlutterActivityAndFragmentDelegateTest.java | 15 +++++++++------ .../embedding/android/FlutterViewTest.java | 12 ------------ 4 files changed, 11 insertions(+), 34 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index a0b74bedf983b..10218088922d5 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -388,7 +388,7 @@ void onStart() { Log.v(TAG, "onStart()"); ensureAlive(); doInitialFlutterViewRun(); - flutterView.onStart(); + flutterView.setVisibility(View.VISIBLE); } /** @@ -575,7 +575,7 @@ void onStop() { Log.v(TAG, "onStop()"); ensureAlive(); flutterEngine.getLifecycleChannel().appIsPaused(); - flutterView.onStop(); + flutterView.setVisibility(View.GONE); } /** diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 781c2357dcc2d..6e858204d9dd4 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1420,20 +1420,6 @@ public void autofill(SparseArray values) { textInputPlugin.autofill(values); } - // Invoke this from {@code FlutterActivityAndFragmentDelegate#onStart()} - /* package */ void onStart() { - if (flutterSurfaceView != null) { - flutterSurfaceView.setVisibility(View.VISIBLE); - } - } - - // Invoke this from {@code FlutterActivityAndFragmentDelegate#onStop()} - /* package */ void onStop() { - if (flutterSurfaceView != null) { - flutterSurfaceView.setVisibility(View.GONE); - } - } - /** * Listener that is notified when a {@link io.flutter.embedding.engine.FlutterEngine} is attached * to/detached from a given {@code FlutterView}. diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 90b794e9d2640..4a95816061add 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -21,6 +21,7 @@ import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.net.Uri; +import android.view.View; import androidx.annotation.NonNull; import androidx.lifecycle.Lifecycle; import io.flutter.FlutterInjector; @@ -984,7 +985,7 @@ public void itThrowsWhenDelayingTheFirstDrawAndUsingATextureView() { } @Test - public void itNotifiesFlutterViewWhenOnStartAndOnStop() { + public void itChangesFlutterViewVisibilityWhenOnStartAndOnStop() { // ---- Test setup ---- // Create the real object that we're testing. FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); @@ -992,13 +993,15 @@ public void itNotifiesFlutterViewWhenOnStartAndOnStop() { // --- Execute the behavior under test --- delegate.onAttach(RuntimeEnvironment.application); delegate.onCreateView(null, null, null, 0, true); - delegate.flutterView = mock(FlutterView.class); delegate.onStart(); - // Verify that the onStart of flutterView was called. - verify(delegate.flutterView, times(1)).onStart(); + // Verify that the flutterView is visible. + assertEquals(View.VISIBLE, delegate.flutterView.getVisibility()); delegate.onStop(); - // Verify that the onStop of flutterView was called. - verify(delegate.flutterView, times(1)).onStop(); + // Verify that the flutterView is not visible. + assertEquals(View.GONE, delegate.flutterView.getVisibility()); + delegate.onStart(); + // Verify that the flutterView is visible. + assertEquals(View.VISIBLE, delegate.flutterView.getVisibility()); } @Test diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index f2650ffef2629..7a99f5fe04cdf 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -687,18 +687,6 @@ public void itRegistersAndUnregistersToWindowManager() { verify(windowInfoRepo, times(1)).removeWindowLayoutInfoListener(any()); } - @Test - public void itChangesSurfaceViewVisibilityWhenOnStartAndOnStop() { - Context context = Robolectric.setupActivity(Activity.class); - FlutterView flutterView = spy(new FlutterView(context)); - FlutterSurfaceView flutterSurfaceView = (FlutterSurfaceView) flutterView.renderSurface; - assertEquals(View.VISIBLE, flutterSurfaceView.getVisibility()); - flutterView.onStop(); - assertEquals(View.GONE, flutterSurfaceView.getVisibility()); - flutterView.onStart(); - assertEquals(View.VISIBLE, flutterSurfaceView.getVisibility()); - } - @Test public void itSendsHingeDisplayFeatureToFlutter() { Context context = Robolectric.setupActivity(Activity.class); From 930bba29e6f63ad2e48c154cc4ebd4fe048a2779 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Thu, 20 Jan 2022 17:23:22 +0800 Subject: [PATCH 5/5] Add comments --- .../android/FlutterActivityAndFragmentDelegate.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 10218088922d5..94e6722d9ec8d 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -388,6 +388,11 @@ void onStart() { Log.v(TAG, "onStart()"); ensureAlive(); doInitialFlutterViewRun(); + // This is a workaround for a bug on some OnePlus phones. The visibility of the application + // window is still true after locking the screen on some OnePlus phones, and shows a black + // screen when unlocked. We can work around this by changing the visibility of FlutterView in + // onStart and onStop. + // See https://github.com/flutter/flutter/issues/93276 flutterView.setVisibility(View.VISIBLE); } @@ -575,6 +580,11 @@ void onStop() { Log.v(TAG, "onStop()"); ensureAlive(); flutterEngine.getLifecycleChannel().appIsPaused(); + // This is a workaround for a bug on some OnePlus phones. The visibility of the application + // window is still true after locking the screen on some OnePlus phones, and shows a black + // screen when unlocked. We can work around this by changing the visibility of FlutterView in + // onStart and onStop. + // See https://github.com/flutter/flutter/issues/93276 flutterView.setVisibility(View.GONE); }