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;
12import android.content.ComponentCallbacks2;
17import android.view.LayoutInflater;
20import android.view.ViewTreeObserver.OnPreDrawListener;
22import android.window.OnBackAnimationCallback;
23import androidx.annotation.NonNull;
24import androidx.annotation.Nullable;
25import androidx.annotation.RequiresApi;
26import androidx.annotation.VisibleForTesting;
27import androidx.lifecycle.Lifecycle;
28import io.flutter.Build.API_LEVELS;
29import io.flutter.FlutterInjector;
31import io.flutter.embedding.engine.FlutterEngine;
32import io.flutter.embedding.engine.FlutterEngineCache;
33import io.flutter.embedding.engine.FlutterEngineGroup;
34import io.flutter.embedding.engine.FlutterEngineGroupCache;
35import io.flutter.embedding.engine.FlutterShellArgs;
36import io.flutter.embedding.engine.dart.DartExecutor;
37import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
38import io.flutter.plugin.platform.PlatformPlugin;
39import java.util.Arrays;
76 private static final String TAG =
"FlutterActivityAndFragmentDelegate";
77 private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY =
"framework";
78 private static final String PLUGINS_RESTORATION_BUNDLE_KEY =
"plugins";
79 private static final int FLUTTER_SPLASH_VIEW_FALLBACK_ID = 486947586;
88 @NonNull
private Host host;
93 private boolean isFlutterEngineFromHost;
94 private boolean isFlutterUiDisplayed;
95 private boolean isFirstFrameRendered;
96 private boolean isAttached;
97 private Integer previousVisibility;
104 public void onFlutterUiDisplayed() {
105 host.onFlutterUiDisplayed();
106 isFlutterUiDisplayed =
true;
107 isFirstFrameRendered =
true;
111 public void onFlutterUiNoLongerDisplayed() {
112 host.onFlutterUiNoLongerDisplayed();
113 isFlutterUiDisplayed =
false;
123 this.isFirstFrameRendered =
false;
124 this.engineGroup = engineGroup;
140 this.flutterEngine =
null;
141 this.flutterView =
null;
142 this.platformPlugin =
null;
151 return flutterEngine;
159 return isFlutterEngineFromHost;
193 if (flutterEngine ==
null) {
197 if (host.shouldAttachEngineToActivity()) {
207 Log.
v(
TAG,
"Attaching FlutterEngine to the Activity that owns this delegate.");
208 flutterEngine.getActivityControlSurface().attachToActivity(
this, host.getLifecycle());
217 platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
219 host.configureFlutterEngine(flutterEngine);
225 final Activity activity = host.getActivity();
226 if (activity ==
null) {
227 throw new AssertionError(
228 "FlutterActivityAndFragmentDelegate's getAppComponent should only "
229 +
"be queried after onAttach, when the host's activity should always be non-null");
235 String appBundlePathOverride = host.getAppBundlePath();
236 if (appBundlePathOverride ==
null || appBundlePathOverride.isEmpty()) {
240 DartExecutor.DartEntrypoint dartEntrypoint =
241 new DartExecutor.DartEntrypoint(
242 appBundlePathOverride, host.getDartEntrypointFunctionName());
243 String initialRoute = host.getInitialRoute();
244 if (initialRoute ==
null) {
245 initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
246 if (initialRoute ==
null) {
247 initialRoute = DEFAULT_INITIAL_ROUTE;
251 .setDartEntrypoint(dartEntrypoint)
252 .setInitialRoute(initialRoute)
253 .setDartEntrypointArgs(host.getDartEntrypointArgs());
277 Log.
v(
TAG,
"Setting up FlutterEngine.");
280 String cachedEngineId = host.getCachedEngineId();
281 if (cachedEngineId !=
null) {
283 isFlutterEngineFromHost =
true;
284 if (flutterEngine ==
null) {
285 throw new IllegalStateException(
286 "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
294 flutterEngine = host.provideFlutterEngine(host.getContext());
295 if (flutterEngine !=
null) {
296 isFlutterEngineFromHost =
true;
302 String cachedEngineGroupId = host.getCachedEngineGroupId();
303 if (cachedEngineGroupId !=
null) {
306 if (flutterEngineGroup ==
null) {
307 throw new IllegalStateException(
308 "The requested cached FlutterEngineGroup did not exist in the FlutterEngineGroupCache: '"
309 + cachedEngineGroupId
316 isFlutterEngineFromHost =
false;
324 "No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
325 +
" this FlutterFragment.");
332 group.createAndRunEngine(
333 addEntrypointOptions(
337 isFlutterEngineFromHost =
false;
366 LayoutInflater inflater,
367 @Nullable ViewGroup container,
368 @Nullable Bundle savedInstanceState,
370 boolean shouldDelayFirstAndroidViewDraw) {
371 Log.
v(
TAG,
"Creating FlutterView.");
380 host.onFlutterSurfaceViewCreated(flutterSurfaceView);
390 host.onFlutterTextureViewCreated(flutterTextureView);
399 if (host.attachToEngineAutomatically()) {
400 Log.
v(
TAG,
"Attaching FlutterEngine to FlutterView.");
405 if (shouldDelayFirstAndroidViewDraw) {
414 "onRestoreInstanceState. Giving framework and plugins an opportunity to restore state.");
417 Bundle pluginState =
null;
418 byte[] frameworkState =
null;
419 if (bundle !=
null) {
420 pluginState = bundle.getBundle(PLUGINS_RESTORATION_BUNDLE_KEY);
421 frameworkState = bundle.getByteArray(FRAMEWORK_RESTORATION_BUNDLE_KEY);
424 if (host.shouldRestoreAndSaveState()) {
425 flutterEngine.getRestorationChannel().setRestorationData(frameworkState);
428 if (host.shouldAttachEngineToActivity()) {
429 flutterEngine.getActivityControlSurface().onRestoreInstanceState(pluginState);
447 doInitialFlutterViewRun();
453 if (previousVisibility !=
null) {
466 private void doInitialFlutterViewRun() {
468 if (host.getCachedEngineId() !=
null) {
472 if (flutterEngine.getDartExecutor().isExecutingDart()) {
478 String initialRoute = host.getInitialRoute();
479 if (initialRoute ==
null) {
480 initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
481 if (initialRoute ==
null) {
482 initialRoute = DEFAULT_INITIAL_ROUTE;
485 @Nullable String libraryUri = host.getDartEntrypointLibraryUri();
488 "Executing Dart entrypoint: "
489 + host.getDartEntrypointFunctionName()
494 : libraryUri +
", and sending initial route: " + initialRoute);
498 flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
500 String appBundlePathOverride = host.getAppBundlePath();
501 if (appBundlePathOverride ==
null || appBundlePathOverride.isEmpty()) {
502 appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
506 DartExecutor.DartEntrypoint entrypoint =
508 ?
new DartExecutor.DartEntrypoint(
509 appBundlePathOverride,
host.getDartEntrypointFunctionName())
510 :
new DartExecutor.DartEntrypoint(
511 appBundlePathOverride, libraryUri,
host.getDartEntrypointFunctionName());
512 flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint,
host.getDartEntrypointArgs());
515 private String maybeGetInitialRouteFromIntent(Intent intent) {
516 if (
host.shouldHandleDeeplinking()) {
517 Uri
data = intent.getData();
519 return data.toString();
529 if (
host.getRenderMode() != RenderMode.surface) {
534 throw new IllegalArgumentException(
535 "Cannot delay the first Android view draw when the render mode is not set to"
536 +
" `RenderMode.surface`.");
544 new OnPreDrawListener() {
546 public boolean onPreDraw() {
548 flutterView.getViewTreeObserver().removeOnPreDrawListener(
this);
551 return isFlutterUiDisplayed;
566 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
567 flutterEngine.getLifecycleChannel().appIsResumed();
585 if (flutterEngine !=
null) {
587 flutterEngine.getPlatformViewsController().onResume();
589 Log.
w(
TAG,
"onPostResume() invoked before FlutterFragment was attached to an Activity.");
598 if (platformPlugin !=
null) {
602 platformPlugin.updateSystemUiOverlays();
615 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
616 flutterEngine.getLifecycleChannel().appIsInactive();
638 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
639 flutterEngine.getLifecycleChannel().appIsPaused();
649 if (flutterEngine !=
null) {
653 flutterEngine.getRenderer().onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
680 Log.
v(
TAG,
"onSaveInstanceState. Giving framework and plugins an opportunity to save state.");
683 if (host.shouldRestoreAndSaveState()) {
685 FRAMEWORK_RESTORATION_BUNDLE_KEY,
686 flutterEngine.getRestorationChannel().getRestorationData());
689 if (host.shouldAttachEngineToActivity()) {
690 final Bundle plugins =
new Bundle();
691 flutterEngine.getActivityControlSurface().onSaveInstanceState(plugins);
692 bundle.putBundle(PLUGINS_RESTORATION_BUNDLE_KEY, plugins);
698 if (host.shouldDestroyEngineWithHost()) {
701 throw new AssertionError(
702 "The internal FlutterEngine created by "
704 +
" has been attached to by another activity. To persist a FlutterEngine beyond the "
705 +
"ownership of this activity, explicitly create a FlutterEngine");
711 host.detachFromFlutterEngine();
739 host.cleanUpFlutterEngine(flutterEngine);
741 if (host.shouldAttachEngineToActivity()) {
743 Log.
v(
TAG,
"Detaching FlutterEngine from the Activity that owns this Fragment.");
744 if (host.getActivity().isChangingConfigurations()) {
745 flutterEngine.getActivityControlSurface().detachFromActivityForConfigChanges();
747 flutterEngine.getActivityControlSurface().detachFromActivity();
754 if (platformPlugin !=
null) {
755 platformPlugin.destroy();
756 platformPlugin =
null;
759 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
760 flutterEngine.getLifecycleChannel().appIsDetached();
764 if (host.shouldDestroyEngineWithHost()) {
765 flutterEngine.destroy();
767 if (host.getCachedEngineId() !=
null) {
771 flutterEngine =
null;
787 if (flutterEngine !=
null) {
788 Log.
v(
TAG,
"Forwarding onBackPressed() to FlutterEngine.");
789 flutterEngine.getNavigationChannel().popRoute();
791 Log.
w(
TAG,
"Invoked onBackPressed() before FlutterFragment was attached to an Activity.");
811 if (flutterEngine !=
null) {
812 Log.
v(
TAG,
"Forwarding startBackGesture() to FlutterEngine.");
813 flutterEngine.getBackGestureChannel().startBackGesture(backEvent);
815 Log.
w(
TAG,
"Invoked startBackGesture() before FlutterFragment was attached to an Activity.");
834 if (flutterEngine !=
null) {
835 Log.
v(
TAG,
"Forwarding updateBackGestureProgress() to FlutterEngine.");
836 flutterEngine.getBackGestureChannel().updateBackGestureProgress(backEvent);
840 "Invoked updateBackGestureProgress() before FlutterFragment was attached to an Activity.");
859 if (flutterEngine !=
null) {
860 Log.
v(
TAG,
"Forwarding commitBackGesture() to FlutterEngine.");
861 flutterEngine.getBackGestureChannel().commitBackGesture();
863 Log.
w(
TAG,
"Invoked commitBackGesture() before FlutterFragment was attached to an Activity.");
881 if (flutterEngine !=
null) {
882 Log.
v(
TAG,
"Forwarding cancelBackGesture() to FlutterEngine.");
883 flutterEngine.getBackGestureChannel().cancelBackGesture();
885 Log.
w(
TAG,
"Invoked cancelBackGesture() before FlutterFragment was attached to an Activity.");
896 int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
898 if (flutterEngine !=
null) {
901 "Forwarding onRequestPermissionsResult() to FlutterEngine:\n"
906 + Arrays.toString(permissions)
909 + Arrays.toString(grantResults));
911 .getActivityControlSurface()
912 .onRequestPermissionsResult(requestCode, permissions, grantResults);
916 "onRequestPermissionResult() invoked before FlutterFragment was attached to an Activity.");
930 if (flutterEngine !=
null) {
933 "Forwarding onNewIntent() to FlutterEngine and sending pushRouteInformation message.");
934 flutterEngine.getActivityControlSurface().onNewIntent(intent);
935 String initialRoute = maybeGetInitialRouteFromIntent(intent);
936 if (initialRoute !=
null && !initialRoute.isEmpty()) {
937 flutterEngine.getNavigationChannel().pushRouteInformation(initialRoute);
940 Log.
w(
TAG,
"onNewIntent() invoked before FlutterFragment was attached to an Activity.");
952 if (flutterEngine !=
null) {
955 "Forwarding onActivityResult() to FlutterEngine:\n"
964 flutterEngine.getActivityControlSurface().onActivityResult(requestCode, resultCode,
data);
966 Log.
w(
TAG,
"onActivityResult() invoked before FlutterFragment was attached to an Activity.");
980 if (flutterEngine !=
null) {
981 Log.
v(
TAG,
"Forwarding onUserLeaveHint() to FlutterEngine.");
982 flutterEngine.getActivityControlSurface().onUserLeaveHint();
984 Log.
w(
TAG,
"onUserLeaveHint() invoked before FlutterFragment was attached to an Activity.");
996 Log.
v(
TAG,
"Received onWindowFocusChanged: " + (hasFocus ?
"true" :
"false"));
997 if (host.shouldDispatchAppLifecycleState() && flutterEngine !=
null) {
1002 flutterEngine.getLifecycleChannel().aWindowIsFocused();
1004 flutterEngine.getLifecycleChannel().noWindowsAreFocused();
1019 if (flutterEngine !=
null) {
1025 boolean trim = isFirstFrameRendered &&
level >= TRIM_MEMORY_RUNNING_LOW;
1027 flutterEngine.getDartExecutor().notifyLowMemoryWarning();
1028 flutterEngine.getSystemChannel().sendMemoryPressureWarning();
1030 flutterEngine.getRenderer().onTrimMemory(
level);
1031 flutterEngine.getPlatformViewsController().onTrimMemory(
level);
1040 private void ensureAlive() {
1042 throw new IllegalStateException(
1043 "Cannot execute method on a destroyed FlutterActivityAndFragmentDelegate.");
1185 @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)
static FlutterEngineCache getInstance()
FlutterEngine get(@NonNull String engineId)
void remove(@NonNull String engineId)
FlutterEngineGroup get(@NonNull String engineGroupId)
static FlutterEngineGroupCache getInstance()
Options setWaitForRestorationData(boolean waitForRestorationData)
Options setAutomaticallyRegisterPlugins(boolean automaticallyRegisterPlugins)
FlutterEngine createAndRunEngine( @NonNull Context context, @Nullable DartEntrypoint dartEntrypoint)
String findAppBundlePath()
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()
void Log(const char *format,...) SK_PRINTF_LIKE(1
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
std::shared_ptr< const fml::Mapping > data