From 82034033f14440c837c47eb0ac875dc56ccecfd0 Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Tue, 19 Nov 2024 12:09:54 -0800 Subject: [PATCH 1/8] modify interface, and add implementation for saving setFrameworkHandlesBack state --- .../io/flutter/embedding/android/FlutterActivity.java | 5 +++++ .../android/FlutterActivityAndFragmentDelegate.java | 9 +++++++++ .../io/flutter/embedding/android/FlutterFragment.java | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index f5794335b74f4..ee01169535753 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -1477,6 +1477,11 @@ public boolean attachToEngineAutomatically() { return true; } + @Override + public boolean getBackCallbackState() { + return hasRegisteredBackCallback; + } + @Override public boolean popSystemNavigator() { // Hook for subclass. No-op if returns false. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index c576eacda8c0c..e0a6d52e6cc87 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -76,6 +76,7 @@ private static final String TAG = "FlutterActivityAndFragmentDelegate"; private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework"; private static final String PLUGINS_RESTORATION_BUNDLE_KEY = "plugins"; + private static final String ON_BACK_CALLBACK_ENABLED_KEY = "enableOnBackInvokedCallbackState"; private static final int FLUTTER_SPLASH_VIEW_FALLBACK_ID = 486947586; /** Factory to obtain a FlutterActivityAndFragmentDelegate instance. */ @@ -691,6 +692,12 @@ void onSaveInstanceState(@Nullable Bundle bundle) { flutterEngine.getActivityControlSurface().onSaveInstanceState(plugins); bundle.putBundle(PLUGINS_RESTORATION_BUNDLE_KEY, plugins); } + + // If using a cached engine, we need to save whether the framework or the system should handle + // backs. + if (host.getCachedEngineId() != null) { + bundle.putBoolean(ON_BACK_CALLBACK_ENABLED_KEY, host.getBackCallbackState()); + } } @Override @@ -1297,5 +1304,7 @@ PlatformPlugin providePlatformPlugin( *

Defaults to {@code true}. */ boolean attachToEngineAutomatically(); + + boolean getBackCallbackState(); } } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index e26d13e80f74a..b3dc8cedb45ae 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1655,6 +1655,11 @@ public boolean attachToEngineAutomatically() { return true; } + @Override + public boolean getBackCallbackState() { + return onBackPressedCallback.isEnabled(); + } + /** * {@inheritDoc} * From 1e675e77eeebe581762cf7621343d46e1f728408 Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Tue, 19 Nov 2024 12:37:48 -0800 Subject: [PATCH 2/8] use the state --- .../io/flutter/embedding/android/FlutterActivity.java | 5 +++++ .../android/FlutterActivityAndFragmentDelegate.java | 2 +- .../io/flutter/embedding/android/FlutterFragment.java | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index ee01169535753..812bf518090f1 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -634,6 +634,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null && + savedInstanceState.getBoolean(FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY)) { + setFrameworkHandlesBack(true); + } + delegate = new FlutterActivityAndFragmentDelegate(this); delegate.onAttach(this); delegate.onRestoreInstanceState(savedInstanceState); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index e0a6d52e6cc87..8233ae2152184 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -76,7 +76,7 @@ private static final String TAG = "FlutterActivityAndFragmentDelegate"; private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework"; private static final String PLUGINS_RESTORATION_BUNDLE_KEY = "plugins"; - private static final String ON_BACK_CALLBACK_ENABLED_KEY = "enableOnBackInvokedCallbackState"; + static final String ON_BACK_CALLBACK_ENABLED_KEY = "enableOnBackInvokedCallbackState"; private static final int FLUTTER_SPLASH_VIEW_FALLBACK_ID = 486947586; /** Factory to obtain a FlutterActivityAndFragmentDelegate instance. */ diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index b3dc8cedb45ae..1fe75a9540275 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1071,6 +1071,10 @@ public void onAttach(@NonNull Context context) { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null && + savedInstanceState.getBoolean(FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY)) { + onBackPressedCallback.setEnabled(true); + } delegate.onRestoreInstanceState(savedInstanceState); } From 314c4ca647769bbc3baa696e51eb92f4225a8e9a Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Tue, 19 Nov 2024 12:38:22 -0800 Subject: [PATCH 3/8] format --- .../io/flutter/embedding/android/FlutterActivity.java | 5 +++-- .../io/flutter/embedding/android/FlutterFragment.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 812bf518090f1..092f9176729d2 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -634,8 +634,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (savedInstanceState != null && - savedInstanceState.getBoolean(FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY)) { + if (savedInstanceState != null + && savedInstanceState.getBoolean( + FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY)) { setFrameworkHandlesBack(true); } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 1fe75a9540275..2a29544dd581d 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1071,8 +1071,9 @@ public void onAttach(@NonNull Context context) { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (savedInstanceState != null && - savedInstanceState.getBoolean(FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY)) { + if (savedInstanceState != null + && savedInstanceState.getBoolean( + FlutterActivityAndFragmentDelegate.ON_BACK_CALLBACK_ENABLED_KEY)) { onBackPressedCallback.setEnabled(true); } delegate.onRestoreInstanceState(savedInstanceState); From 34889873ea614f8cd2e41b143f9003b2068d5d66 Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Tue, 19 Nov 2024 14:56:04 -0800 Subject: [PATCH 4/8] fix test broken by new element of host interface --- .../embedding/android/FlutterAndroidComponentTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java index 8e8c77619f887..901ac61b2a002 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java @@ -401,6 +401,11 @@ public boolean attachToEngineAutomatically() { return true; } + @Override + public boolean getBackCallbackState() { + return false; + } + @Override public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) {} From c912bf8a0f066e2089d44495e477e01c20b98d17 Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Tue, 19 Nov 2024 15:25:24 -0800 Subject: [PATCH 5/8] add a test --- .../embedding/android/FlutterActivity.java | 2 +- .../android/FlutterActivityTest.java | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 092f9176729d2..668dda306bcef 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -212,7 +212,7 @@ public class FlutterActivity extends Activity implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner { private static final String TAG = "FlutterActivity"; - private boolean hasRegisteredBackCallback = false; + @VisibleForTesting boolean hasRegisteredBackCallback = false; /** * The ID of the {@code FlutterView} created by this activity. diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java index 8833b7a96dbe3..5ae753d184efc 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java @@ -5,6 +5,7 @@ package io.flutter.embedding.android; import static io.flutter.Build.API_LEVELS; +import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_ID; import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -34,6 +35,7 @@ import androidx.annotation.RequiresApi; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; +import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import io.flutter.FlutterInjector; @@ -94,6 +96,47 @@ public void flutterViewHasId() { assertTrue(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID) instanceof FlutterView); } + @Test + @Config(sdk = API_LEVELS.API_34) + @TargetApi(API_LEVELS.API_34) + public void whenUsingCachedEngine_predictiveBackStateIsSaved() { + FlutterLoader mockFlutterLoader = mock(FlutterLoader.class); + FlutterJNI mockFlutterJni = mock(FlutterJNI.class); + when(mockFlutterJni.isAttached()).thenReturn(true); + FlutterEngine cachedEngine = new FlutterEngine(ctx, mockFlutterLoader, mockFlutterJni); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + + ActivityScenario flutterActivityScenario = + ActivityScenario.launch(FlutterActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); + flutterActivityScenario.onActivity(activity -> activity.getIntent().putExtra(EXTRA_CACHED_ENGINE_ID, "my_cached_engine")); + + flutterActivityScenario.recreate(); + flutterActivityScenario.onActivity(activity -> assertTrue(activity.hasRegisteredBackCallback)); + + // Clean up. + flutterActivityScenario.close(); + } + + @Test + @Config(sdk = API_LEVELS.API_34) + @TargetApi(API_LEVELS.API_34) + public void whenNotUsingCachedEngine_predictiveBackStateIsNotSaved() { + ActivityScenario flutterActivityScenario = + ActivityScenario.launch(FlutterActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); + + flutterActivityScenario.recreate(); + flutterActivityScenario.onActivity(activity -> assertFalse(activity.hasRegisteredBackCallback)); + + // Clean up. + flutterActivityScenario.close(); + } + // TODO(garyq): Robolectric does not yet support android api 33 yet. Switch to a robolectric // test that directly exercises the OnBackInvoked APIs when API 33 is supported. @Test From 50337ca71da220b238bcad70d61213f79f51cb8c Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Wed, 20 Nov 2024 08:53:24 -0800 Subject: [PATCH 6/8] ffa tests --- .../embedding/android/FlutterFragment.java | 2 +- .../android/FlutterFragmentActivityTest.java | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 2a29544dd581d..20fa6d492cc7e 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1009,7 +1009,7 @@ public FlutterActivityAndFragmentDelegate createDelegate( return new FlutterActivityAndFragmentDelegate(host); } - private final OnBackPressedCallback onBackPressedCallback = + @VisibleForTesting final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java index 97701775adc8e..0c16adedec039 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java @@ -5,6 +5,8 @@ package io.flutter.embedding.android; import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY; +import static io.flutter.embedding.android.FlutterFragment.ARG_CACHED_ENGINE_ID; +import static io.flutter.embedding.android.FlutterFragment.ARG_DESTROY_ENGINE_WITH_FRAGMENT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -13,6 +15,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -25,9 +28,12 @@ import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; + +import io.flutter.Build; import io.flutter.FlutterInjector; import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode; import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.embedding.engine.FlutterEngineCache; import io.flutter.embedding.engine.FlutterJNI; import io.flutter.embedding.engine.loader.FlutterLoader; import io.flutter.plugins.GeneratedPluginRegistrant; @@ -254,6 +260,60 @@ public void itHandlesNewFragmentRecreationDuringRestoreWhenActivityIsRecreated() assertEquals(0, activity.numberOfEnginesCreated); } + @Test + @Config(sdk = Build.API_LEVELS.API_34) + @TargetApi(Build.API_LEVELS.API_34) + public void whenUsingCachedEngine_predictiveBackStateIsSaved() { + FlutterLoader mockFlutterLoader = mock(FlutterLoader.class); + FlutterJNI mockFlutterJni = mock(FlutterJNI.class); + when(mockFlutterJni.isAttached()).thenReturn(true); + FlutterEngine cachedEngine = new FlutterEngine(ctx, mockFlutterLoader, mockFlutterJni); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + + ActivityScenario flutterFragmentActivityActivityScenario = + ActivityScenario.launch(FlutterFragmentActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterFragmentActivityActivityScenario.onActivity(activity -> { + FlutterFragment flutterFragment = activity.retrieveExistingFlutterFragmentIfPossible(); + flutterFragment.setFrameworkHandlesBack(true); + Bundle bundle = flutterFragment.getArguments(); + bundle.putString(ARG_CACHED_ENGINE_ID, "my_cached_engine"); + bundle.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, false); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + flutterFragment.setArguments(bundle); + }); + + flutterFragmentActivityActivityScenario.recreate(); + + flutterFragmentActivityActivityScenario.onActivity(activity -> { + assertTrue(activity + .retrieveExistingFlutterFragmentIfPossible() + .onBackPressedCallback + .isEnabled()); + }); + + // Clean up. + flutterFragmentActivityActivityScenario.close(); + } + + @Test + @Config(sdk = Build.API_LEVELS.API_34) + @TargetApi(Build.API_LEVELS.API_34) + public void whenNotUsingCachedEngine_predictiveBackStateIsNotSaved() { + ActivityScenario flutterActivityScenario = + ActivityScenario.launch(FlutterActivity.class); + + // Set to framework handling and then recreate the activity and check the state is preserved. + flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); + + flutterActivityScenario.recreate(); + flutterActivityScenario.onActivity(activity -> assertFalse(activity.hasRegisteredBackCallback)); + + // Clean up. + flutterActivityScenario.close(); + } + static class FlutterFragmentActivityWithProvidedEngine extends FlutterFragmentActivity { int numberOfEnginesCreated = 0; From 4cd8e7bc2080ec4429df109c3496421a3fe8226e Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Wed, 20 Nov 2024 08:53:54 -0800 Subject: [PATCH 7/8] format --- .../embedding/android/FlutterFragment.java | 3 +- .../android/FlutterActivityTest.java | 5 ++- .../android/FlutterFragmentActivityTest.java | 38 ++++++++++--------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 20fa6d492cc7e..c9727594b618e 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1009,7 +1009,8 @@ public FlutterActivityAndFragmentDelegate createDelegate( return new FlutterActivityAndFragmentDelegate(host); } - @VisibleForTesting final OnBackPressedCallback onBackPressedCallback = + @VisibleForTesting + final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java index 5ae753d184efc..07babd12a79ec 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java @@ -111,7 +111,8 @@ public void whenUsingCachedEngine_predictiveBackStateIsSaved() { // Set to framework handling and then recreate the activity and check the state is preserved. flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); - flutterActivityScenario.onActivity(activity -> activity.getIntent().putExtra(EXTRA_CACHED_ENGINE_ID, "my_cached_engine")); + flutterActivityScenario.onActivity( + activity -> activity.getIntent().putExtra(EXTRA_CACHED_ENGINE_ID, "my_cached_engine")); flutterActivityScenario.recreate(); flutterActivityScenario.onActivity(activity -> assertTrue(activity.hasRegisteredBackCallback)); @@ -125,7 +126,7 @@ public void whenUsingCachedEngine_predictiveBackStateIsSaved() { @TargetApi(API_LEVELS.API_34) public void whenNotUsingCachedEngine_predictiveBackStateIsNotSaved() { ActivityScenario flutterActivityScenario = - ActivityScenario.launch(FlutterActivity.class); + ActivityScenario.launch(FlutterActivity.class); // Set to framework handling and then recreate the activity and check the state is preserved. flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java index 0c16adedec039..3fc9084b8422d 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterFragmentActivityTest.java @@ -28,7 +28,6 @@ import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; - import io.flutter.Build; import io.flutter.FlutterInjector; import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode; @@ -271,27 +270,30 @@ public void whenUsingCachedEngine_predictiveBackStateIsSaved() { FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); ActivityScenario flutterFragmentActivityActivityScenario = - ActivityScenario.launch(FlutterFragmentActivity.class); + ActivityScenario.launch(FlutterFragmentActivity.class); // Set to framework handling and then recreate the activity and check the state is preserved. - flutterFragmentActivityActivityScenario.onActivity(activity -> { - FlutterFragment flutterFragment = activity.retrieveExistingFlutterFragmentIfPossible(); - flutterFragment.setFrameworkHandlesBack(true); - Bundle bundle = flutterFragment.getArguments(); - bundle.putString(ARG_CACHED_ENGINE_ID, "my_cached_engine"); - bundle.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, false); - FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); - flutterFragment.setArguments(bundle); - }); + flutterFragmentActivityActivityScenario.onActivity( + activity -> { + FlutterFragment flutterFragment = activity.retrieveExistingFlutterFragmentIfPossible(); + flutterFragment.setFrameworkHandlesBack(true); + Bundle bundle = flutterFragment.getArguments(); + bundle.putString(ARG_CACHED_ENGINE_ID, "my_cached_engine"); + bundle.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, false); + FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine); + flutterFragment.setArguments(bundle); + }); flutterFragmentActivityActivityScenario.recreate(); - flutterFragmentActivityActivityScenario.onActivity(activity -> { - assertTrue(activity - .retrieveExistingFlutterFragmentIfPossible() - .onBackPressedCallback - .isEnabled()); - }); + flutterFragmentActivityActivityScenario.onActivity( + activity -> { + assertTrue( + activity + .retrieveExistingFlutterFragmentIfPossible() + .onBackPressedCallback + .isEnabled()); + }); // Clean up. flutterFragmentActivityActivityScenario.close(); @@ -302,7 +304,7 @@ public void whenUsingCachedEngine_predictiveBackStateIsSaved() { @TargetApi(Build.API_LEVELS.API_34) public void whenNotUsingCachedEngine_predictiveBackStateIsNotSaved() { ActivityScenario flutterActivityScenario = - ActivityScenario.launch(FlutterActivity.class); + ActivityScenario.launch(FlutterActivity.class); // Set to framework handling and then recreate the activity and check the state is preserved. flutterActivityScenario.onActivity(activity -> activity.setFrameworkHandlesBack(true)); From ebb59e150524f44af17caef4105c6f30d4fc4cc5 Mon Sep 17 00:00:00 2001 From: Gray Mackall Date: Wed, 20 Nov 2024 10:11:49 -0800 Subject: [PATCH 8/8] don't keep state if engine will be destroyed --- .../embedding/android/FlutterActivityAndFragmentDelegate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 8233ae2152184..630d3dff4f4c9 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -695,7 +695,7 @@ void onSaveInstanceState(@Nullable Bundle bundle) { // If using a cached engine, we need to save whether the framework or the system should handle // backs. - if (host.getCachedEngineId() != null) { + if (host.getCachedEngineId() != null && !host.shouldDestroyEngineWithHost()) { bundle.putBoolean(ON_BACK_CALLBACK_ENABLED_KEY, host.getBackCallbackState()); } }