diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 8665af6185743..94e6722d9ec8d 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; @@ -388,6 +388,12 @@ 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); } /** @@ -574,6 +580,12 @@ 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); } /** 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..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; @@ -484,6 +485,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 +513,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 +541,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 +569,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 +595,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(); @@ -978,6 +984,26 @@ public void itThrowsWhenDelayingTheFirstDrawAndUsingATextureView() { }); } + @Test + public void itChangesFlutterViewVisibilityWhenOnStartAndOnStop() { + // ---- 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.onStart(); + // Verify that the flutterView is visible. + assertEquals(View.VISIBLE, delegate.flutterView.getVisibility()); + delegate.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 public void itDoesNotDelayTheFirstDrawWhenRequestedAndWithAProvidedSplashScreen() { when(mockHost.provideSplashScreen())