5package io.flutter.embedding.android;
8import android.content.ComponentCallbacks2;
12import android.view.LayoutInflater;
15import android.view.ViewTreeObserver.OnWindowFocusChangeListener;
16import androidx.activity.OnBackPressedCallback;
17import androidx.annotation.NonNull;
18import androidx.annotation.Nullable;
19import androidx.annotation.VisibleForTesting;
20import androidx.fragment.app.Fragment;
21import androidx.fragment.app.FragmentActivity;
22import androidx.lifecycle.Lifecycle;
24import io.flutter.embedding.engine.FlutterEngine;
25import io.flutter.embedding.engine.FlutterShellArgs;
26import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
27import io.flutter.plugin.platform.PlatformPlugin;
28import java.util.ArrayList;
109 private static final String TAG =
"FlutterFragment";
125 "should_delay_first_android_view_draw";
141 "should_attach_engine_to_activity";
168 "should_automatically_handle_on_back_pressed";
170 private final OnWindowFocusChangeListener onWindowFocusChangeListener =
171 new OnWindowFocusChangeListener() {
173 public void onWindowFocusChanged(
boolean hasFocus) {
174 if (stillAttachedForEvent(
"onWindowFocusChanged")) {
246 private final Class<? extends FlutterFragment> fragmentClass;
247 private String dartEntrypoint =
"main";
248 private String dartLibraryUri =
null;
250 private String initialRoute =
"/";
251 private boolean handleDeeplinking =
false;
252 private String appBundlePath =
null;
256 private boolean shouldAttachEngineToActivity =
true;
257 private boolean shouldAutomaticallyHandleOnBackPressed =
false;
258 private boolean shouldDelayFirstAndroidViewDraw =
false;
273 fragmentClass = subclass;
279 this.dartEntrypoint = dartEntrypoint;
285 this.dartLibraryUri = dartLibraryUri;
292 this.dartEntrypointArgs = dartEntrypointArgs;
302 this.initialRoute = initialRoute;
312 this.handleDeeplinking = handleDeeplinking;
323 this.appBundlePath = appBundlePath;
330 this.shellArgs = shellArgs;
342 this.renderMode = renderMode;
355 this.transparencyMode = transparencyMode;
398 boolean shouldAttachEngineToActivity) {
399 this.shouldAttachEngineToActivity = shouldAttachEngineToActivity;
420 boolean shouldAutomaticallyHandleOnBackPressed) {
421 this.shouldAutomaticallyHandleOnBackPressed = shouldAutomaticallyHandleOnBackPressed;
432 boolean shouldDelayFirstAndroidViewDraw) {
433 this.shouldDelayFirstAndroidViewDraw = shouldDelayFirstAndroidViewDraw;
445 Bundle
args =
new Bundle();
451 args.putStringArrayList(
453 dartEntrypointArgs !=
null ?
new ArrayList(dartEntrypointArgs) :
null);
456 if (
null != shellArgs) {
478 public <T extends FlutterFragment>
T build() {
480 @SuppressWarnings(
"unchecked")
481 T frag = (
T) fragmentClass.getDeclaredConstructor().newInstance();
483 throw new RuntimeException(
484 "The FlutterFragment subclass sent in the constructor ("
485 + fragmentClass.getCanonicalName()
486 +
") does not match the expected return type.");
490 frag.setArguments(
args);
493 }
catch (Exception
e) {
494 throw new RuntimeException(
495 "Could not instantiate FlutterFragment subclass (" + fragmentClass.getName() +
")",
e);
548 private final Class<? extends FlutterFragment> fragmentClass;
549 private final String engineId;
550 private boolean destroyEngineWithFragment =
false;
551 private boolean handleDeeplinking =
false;
554 private boolean shouldAttachEngineToActivity =
true;
555 private boolean shouldAutomaticallyHandleOnBackPressed =
false;
556 private boolean shouldDelayFirstAndroidViewDraw =
false;
563 @NonNull Class<? extends FlutterFragment> subclass, @NonNull String engineId) {
564 this.fragmentClass = subclass;
565 this.engineId = engineId;
575 boolean destroyEngineWithFragment) {
576 this.destroyEngineWithFragment = destroyEngineWithFragment;
588 this.renderMode = renderMode;
602 this.transparencyMode = transparencyMode;
612 this.handleDeeplinking = handleDeeplinking;
655 boolean shouldAttachEngineToActivity) {
656 this.shouldAttachEngineToActivity = shouldAttachEngineToActivity;
677 boolean shouldAutomaticallyHandleOnBackPressed) {
678 this.shouldAutomaticallyHandleOnBackPressed = shouldAutomaticallyHandleOnBackPressed;
689 @NonNull
boolean shouldDelayFirstAndroidViewDraw) {
690 this.shouldDelayFirstAndroidViewDraw = shouldDelayFirstAndroidViewDraw;
702 Bundle
args =
new Bundle();
724 public <T extends FlutterFragment>
T build() {
726 @SuppressWarnings(
"unchecked")
727 T frag = (
T) fragmentClass.getDeclaredConstructor().newInstance();
729 throw new RuntimeException(
730 "The FlutterFragment subclass sent in the constructor ("
731 + fragmentClass.getCanonicalName()
732 +
") does not match the expected return type.");
736 frag.setArguments(
args);
739 }
catch (Exception
e) {
740 throw new RuntimeException(
741 "Could not instantiate FlutterFragment subclass (" + fragmentClass.getName() +
")",
e);
758 @NonNull String engineGroupId) {
793 private final Class<? extends FlutterFragment> fragmentClass;
794 private final String cachedEngineGroupId;
795 private @NonNull String dartEntrypoint =
"main";
796 private @NonNull String initialRoute =
"/";
797 private @NonNull
boolean handleDeeplinking =
false;
800 private boolean shouldAttachEngineToActivity =
true;
801 private boolean shouldAutomaticallyHandleOnBackPressed =
false;
802 private boolean shouldDelayFirstAndroidViewDraw =
false;
809 @NonNull Class<? extends FlutterFragment> fragmentClass, @NonNull String engineGroupId) {
810 this.fragmentClass = fragmentClass;
811 this.cachedEngineGroupId = engineGroupId;
817 this.dartEntrypoint = dartEntrypoint;
827 this.initialRoute = initialRoute;
837 this.handleDeeplinking = handleDeeplinking;
849 this.renderMode = renderMode;
863 this.transparencyMode = transparencyMode;
906 boolean shouldAttachEngineToActivity) {
907 this.shouldAttachEngineToActivity = shouldAttachEngineToActivity;
928 boolean shouldAutomaticallyHandleOnBackPressed) {
929 this.shouldAutomaticallyHandleOnBackPressed = shouldAutomaticallyHandleOnBackPressed;
940 @NonNull
boolean shouldDelayFirstAndroidViewDraw) {
941 this.shouldDelayFirstAndroidViewDraw = shouldDelayFirstAndroidViewDraw;
953 Bundle
args =
new Bundle();
977 public <T extends FlutterFragment>
T build() {
979 @SuppressWarnings(
"unchecked")
980 T frag = (
T) fragmentClass.getDeclaredConstructor().newInstance();
982 throw new RuntimeException(
983 "The FlutterFragment subclass sent in the constructor ("
984 + fragmentClass.getCanonicalName()
985 +
") does not match the expected return type.");
989 frag.setArguments(
args);
992 }
catch (Exception
e) {
993 throw new RuntimeException(
994 "Could not instantiate FlutterFragment subclass (" + fragmentClass.getName() +
")",
e);
1004 @NonNull
private FlutterActivityAndFragmentDelegate.DelegateFactory delegateFactory =
this;
1012 private final OnBackPressedCallback onBackPressedCallback =
1013 new OnBackPressedCallback(
true) {
1015 public void handleOnBackPressed() {
1023 setArguments(
new Bundle());
1039 this.delegateFactory = delegateFactory;
1040 delegate = delegateFactory.createDelegate(
this);
1054 super.onAttach(context);
1055 delegate = delegateFactory.createDelegate(
this);
1058 requireActivity().getOnBackPressedDispatcher().addCallback(
this, onBackPressedCallback);
1066 onBackPressedCallback.setEnabled(
false);
1068 context.registerComponentCallbacks(
this);
1072 public void onCreate(@Nullable Bundle savedInstanceState) {
1073 super.onCreate(savedInstanceState);
1080 LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
1092 if (stillAttachedForEvent(
"onStart")) {
1100 if (stillAttachedForEvent(
"onResume")) {
1107 @ActivityCallThrough
1109 if (stillAttachedForEvent(
"onPostResume")) {
1117 if (stillAttachedForEvent(
"onPause")) {
1125 if (stillAttachedForEvent(
"onStop")) {
1132 super.onViewCreated(view, savedInstanceState);
1133 view.getViewTreeObserver().addOnWindowFocusChangeListener(onWindowFocusChangeListener);
1138 super.onDestroyView();
1140 .getViewTreeObserver()
1141 .removeOnWindowFocusChangeListener(onWindowFocusChangeListener);
1142 if (stillAttachedForEvent(
"onDestroyView")) {
1149 super.onSaveInstanceState(outState);
1150 if (stillAttachedForEvent(
"onSaveInstanceState")) {
1161 +
" connection to the engine "
1163 +
" evicted by another attaching activity");
1173 getContext().unregisterComponentCallbacks(
this);
1180 Log.
v(
TAG,
"FlutterFragment " +
this +
" onDetach called after release.");
1195 @ActivityCallThrough
1197 int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
1198 if (stillAttachedForEvent(
"onRequestPermissionsResult")) {
1213 @ActivityCallThrough
1215 if (stillAttachedForEvent(
"onNewIntent")) {
1228 @ActivityCallThrough
1230 if (stillAttachedForEvent(
"onBackPressed")) {
1247 if (stillAttachedForEvent(
"onActivityResult")) {
1258 @ActivityCallThrough
1260 if (stillAttachedForEvent(
"onUserLeaveHint")) {
1276 if (stillAttachedForEvent(
"onTrimMemory")) {
1291 flutterShellArgsArray !=
null ? flutterShellArgsArray :
new String[] {});
1321 return delegate.isFlutterEngineFromHost();
1333 boolean explicitDestructionRequested =
1337 return explicitDestructionRequested;
1425 String renderModeName =
1441 String transparencyModeName =
1473 FragmentActivity attachedActivity =
getActivity();
1476 Log.
v(
TAG,
"Deferring to attached Activity to provide a FlutterEngine.");
1481 return flutterEngine;
1496 @Nullable Activity activity, @NonNull
FlutterEngine flutterEngine) {
1497 if (activity !=
null) {
1526 FragmentActivity attachedActivity =
getActivity();
1540 FragmentActivity attachedActivity =
getActivity();
1589 FragmentActivity attachedActivity =
getActivity();
1608 FragmentActivity attachedActivity =
getActivity();
1670 if (activity !=
null) {
1674 boolean enabledAtStart = onBackPressedCallback.isEnabled();
1675 if (enabledAtStart) {
1676 onBackPressedCallback.setEnabled(
false);
1678 activity.getOnBackPressedDispatcher().onBackPressed();
1679 if (enabledAtStart) {
1680 onBackPressedCallback.setEnabled(
true);
1694 onBackPressedCallback.setEnabled(frameworkHandlesBack);
1703 private boolean stillAttachedForEvent(String
event) {
1705 Log.
w(TAG,
"FlutterFragment " + hashCode() +
" " +
event +
" called after release.");
1709 Log.
w(TAG,
"FlutterFragment " + hashCode() +
" " +
event +
" called after detach.");
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)
void updateSystemUiOverlays()
void onAttach(@NonNull Context context)
void onTrimMemory(int level)
void onSaveInstanceState(@Nullable Bundle bundle)
void onRestoreInstanceState(@Nullable Bundle bundle)
void onWindowFocusChanged(boolean hasFocus)
void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
void onNewIntent(@NonNull Intent intent)
FlutterEngine getFlutterEngine()
CachedEngineFragmentBuilder shouldAutomaticallyHandleOnBackPressed(boolean shouldAutomaticallyHandleOnBackPressed)
CachedEngineFragmentBuilder destroyEngineWithFragment(boolean destroyEngineWithFragment)
CachedEngineFragmentBuilder renderMode(@NonNull RenderMode renderMode)
CachedEngineFragmentBuilder shouldDelayFirstAndroidViewDraw( @NonNull boolean shouldDelayFirstAndroidViewDraw)
CachedEngineFragmentBuilder( @NonNull Class<? extends FlutterFragment > subclass, @NonNull String engineId)
CachedEngineFragmentBuilder transparencyMode( @NonNull TransparencyMode transparencyMode)
CachedEngineFragmentBuilder shouldAttachEngineToActivity(boolean shouldAttachEngineToActivity)
public< T extends FlutterFragment > T build()
CachedEngineFragmentBuilder handleDeeplinking(@NonNull Boolean handleDeeplinking)
public< T extends FlutterFragment > T build()
NewEngineFragmentBuilder renderMode(@NonNull RenderMode renderMode)
NewEngineFragmentBuilder initialRoute(@NonNull String initialRoute)
NewEngineFragmentBuilder shouldDelayFirstAndroidViewDraw(boolean shouldDelayFirstAndroidViewDraw)
NewEngineFragmentBuilder()
NewEngineFragmentBuilder transparencyMode(@NonNull TransparencyMode transparencyMode)
NewEngineFragmentBuilder(@NonNull Class<? extends FlutterFragment > subclass)
NewEngineFragmentBuilder handleDeeplinking(@NonNull Boolean handleDeeplinking)
NewEngineFragmentBuilder dartEntrypointArgs(@NonNull List< String > dartEntrypointArgs)
NewEngineFragmentBuilder dartEntrypoint(@NonNull String dartEntrypoint)
NewEngineFragmentBuilder flutterShellArgs(@NonNull FlutterShellArgs shellArgs)
NewEngineFragmentBuilder shouldAutomaticallyHandleOnBackPressed(boolean shouldAutomaticallyHandleOnBackPressed)
NewEngineFragmentBuilder shouldAttachEngineToActivity(boolean shouldAttachEngineToActivity)
NewEngineFragmentBuilder dartLibraryUri(@NonNull String dartLibraryUri)
NewEngineFragmentBuilder appBundlePath(@NonNull String appBundlePath)
public< T extends FlutterFragment > T build()
NewEngineInGroupFragmentBuilder handleDeeplinking(@NonNull boolean handleDeeplinking)
NewEngineInGroupFragmentBuilder initialRoute(@NonNull String initialRoute)
NewEngineInGroupFragmentBuilder(@NonNull String engineGroupId)
NewEngineInGroupFragmentBuilder( @NonNull Class<? extends FlutterFragment > fragmentClass, @NonNull String engineGroupId)
NewEngineInGroupFragmentBuilder shouldDelayFirstAndroidViewDraw( @NonNull boolean shouldDelayFirstAndroidViewDraw)
NewEngineInGroupFragmentBuilder renderMode(@NonNull RenderMode renderMode)
NewEngineInGroupFragmentBuilder shouldAutomaticallyHandleOnBackPressed(boolean shouldAutomaticallyHandleOnBackPressed)
NewEngineInGroupFragmentBuilder transparencyMode( @NonNull TransparencyMode transparencyMode)
NewEngineInGroupFragmentBuilder dartEntrypoint(@NonNull String dartEntrypoint)
NewEngineInGroupFragmentBuilder shouldAttachEngineToActivity(boolean shouldAttachEngineToActivity)
static final String ARG_DART_ENTRYPOINT_ARGS
void onSaveInstanceState(Bundle outState)
void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
String getCachedEngineGroupId()
void setFrameworkHandlesBack(boolean frameworkHandlesBack)
View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView)
static final String ARG_ENABLE_STATE_RESTORATION
List< String > getDartEntrypointArgs()
static final String ARG_APP_BUNDLE_PATH
void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView)
String getAppBundlePath()
FlutterShellArgs getFlutterShellArgs()
static final String ARG_FLUTTERVIEW_RENDER_MODE
boolean popSystemNavigator()
static NewEngineFragmentBuilder withNewEngine()
static final int FLUTTER_VIEW_ID
void onViewCreated(View view, Bundle savedInstanceState)
FlutterEngine getFlutterEngine()
static final String ARG_DART_ENTRYPOINT_URI
static final String ARG_INITIAL_ROUTE
void onCreate(@Nullable Bundle savedInstanceState)
boolean shouldHandleDeeplinking()
static final String ARG_DART_ENTRYPOINT
static FlutterFragment createDefault()
String getDartEntrypointFunctionName()
static final String ARG_DESTROY_ENGINE_WITH_FRAGMENT
boolean shouldDelayFirstAndroidViewDraw()
static NewEngineInGroupFragmentBuilder withNewEngineInGroup( @NonNull String engineGroupId)
void detachFromFlutterEngine()
static final String ARG_SHOULD_AUTOMATICALLY_HANDLE_ON_BACK_PRESSED
FlutterActivityAndFragmentDelegate createDelegate(FlutterActivityAndFragmentDelegate.Host host)
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine)
boolean shouldAttachEngineToActivity()
void onActivityResult(int requestCode, int resultCode, Intent data)
static CachedEngineFragmentBuilder withCachedEngine(@NonNull String engineId)
boolean attachToEngineAutomatically()
void onTrimMemory(int level)
String getDartEntrypointLibraryUri()
PlatformPlugin providePlatformPlugin( @Nullable Activity activity, @NonNull FlutterEngine flutterEngine)
boolean shouldDispatchAppLifecycleState()
static final String ARG_HANDLE_DEEPLINKING
static final String ARG_CACHED_ENGINE_ID
TransparencyMode getTransparencyMode()
void onFlutterUiDisplayed()
void updateSystemUiOverlays()
static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE
RenderMode getRenderMode()
ExclusiveAppComponent< Activity > getExclusiveAppComponent()
boolean shouldDestroyEngineWithHost()
FlutterEngine provideFlutterEngine(@NonNull Context context)
static final String ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY
static final String ARG_FLUTTER_INITIALIZATION_ARGS
String getCachedEngineId()
void setDelegateFactory( @NonNull FlutterActivityAndFragmentDelegate.DelegateFactory delegateFactory)
static final String ARG_CACHED_ENGINE_GROUP_ID
static final String ARG_SHOULD_DELAY_FIRST_ANDROID_VIEW_DRAW
void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine)
void onAttach(@NonNull Context context)
void onNewIntent(@NonNull Intent intent)
boolean isFlutterEngineInjected()
void onFlutterUiNoLongerDisplayed()
boolean shouldRestoreAndSaveState()
FlutterActivityAndFragmentDelegate delegate
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlutterEngine provideFlutterEngine(@NonNull Context context)
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