5package io.flutter.embedding.android;
7import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
8import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
10import android.annotation.TargetApi;
16import android.view.LayoutInflater;
19import android.view.ViewTreeObserver.OnPreDrawListener;
21import android.window.OnBackAnimationCallback;
22import androidx.annotation.NonNull;
23import androidx.annotation.Nullable;
24import androidx.annotation.RequiresApi;
25import androidx.annotation.VisibleForTesting;
26import androidx.lifecycle.Lifecycle;
27import io.flutter.Build.API_LEVELS;
28import io.flutter.FlutterInjector;
30import io.flutter.embedding.engine.FlutterEngine;
31import io.flutter.embedding.engine.FlutterEngineCache;
32import io.flutter.embedding.engine.FlutterEngineGroup;
33import io.flutter.embedding.engine.FlutterEngineGroupCache;
34import io.flutter.embedding.engine.FlutterShellArgs;
35import io.flutter.embedding.engine.dart.DartExecutor;
36import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
37import io.flutter.plugin.platform.PlatformPlugin;
38import java.util.Arrays;
75 private static final String TAG =
"FlutterActivityAndFragmentDelegate";
76 private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY =
"framework";
77 private static final String PLUGINS_RESTORATION_BUNDLE_KEY =
"plugins";
78 private static final int FLUTTER_SPLASH_VIEW_FALLBACK_ID = 486947586;
87 @NonNull
private Host host;
90 @Nullable
private PlatformPlugin platformPlugin;
92 private boolean isFlutterEngineFromHost;
93 private boolean isFlutterUiDisplayed;
94 private boolean isFirstFrameRendered;
95 private boolean isAttached;
96 private Integer previousVisibility;
100 private final FlutterUiDisplayListener flutterUiDisplayListener =
101 new FlutterUiDisplayListener() {
103 public void onFlutterUiDisplayed() {
104 host.onFlutterUiDisplayed();
105 isFlutterUiDisplayed =
true;
106 isFirstFrameRendered =
true;
110 public void onFlutterUiNoLongerDisplayed() {
111 host.onFlutterUiNoLongerDisplayed();
112 isFlutterUiDisplayed =
false;
122 this.isFirstFrameRendered =
false;
123 this.engineGroup = engineGroup;
139 this.flutterEngine =
null;
140 this.flutterView =
null;
141 this.platformPlugin =
null;
150 return flutterEngine;
158 return isFlutterEngineFromHost;
192 if (flutterEngine ==
null) {
196 if (host.shouldAttachEngineToActivity()) {
206 Log.
v(
TAG,
"Attaching FlutterEngine to the Activity that owns this delegate.");
207 flutterEngine.getActivityControlSurface().attachToActivity(
this, host.getLifecycle());
216 platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
218 host.configureFlutterEngine(flutterEngine);
224 final Activity activity = host.getActivity();
225 if (activity ==
null) {
226 throw new AssertionError(
227 "FlutterActivityAndFragmentDelegate's getAppComponent should only "
228 +
"be queried after onAttach, when the host's activity should always be non-null");
234 String appBundlePathOverride = host.getAppBundlePath();
235 if (appBundlePathOverride ==
null || appBundlePathOverride.isEmpty()) {
236 appBundlePathOverride =
FlutterInjector.instance().flutterLoader().findAppBundlePath();
239 DartExecutor.DartEntrypoint dartEntrypoint =
240 new DartExecutor.DartEntrypoint(
241 appBundlePathOverride, host.getDartEntrypointFunctionName());
242 String initialRoute = host.getInitialRoute();
243 if (initialRoute ==
null) {
244 initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
245 if (initialRoute ==
null) {
246 initialRoute = DEFAULT_INITIAL_ROUTE;
250 .setDartEntrypoint(dartEntrypoint)
251 .setInitialRoute(initialRoute)
252 .setDartEntrypointArgs(host.getDartEntrypointArgs());
276 Log.
v(
TAG,
"Setting up FlutterEngine.");
279 String cachedEngineId = host.getCachedEngineId();
280 if (cachedEngineId !=
null) {
281 flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
282 isFlutterEngineFromHost =
true;
283 if (flutterEngine ==
null) {
284 throw new IllegalStateException(
285 "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
293 flutterEngine = host.provideFlutterEngine(host.getContext());
294 if (flutterEngine !=
null) {
295 isFlutterEngineFromHost =
true;
301 String cachedEngineGroupId = host.getCachedEngineGroupId();
302 if (cachedEngineGroupId !=
null) {
304 FlutterEngineGroupCache.getInstance().get(cachedEngineGroupId);
305 if (flutterEngineGroup ==
null) {
306 throw new IllegalStateException(
307 "The requested cached FlutterEngineGroup did not exist in the FlutterEngineGroupCache: '"
308 + cachedEngineGroupId
313 flutterEngineGroup.createAndRunEngine(
315 isFlutterEngineFromHost =
false;
323 "No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
324 +
" this FlutterFragment.");
331 group.createAndRunEngine(
332 addEntrypointOptions(
334 .setAutomaticallyRegisterPlugins(
false)
335 .setWaitForRestorationData(host.shouldRestoreAndSaveState())));
336 isFlutterEngineFromHost =
false;
365 LayoutInflater inflater,
366 @Nullable ViewGroup container,
367 @Nullable Bundle savedInstanceState,
369 boolean shouldDelayFirstAndroidViewDraw) {
370 Log.
v(
TAG,
"Creating FlutterView.");
379 host.onFlutterSurfaceViewCreated(flutterSurfaceView);
389 host.onFlutterTextureViewCreated(flutterTextureView);
398 if (host.attachToEngineAutomatically()) {
399 Log.
v(
TAG,
"Attaching FlutterEngine to FlutterView.");
404 if (shouldDelayFirstAndroidViewDraw) {
413 "onRestoreInstanceState. Giving framework and plugins an opportunity to restore state.");
416 Bundle pluginState =
null;
417 byte[] frameworkState =
null;
418 if (bundle !=
null) {
419 pluginState = bundle.getBundle(PLUGINS_RESTORATION_BUNDLE_KEY);
420 frameworkState = bundle.getByteArray(FRAMEWORK_RESTORATION_BUNDLE_KEY);
423 if (host.shouldRestoreAndSaveState()) {
424 flutterEngine.getRestorationChannel().setRestorationData(frameworkState);
427 if (host.shouldAttachEngineToActivity()) {
428 flutterEngine.getActivityControlSurface().onRestoreInstanceState(pluginState);
446 doInitialFlutterViewRun();
452 if (previousVisibility !=
null) {
465 private void doInitialFlutterViewRun() {
467 if (host.getCachedEngineId() !=
null) {
471 if (flutterEngine.getDartExecutor().isExecutingDart()) {
477 String initialRoute = host.getInitialRoute();
478 if (initialRoute ==
null) {
479 initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
480 if (initialRoute ==
null) {
481 initialRoute = DEFAULT_INITIAL_ROUTE;
484 @Nullable String libraryUri = host.getDartEntrypointLibraryUri();
487 "Executing Dart entrypoint: "
488 + host.getDartEntrypointFunctionName()
493 : libraryUri +
", and sending initial route: " + initialRoute);
497 flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
499 String appBundlePathOverride = host.getAppBundlePath();
500 if (appBundlePathOverride ==
null || appBundlePathOverride.isEmpty()) {
501 appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
505 DartExecutor.DartEntrypoint entrypoint =
507 ?
new DartExecutor.DartEntrypoint(
508 appBundlePathOverride,
host.getDartEntrypointFunctionName())
509 :
new DartExecutor.DartEntrypoint(
510 appBundlePathOverride, libraryUri,
host.getDartEntrypointFunctionName());
511 flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint,
host.getDartEntrypointArgs());
514 private String maybeGetInitialRouteFromIntent(Intent intent) {
515 if (
host.shouldHandleDeeplinking()) {
516 Uri
data = intent.getData();
518 return data.toString();
528 if (
host.getRenderMode() != RenderMode.surface) {
533 throw new IllegalArgumentException(
534 "Cannot delay the first Android view draw when the render mode is not set to"
535 +
" `RenderMode.surface`.");
543 new OnPreDrawListener() {
545 public boolean onPreDraw() {
547 flutterView.getViewTreeObserver().removeOnPreDrawListener(
this);
550 return isFlutterUiDisplayed;
565 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
566 flutterEngine.getLifecycleChannel().appIsResumed();
584 if (flutterEngine !=
null) {
587 Log.
w(
TAG,
"onPostResume() invoked before FlutterFragment was attached to an Activity.");
596 if (platformPlugin !=
null) {
600 platformPlugin.updateSystemUiOverlays();
613 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
614 flutterEngine.getLifecycleChannel().appIsInactive();
636 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
637 flutterEngine.getLifecycleChannel().appIsPaused();
672 Log.
v(
TAG,
"onSaveInstanceState. Giving framework and plugins an opportunity to save state.");
675 if (host.shouldRestoreAndSaveState()) {
677 FRAMEWORK_RESTORATION_BUNDLE_KEY,
678 flutterEngine.getRestorationChannel().getRestorationData());
681 if (host.shouldAttachEngineToActivity()) {
682 final Bundle plugins =
new Bundle();
683 flutterEngine.getActivityControlSurface().onSaveInstanceState(plugins);
684 bundle.putBundle(PLUGINS_RESTORATION_BUNDLE_KEY, plugins);
690 if (host.shouldDestroyEngineWithHost()) {
693 throw new AssertionError(
694 "The internal FlutterEngine created by "
696 +
" has been attached to by another activity. To persist a FlutterEngine beyond the "
697 +
"ownership of this activity, explicitly create a FlutterEngine");
703 host.detachFromFlutterEngine();
731 host.cleanUpFlutterEngine(flutterEngine);
733 if (host.shouldAttachEngineToActivity()) {
735 Log.
v(
TAG,
"Detaching FlutterEngine from the Activity that owns this Fragment.");
736 if (host.getActivity().isChangingConfigurations()) {
737 flutterEngine.getActivityControlSurface().detachFromActivityForConfigChanges();
739 flutterEngine.getActivityControlSurface().detachFromActivity();
746 if (platformPlugin !=
null) {
747 platformPlugin.destroy();
748 platformPlugin =
null;
751 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
752 flutterEngine.getLifecycleChannel().appIsDetached();
756 if (host.shouldDestroyEngineWithHost()) {
757 flutterEngine.destroy();
759 if (host.getCachedEngineId() !=
null) {
760 FlutterEngineCache.getInstance().remove(host.getCachedEngineId());
763 flutterEngine =
null;
779 if (flutterEngine !=
null) {
780 Log.
v(
TAG,
"Forwarding onBackPressed() to FlutterEngine.");
781 flutterEngine.getNavigationChannel().popRoute();
783 Log.
w(
TAG,
"Invoked onBackPressed() before FlutterFragment was attached to an Activity.");
799 @TargetApi(API_LEVELS.API_34)
800 @RequiresApi(API_LEVELS.API_34)
803 if (flutterEngine !=
null) {
804 Log.
v(
TAG,
"Forwarding startBackGesture() to FlutterEngine.");
805 flutterEngine.getBackGestureChannel().startBackGesture(backEvent);
807 Log.
w(
TAG,
"Invoked startBackGesture() before FlutterFragment was attached to an Activity.");
822 @TargetApi(API_LEVELS.API_34)
823 @RequiresApi(API_LEVELS.API_34)
826 if (flutterEngine !=
null) {
827 Log.
v(
TAG,
"Forwarding updateBackGestureProgress() to FlutterEngine.");
828 flutterEngine.getBackGestureChannel().updateBackGestureProgress(backEvent);
832 "Invoked updateBackGestureProgress() before FlutterFragment was attached to an Activity.");
847 @TargetApi(API_LEVELS.API_34)
848 @RequiresApi(API_LEVELS.API_34)
851 if (flutterEngine !=
null) {
852 Log.
v(
TAG,
"Forwarding commitBackGesture() to FlutterEngine.");
853 flutterEngine.getBackGestureChannel().commitBackGesture();
855 Log.
w(
TAG,
"Invoked commitBackGesture() before FlutterFragment was attached to an Activity.");
869 @TargetApi(API_LEVELS.API_34)
870 @RequiresApi(API_LEVELS.API_34)
873 if (flutterEngine !=
null) {
874 Log.
v(
TAG,
"Forwarding cancelBackGesture() to FlutterEngine.");
875 flutterEngine.getBackGestureChannel().cancelBackGesture();
877 Log.
w(
TAG,
"Invoked cancelBackGesture() before FlutterFragment was attached to an Activity.");
888 int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
890 if (flutterEngine !=
null) {
893 "Forwarding onRequestPermissionsResult() to FlutterEngine:\n"
898 + Arrays.toString(permissions)
901 + Arrays.toString(grantResults));
903 .getActivityControlSurface()
904 .onRequestPermissionsResult(requestCode, permissions, grantResults);
908 "onRequestPermissionResult() invoked before FlutterFragment was attached to an Activity.");
922 if (flutterEngine !=
null) {
925 "Forwarding onNewIntent() to FlutterEngine and sending pushRouteInformation message.");
926 flutterEngine.getActivityControlSurface().onNewIntent(intent);
927 String initialRoute = maybeGetInitialRouteFromIntent(intent);
928 if (initialRoute !=
null && !initialRoute.isEmpty()) {
929 flutterEngine.getNavigationChannel().pushRouteInformation(initialRoute);
932 Log.
w(
TAG,
"onNewIntent() invoked before FlutterFragment was attached to an Activity.");
944 if (flutterEngine !=
null) {
947 "Forwarding onActivityResult() to FlutterEngine:\n"
956 flutterEngine.getActivityControlSurface().onActivityResult(requestCode, resultCode, data);
958 Log.
w(
TAG,
"onActivityResult() invoked before FlutterFragment was attached to an Activity.");
972 if (flutterEngine !=
null) {
973 Log.
v(
TAG,
"Forwarding onUserLeaveHint() to FlutterEngine.");
974 flutterEngine.getActivityControlSurface().onUserLeaveHint();
976 Log.
w(
TAG,
"onUserLeaveHint() invoked before FlutterFragment was attached to an Activity.");
988 Log.
v(
TAG,
"Received onWindowFocusChanged: " + (hasFocus ?
"true" :
"false"));
989 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
994 flutterEngine.getLifecycleChannel().aWindowIsFocused();
996 flutterEngine.getLifecycleChannel().noWindowsAreFocused();
1011 if (flutterEngine !=
null) {
1017 boolean trim = isFirstFrameRendered && level >= TRIM_MEMORY_RUNNING_LOW;
1019 flutterEngine.getDartExecutor().notifyLowMemoryWarning();
1020 flutterEngine.getSystemChannel().sendMemoryPressureWarning();
1022 flutterEngine.getRenderer().onTrimMemory(level);
1031 private void ensureAlive() {
1033 throw new IllegalStateException(
1034 "Cannot execute method on a destroyed FlutterActivityAndFragmentDelegate.");
1045 PlatformPlugin.PlatformPluginDelegate {
1176 @Nullable Activity activity, @NonNull
FlutterEngine flutterEngine);
static SkCanvas * trim(SkCanvas *canvas, SkScalar width, SkScalar height, const SkRect *content)
static void v(@NonNull String tag, @NonNull String message)
static void w(@NonNull String tag, @NonNull String message)
View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState, int flutterViewId, boolean shouldDelayFirstAndroidViewDraw)
void onActivityResult(int requestCode, int resultCode, Intent data)
OnPreDrawListener activePreDrawListener
void updateSystemUiOverlays()
FlutterActivityAndFragmentDelegate(@NonNull Host host)
Activity getAppComponent()
FlutterActivityAndFragmentDelegate(@NonNull Host host, @Nullable FlutterEngineGroup engineGroup)
void updateBackGestureProgress(@NonNull BackEvent backEvent)
void onAttach(@NonNull Context context)
void startBackGesture(@NonNull BackEvent backEvent)
void onTrimMemory(int level)
void onSaveInstanceState(@Nullable Bundle bundle)
boolean isFlutterEngineFromHost()
void onRestoreInstanceState(@Nullable Bundle bundle)
void onWindowFocusChanged(boolean hasFocus)
void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
void onNewIntent(@NonNull Intent intent)
void detachFromFlutterEngine()
void setUpFlutterEngine()
FlutterEngine getFlutterEngine()
void removeOnFirstFrameRenderedListener(@NonNull FlutterUiDisplayListener listener)
void detachFromFlutterEngine()
void addOnFirstFrameRenderedListener(@NonNull FlutterUiDisplayListener listener)
void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine)
FlutterActivityAndFragmentDelegate createDelegate(FlutterActivityAndFragmentDelegate.Host host)
void detachFromFlutterEngine()
ExclusiveAppComponent< Activity > getExclusiveAppComponent()
void onFlutterUiDisplayed()
PlatformPlugin providePlatformPlugin( @Nullable Activity activity, @NonNull FlutterEngine flutterEngine)
boolean shouldDispatchAppLifecycleState()
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine)
void updateSystemUiOverlays()
void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView)
RenderMode getRenderMode()
void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView)
boolean attachToEngineAutomatically()
String getCachedEngineGroupId()
boolean shouldRestoreAndSaveState()
boolean shouldAttachEngineToActivity()
String getCachedEngineId()
boolean shouldDestroyEngineWithHost()
String getDartEntrypointFunctionName()
FlutterShellArgs getFlutterShellArgs()
String getDartEntrypointLibraryUri()
List< String > getDartEntrypointArgs()
void onFlutterUiNoLongerDisplayed()
String getAppBundlePath()
FlutterEngine provideFlutterEngine(@NonNull Context context)
TransparencyMode getTransparencyMode()
void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine)
boolean shouldHandleDeeplinking()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service host
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data