5package io.flutter.embedding.android;
7import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DART_ENTRYPOINT_META_DATA_KEY;
8import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DART_ENTRYPOINT_URI_META_DATA_KEY;
9import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_BACKGROUND_MODE;
10import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_DART_ENTRYPOINT;
11import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
12import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_BACKGROUND_MODE;
13import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID;
14import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_ID;
15import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DART_ENTRYPOINT;
16import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DART_ENTRYPOINT_ARGS;
17import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DESTROY_ENGINE_WITH_ACTIVITY;
18import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_INITIAL_ROUTE;
19import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY;
20import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.INITIAL_ROUTE_META_DATA_KEY;
21import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.NORMAL_THEME_META_DATA_KEY;
25import android.content.pm.ActivityInfo;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.PackageManager;
29import android.graphics.drawable.ColorDrawable;
34import android.view.WindowManager;
35import android.widget.FrameLayout;
36import androidx.annotation.NonNull;
37import androidx.annotation.Nullable;
38import androidx.annotation.VisibleForTesting;
39import androidx.fragment.app.FragmentActivity;
40import androidx.fragment.app.FragmentManager;
42import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
43import io.flutter.embedding.engine.FlutterEngine;
44import io.flutter.embedding.engine.FlutterShellArgs;
45import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister;
46import io.flutter.plugin.platform.PlatformPlugin;
47import java.util.ArrayList;
63 private static final String TAG =
"FlutterFragmentActivity";
66 private static final String TAG_FLUTTER_FRAGMENT =
"flutter_fragment";
95 private final Class<? extends FlutterFragmentActivity> activityClass;
96 private String initialRoute = DEFAULT_INITIAL_ROUTE;
97 private String backgroundMode = DEFAULT_BACKGROUND_MODE;
112 this.activityClass = activityClass;
121 this.initialRoute = initialRoute;
143 this.backgroundMode = backgroundMode.name();
158 this.dartEntrypointArgs = dartEntrypointArgs;
169 new Intent(context, activityClass)
170 .putExtra(EXTRA_INITIAL_ROUTE, initialRoute)
171 .putExtra(EXTRA_BACKGROUND_MODE, backgroundMode)
172 .putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
true);
173 if (dartEntrypointArgs !=
null) {
174 intent.putExtra(EXTRA_DART_ENTRYPOINT_ARGS,
new ArrayList(dartEntrypointArgs));
196 private final Class<? extends FlutterFragmentActivity> activityClass;
197 private final String cachedEngineId;
198 private boolean destroyEngineWithActivity =
false;
199 private String backgroundMode = DEFAULT_BACKGROUND_MODE;
213 @NonNull Class<? extends FlutterFragmentActivity> activityClass, @NonNull String engineId) {
214 this.activityClass = activityClass;
215 this.cachedEngineId = engineId;
225 this.destroyEngineWithActivity = destroyEngineWithActivity;
247 this.backgroundMode = backgroundMode.name();
257 return new Intent(context, activityClass)
258 .putExtra(EXTRA_CACHED_ENGINE_ID, cachedEngineId)
259 .putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY, destroyEngineWithActivity)
260 .putExtra(EXTRA_BACKGROUND_MODE, backgroundMode);
282 private final Class<? extends FlutterFragmentActivity> activityClass;
283 private final String cachedEngineGroupId;
284 private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT;
285 private String initialRoute = DEFAULT_INITIAL_ROUTE;
286 private String backgroundMode = DEFAULT_BACKGROUND_MODE;
304 @NonNull Class<? extends FlutterFragmentActivity> activityClass,
305 @NonNull String engineGroupId) {
306 this.activityClass = activityClass;
307 this.cachedEngineGroupId = engineGroupId;
319 this.dartEntrypoint = dartEntrypoint;
329 this.initialRoute = initialRoute;
351 this.backgroundMode = backgroundMode.name();
361 return new Intent(context, activityClass)
362 .putExtra(EXTRA_DART_ENTRYPOINT, dartEntrypoint)
363 .putExtra(EXTRA_INITIAL_ROUTE, initialRoute)
364 .putExtra(EXTRA_CACHED_ENGINE_GROUP_ID, cachedEngineGroupId)
365 .putExtra(EXTRA_BACKGROUND_MODE, backgroundMode)
366 .putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
true);
373 protected void onCreate(@Nullable Bundle savedInstanceState) {
374 switchLaunchThemeForNormalTheme();
380 super.onCreate(savedInstanceState);
382 configureWindowForTransparency();
383 setContentView(createFragmentContainer());
384 configureStatusBarForFullscreenFlutterExperience();
385 ensureFlutterFragmentCreated();
417 private void switchLaunchThemeForNormalTheme() {
420 if (metaData !=
null) {
421 int normalThemeRID = metaData.getInt(NORMAL_THEME_META_DATA_KEY, -1);
422 if (normalThemeRID != -1) {
423 setTheme(normalThemeRID);
426 Log.
v(TAG,
"Using the launch theme as normal theme.");
428 }
catch (PackageManager.NameNotFoundException exception) {
431 "Could not read meta-data for FlutterFragmentActivity. Using the launch theme as normal theme.");
443 private void configureWindowForTransparency() {
445 if (backgroundMode == BackgroundMode.transparent) {
446 getWindow().setBackgroundDrawable(
new ColorDrawable(Color.TRANSPARENT));
459 private View createFragmentContainer() {
462 container.setLayoutParams(
463 new ViewGroup.LayoutParams(
464 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
477 FragmentManager fragmentManager = getSupportFragmentManager();
478 return (
FlutterFragment) fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT);
487 private void ensureFlutterFragmentCreated() {
488 if (flutterFragment ==
null) {
494 if (flutterFragment ==
null) {
498 FragmentManager fragmentManager = getSupportFragmentManager();
517 backgroundMode == BackgroundMode.opaque
518 ? TransparencyMode.opaque
520 final boolean shouldDelayFirstAndroidViewDraw = renderMode ==
RenderMode.
surface;
525 "Creating FlutterFragment with cached engine:\n"
526 +
"Cached engine ID: "
529 +
"Will destroy engine when Activity is destroyed: "
532 +
"Background transparency mode: "
535 +
"Will attach FlutterEngine to Activity: "
539 .renderMode(renderMode)
540 .transparencyMode(transparencyMode)
544 .shouldDelayFirstAndroidViewDraw(shouldDelayFirstAndroidViewDraw)
549 "Creating FlutterFragment with new engine:\n"
550 +
"Cached engine group ID: "
553 +
"Background transparency mode: "
556 +
"Dart entrypoint: "
559 +
"Dart entrypoint library uri: "
565 +
"App bundle path: "
568 +
"Will attach FlutterEngine to Activity: "
576 .renderMode(renderMode)
577 .transparencyMode(transparencyMode)
579 .shouldDelayFirstAndroidViewDraw(shouldDelayFirstAndroidViewDraw)
589 .flutterShellArgs(FlutterShellArgs.fromIntent(getIntent()))
591 .renderMode(renderMode)
592 .transparencyMode(transparencyMode)
594 .shouldDelayFirstAndroidViewDraw(shouldDelayFirstAndroidViewDraw)
599 private void configureStatusBarForFullscreenFlutterExperience() {
601 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
602 window.setStatusBarColor(0x40000000);
603 window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
608 super.onPostResume();
609 flutterFragment.onPostResume();
615 flutterFragment.onNewIntent(intent);
616 super.onNewIntent(intent);
620 @SuppressWarnings(
"MissingSuperCall")
622 flutterFragment.onBackPressed();
627 int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
628 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
629 flutterFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
633 @SuppressWarnings(
"MissingSuperCall")
635 flutterFragment.onUserLeaveHint();
640 super.onTrimMemory(level);
641 flutterFragment.onTrimMemory(level);
646 super.onActivityResult(requestCode, resultCode, data);
647 flutterFragment.onActivityResult(requestCode, resultCode, data);
650 @SuppressWarnings(
"unused")
653 return flutterFragment.getFlutterEngine();
666 return getIntent().getBooleanExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
false);
701 metaData !=
null ? metaData.getBoolean(HANDLE_DEEPLINKING_META_DATA_KEY) :
false;
703 }
catch (PackageManager.NameNotFoundException e) {
730 if (flutterFragment !=
null && flutterFragment.isFlutterEngineInjected()) {
737 GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
770 if (isDebuggable() && Intent.ACTION_RUN.equals(getIntent().getAction())) {
771 String appBundlePath = getIntent().getDataString();
772 if (appBundlePath !=
null) {
773 return appBundlePath;
782 protected Bundle
getMetaData() throws PackageManager.NameNotFoundException {
783 ActivityInfo activityInfo =
784 getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
785 return activityInfo.metaData;
801 String desiredDartEntrypoint =
802 metaData !=
null ? metaData.getString(DART_ENTRYPOINT_META_DATA_KEY) :
null;
803 return desiredDartEntrypoint !=
null ? desiredDartEntrypoint : DEFAULT_DART_ENTRYPOINT;
804 }
catch (PackageManager.NameNotFoundException e) {
805 return DEFAULT_DART_ENTRYPOINT;
818 return (
List<String>) getIntent().getSerializableExtra(EXTRA_DART_ENTRYPOINT_ARGS);
839 String desiredDartLibraryUri =
840 metaData !=
null ? metaData.getString(DART_ENTRYPOINT_URI_META_DATA_KEY) :
null;
841 return desiredDartLibraryUri;
842 }
catch (PackageManager.NameNotFoundException e) {
872 if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
873 return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
878 String desiredInitialRoute =
879 metaData !=
null ? metaData.getString(INITIAL_ROUTE_META_DATA_KEY) :
null;
880 return desiredInitialRoute;
881 }
catch (PackageManager.NameNotFoundException e) {
894 return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
899 return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_GROUP_ID);
908 if (getIntent().hasExtra(EXTRA_BACKGROUND_MODE)) {
909 return BackgroundMode.valueOf(getIntent().getStringExtra(EXTRA_BACKGROUND_MODE));
911 return BackgroundMode.opaque;
925 return backgroundMode == BackgroundMode.opaque ? RenderMode.surface :
RenderMode.
texture;
933 private boolean isDebuggable() {
934 return (getApplicationInfo().
flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
940 return new FrameLayout(context);
static void v(@NonNull String tag, @NonNull String message)
Intent build(@NonNull Context context)
CachedEngineIntentBuilder destroyEngineWithActivity(boolean destroyEngineWithActivity)
CachedEngineIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode)
CachedEngineIntentBuilder( @NonNull Class<? extends FlutterFragmentActivity > activityClass, @NonNull String engineId)
NewEngineInGroupIntentBuilder initialRoute(@NonNull String initialRoute)
NewEngineInGroupIntentBuilder( @NonNull Class<? extends FlutterFragmentActivity > activityClass, @NonNull String engineGroupId)
NewEngineInGroupIntentBuilder dartEntrypoint(@NonNull String dartEntrypoint)
Intent build(@NonNull Context context)
NewEngineInGroupIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode)
NewEngineIntentBuilder(@NonNull Class<? extends FlutterFragmentActivity > activityClass)
NewEngineIntentBuilder initialRoute(@NonNull String initialRoute)
Intent build(@NonNull Context context)
NewEngineIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode)
NewEngineIntentBuilder dartEntrypointArgs(@Nullable List< String > dartEntrypointArgs)
String getDartEntrypointLibraryUri()
List< String > getDartEntrypointArgs()
boolean shouldAttachEngineToActivity()
FlutterFragment createFlutterFragment()
void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
void onActivityResult(int requestCode, int resultCode, Intent data)
boolean shouldDestroyEngineWithHost()
String getCachedEngineId()
FlutterFragment retrieveExistingFlutterFragmentIfPossible()
FlutterEngine provideFlutterEngine(@NonNull Context context)
static Intent createDefaultIntent(@NonNull Context launchContext)
static CachedEngineIntentBuilder withCachedEngine(@NonNull String cachedEngineId)
String getAppBundlePath()
static final int FRAGMENT_CONTAINER_ID
void onNewIntent(@NonNull Intent intent)
FrameLayout provideRootLayout(Context context)
static NewEngineInGroupIntentBuilder withNewEngineInGroup(@NonNull String engineGroupId)
String getDartEntrypointFunctionName()
boolean shouldHandleDeeplinking()
void onCreate(@Nullable Bundle savedInstanceState)
FlutterEngine getFlutterEngine()
void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine)
BackgroundMode getBackgroundMode()
void onTrimMemory(int level)
String getCachedEngineGroupId()
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine)
static NewEngineIntentBuilder withNewEngine()
RenderMode getRenderMode()
static NewEngineFragmentBuilder withNewEngine()
static NewEngineInGroupFragmentBuilder withNewEngineInGroup( @NonNull String engineGroupId)
static CachedEngineFragmentBuilder withCachedEngine(@NonNull String engineId)
FlutterSemanticsFlag flags