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;
167 public Intent
build(@NonNull Context context) {
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();
256 public Intent
build(@NonNull Context context) {
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();
360 public Intent
build(@NonNull Context context) {
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;
521 final boolean shouldAutomaticallyHandleOnBackPressed =
true;
526 "Creating FlutterFragment with cached engine:\n"
527 +
"Cached engine ID: "
530 +
"Will destroy engine when Activity is destroyed: "
533 +
"Background transparency mode: "
536 +
"Will attach FlutterEngine to Activity: "
540 .renderMode(renderMode)
541 .transparencyMode(transparencyMode)
545 .shouldDelayFirstAndroidViewDraw(shouldDelayFirstAndroidViewDraw)
546 .shouldAutomaticallyHandleOnBackPressed(shouldAutomaticallyHandleOnBackPressed)
551 "Creating FlutterFragment with new engine:\n"
552 +
"Cached engine group ID: "
555 +
"Background transparency mode: "
558 +
"Dart entrypoint: "
561 +
"Dart entrypoint library uri: "
567 +
"App bundle path: "
570 +
"Will attach FlutterEngine to Activity: "
578 .renderMode(renderMode)
579 .transparencyMode(transparencyMode)
581 .shouldDelayFirstAndroidViewDraw(shouldDelayFirstAndroidViewDraw)
582 .shouldAutomaticallyHandleOnBackPressed(shouldAutomaticallyHandleOnBackPressed)
594 .renderMode(renderMode)
595 .transparencyMode(transparencyMode)
597 .shouldDelayFirstAndroidViewDraw(shouldDelayFirstAndroidViewDraw)
598 .shouldAutomaticallyHandleOnBackPressed(shouldAutomaticallyHandleOnBackPressed)
603 private void configureStatusBarForFullscreenFlutterExperience() {
604 Window
window = getWindow();
605 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
606 window.setStatusBarColor(0x40000000);
612 super.onPostResume();
613 flutterFragment.onPostResume();
619 flutterFragment.onNewIntent(intent);
620 super.onNewIntent(intent);
625 int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
626 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
627 flutterFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
631 @SuppressWarnings(
"MissingSuperCall")
633 flutterFragment.onUserLeaveHint();
638 super.onTrimMemory(
level);
639 flutterFragment.onTrimMemory(
level);
644 super.onActivityResult(requestCode, resultCode,
data);
645 flutterFragment.onActivityResult(requestCode, resultCode,
data);
648 @SuppressWarnings(
"unused")
651 return flutterFragment.getFlutterEngine();
664 return getIntent().getBooleanExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
false);
699 metaData !=
null ? metaData.getBoolean(HANDLE_DEEPLINKING_META_DATA_KEY) :
false;
701 }
catch (PackageManager.NameNotFoundException
e) {
728 if (flutterFragment !=
null && flutterFragment.isFlutterEngineInjected()) {
768 if (isDebuggable() && Intent.ACTION_RUN.equals(getIntent().getAction())) {
769 String appBundlePath = getIntent().getDataString();
770 if (appBundlePath !=
null) {
771 return appBundlePath;
780 protected Bundle
getMetaData() throws PackageManager.NameNotFoundException {
781 ActivityInfo activityInfo =
782 getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
783 return activityInfo.metaData;
799 String desiredDartEntrypoint =
800 metaData !=
null ? metaData.getString(DART_ENTRYPOINT_META_DATA_KEY) :
null;
801 return desiredDartEntrypoint !=
null ? desiredDartEntrypoint : DEFAULT_DART_ENTRYPOINT;
802 }
catch (PackageManager.NameNotFoundException
e) {
803 return DEFAULT_DART_ENTRYPOINT;
816 return (
List<String>) getIntent().getSerializableExtra(EXTRA_DART_ENTRYPOINT_ARGS);
837 String desiredDartLibraryUri =
838 metaData !=
null ? metaData.getString(DART_ENTRYPOINT_URI_META_DATA_KEY) :
null;
839 return desiredDartLibraryUri;
840 }
catch (PackageManager.NameNotFoundException
e) {
870 if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
871 return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
876 String desiredInitialRoute =
877 metaData !=
null ? metaData.getString(INITIAL_ROUTE_META_DATA_KEY) :
null;
878 return desiredInitialRoute;
879 }
catch (PackageManager.NameNotFoundException
e) {
892 return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
897 return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_GROUP_ID);
906 if (getIntent().hasExtra(EXTRA_BACKGROUND_MODE)) {
907 return BackgroundMode.valueOf(getIntent().getStringExtra(EXTRA_BACKGROUND_MODE));
923 return backgroundMode == BackgroundMode.opaque ? RenderMode.surface :
RenderMode.
texture;
931 private boolean isDebuggable() {
932 return (getApplicationInfo().
flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
938 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)
static FlutterShellArgs fromIntent(@NonNull Intent intent)
static void registerGeneratedPlugins(@NonNull FlutterEngine flutterEngine)
FlutterSemanticsFlag flags
SK_API sk_sp< SkShader > Color(SkColor)
void Log(const char *format,...) SK_PRINTF_LIKE(1
std::shared_ptr< const fml::Mapping > data