5package io.flutter.embedding.android;
7import static io.flutter.Build.API_LEVELS;
8import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DART_ENTRYPOINT_META_DATA_KEY;
9import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DART_ENTRYPOINT_URI_META_DATA_KEY;
10import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_BACKGROUND_MODE;
11import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_DART_ENTRYPOINT;
12import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
13import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_BACKGROUND_MODE;
14import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID;
15import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_CACHED_ENGINE_ID;
16import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DART_ENTRYPOINT;
17import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DART_ENTRYPOINT_ARGS;
18import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_DESTROY_ENGINE_WITH_ACTIVITY;
19import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_ENABLE_STATE_RESTORATION;
20import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.EXTRA_INITIAL_ROUTE;
21import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY;
22import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.INITIAL_ROUTE_META_DATA_KEY;
23import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.NORMAL_THEME_META_DATA_KEY;
25import android.annotation.TargetApi;
29import android.content.pm.ActivityInfo;
30import android.content.pm.ApplicationInfo;
31import android.content.pm.PackageManager;
33import android.graphics.drawable.ColorDrawable;
38import android.view.WindowManager;
40import android.window.OnBackAnimationCallback;
41import android.window.OnBackInvokedCallback;
42import android.window.OnBackInvokedDispatcher;
43import androidx.annotation.NonNull;
44import androidx.annotation.Nullable;
45import androidx.annotation.RequiresApi;
46import androidx.annotation.VisibleForTesting;
47import androidx.lifecycle.Lifecycle;
48import androidx.lifecycle.LifecycleOwner;
49import androidx.lifecycle.LifecycleRegistry;
51import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
52import io.flutter.embedding.engine.FlutterEngine;
53import io.flutter.embedding.engine.FlutterShellArgs;
54import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface;
55import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister;
56import io.flutter.plugin.platform.PlatformPlugin;
57import java.util.ArrayList;
213 private static final String TAG =
"FlutterActivity";
215 private boolean hasRegisteredBackCallback =
false;
259 private final Class<? extends FlutterActivity> activityClass;
260 private String initialRoute = DEFAULT_INITIAL_ROUTE;
261 private String backgroundMode = DEFAULT_BACKGROUND_MODE;
275 this.activityClass = activityClass;
287 this.initialRoute = initialRoute;
312 this.backgroundMode = backgroundMode.name();
327 this.dartEntrypointArgs = dartEntrypointArgs;
339 public Intent
build(@NonNull Context context) {
341 new Intent(context, activityClass)
342 .putExtra(EXTRA_INITIAL_ROUTE, initialRoute)
343 .putExtra(EXTRA_BACKGROUND_MODE, backgroundMode)
344 .putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
true);
345 if (dartEntrypointArgs !=
null) {
346 intent.putExtra(EXTRA_DART_ENTRYPOINT_ARGS,
new ArrayList(dartEntrypointArgs));
371 private final Class<? extends FlutterActivity> activityClass;
372 private final String cachedEngineId;
373 private boolean destroyEngineWithActivity =
false;
374 private String backgroundMode = DEFAULT_BACKGROUND_MODE;
391 @NonNull Class<? extends FlutterActivity> activityClass, @NonNull String engineId) {
392 this.activityClass = activityClass;
393 this.cachedEngineId = engineId;
406 this.destroyEngineWithActivity = destroyEngineWithActivity;
431 this.backgroundMode = backgroundMode.name();
443 public Intent
build(@NonNull Context context) {
444 return new Intent(context, activityClass)
445 .putExtra(EXTRA_CACHED_ENGINE_ID, cachedEngineId)
446 .putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY, destroyEngineWithActivity)
447 .putExtra(EXTRA_BACKGROUND_MODE, backgroundMode);
483 private final Class<? extends FlutterActivity> activityClass;
484 private final String cachedEngineGroupId;
485 private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT;
486 private String initialRoute = DEFAULT_INITIAL_ROUTE;
487 private String backgroundMode = DEFAULT_BACKGROUND_MODE;
520 @NonNull Class<? extends FlutterActivity> activityClass, @NonNull String engineGroupId) {
521 this.activityClass = activityClass;
522 this.cachedEngineGroupId = engineGroupId;
534 this.dartEntrypoint = dartEntrypoint;
547 this.initialRoute = initialRoute;
572 this.backgroundMode = backgroundMode.name();
584 public Intent
build(@NonNull Context context) {
585 return new Intent(context, activityClass)
586 .putExtra(EXTRA_DART_ENTRYPOINT, dartEntrypoint)
587 .putExtra(EXTRA_INITIAL_ROUTE, initialRoute)
588 .putExtra(EXTRA_CACHED_ENGINE_GROUP_ID, cachedEngineGroupId)
589 .putExtra(EXTRA_BACKGROUND_MODE, backgroundMode)
590 .putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
true);
599 @NonNull
private LifecycleRegistry lifecycle;
602 lifecycle =
new LifecycleRegistry(
this);
632 protected void onCreate(@Nullable Bundle savedInstanceState) {
633 switchLaunchThemeForNormalTheme();
635 super.onCreate(savedInstanceState);
641 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
643 configureWindowForTransparency();
645 setContentView(createFlutterView());
647 configureStatusBarForFullscreenFlutterExperience();
663 getOnBackInvokedDispatcher()
664 .registerOnBackInvokedCallback(
665 OnBackInvokedDispatcher.PRIORITY_DEFAULT, onBackInvokedCallback);
666 hasRegisteredBackCallback =
true;
679 getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(onBackInvokedCallback);
680 hasRegisteredBackCallback =
false;
684 private final OnBackInvokedCallback onBackInvokedCallback =
685 Build.VERSION.SDK_INT < API_LEVELS.API_33 ? null : createOnBackInvokedCallback();
689 return onBackInvokedCallback;
695 private OnBackInvokedCallback createOnBackInvokedCallback() {
697 return new OnBackAnimationCallback() {
699 public void onBackInvoked() {
704 public void onBackCancelled() {
709 public void onBackProgressed(@NonNull BackEvent backEvent) {
714 public void onBackStarted(@NonNull BackEvent backEvent) {
720 return this::onBackPressed;
725 if (frameworkHandlesBack && !hasRegisteredBackCallback) {
727 }
else if (!frameworkHandlesBack && hasRegisteredBackCallback) {
761 private void switchLaunchThemeForNormalTheme() {
764 if (metaData !=
null) {
765 int normalThemeRID = metaData.getInt(NORMAL_THEME_META_DATA_KEY, -1);
766 if (normalThemeRID != -1) {
767 setTheme(normalThemeRID);
770 Log.
v(TAG,
"Using the launch theme as normal theme.");
772 }
catch (PackageManager.NameNotFoundException exception) {
775 "Could not read meta-data for FlutterActivity. Using the launch theme as normal theme.");
787 private void configureWindowForTransparency() {
789 if (backgroundMode == BackgroundMode.transparent) {
790 getWindow().setBackgroundDrawable(
new ColorDrawable(
Color.TRANSPARENT));
795 private View createFlutterView() {
804 private void configureStatusBarForFullscreenFlutterExperience() {
805 Window
window = getWindow();
806 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
807 window.setStatusBarColor(0x40000000);
808 window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
814 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
815 if (stillAttachedForEvent(
"onStart")) {
823 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
824 if (stillAttachedForEvent(
"onResume")) {
831 super.onPostResume();
832 if (stillAttachedForEvent(
"onPostResume")) {
840 if (stillAttachedForEvent(
"onPause")) {
843 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
849 if (stillAttachedForEvent(
"onStop")) {
852 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
857 super.onSaveInstanceState(outState);
858 if (stillAttachedForEvent(
"onSaveInstanceState")) {
888 +
" connection to the engine "
890 +
" evicted by another attaching activity");
900 if (stillAttachedForEvent(
"onDestroy")) {
905 lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
910 if (stillAttachedForEvent(
"onActivityResult")) {
918 super.onNewIntent(intent);
919 if (stillAttachedForEvent(
"onNewIntent")) {
926 if (stillAttachedForEvent(
"onBackPressed")) {
934 if (stillAttachedForEvent(
"startBackGesture")) {
942 if (stillAttachedForEvent(
"updateBackGestureProgress")) {
950 if (stillAttachedForEvent(
"commitBackGesture")) {
958 if (stillAttachedForEvent(
"cancelBackGesture")) {
965 int requestCode, @NonNull String[] permissions, @NonNull
int[] grantResults) {
966 if (stillAttachedForEvent(
"onRequestPermissionsResult")) {
973 if (stillAttachedForEvent(
"onUserLeaveHint")) {
980 super.onWindowFocusChanged(hasFocus);
981 if (stillAttachedForEvent(
"onWindowFocusChanged")) {
988 super.onTrimMemory(
level);
989 if (stillAttachedForEvent(
"onTrimMemory")) {
1046 return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
1057 return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_GROUP_ID);
1071 boolean explicitDestructionRequested =
1072 getIntent().getBooleanExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
false);
1075 return explicitDestructionRequested;
1079 return getIntent().getBooleanExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY,
true);
1102 if (getIntent().hasExtra(EXTRA_DART_ENTRYPOINT)) {
1103 return getIntent().getStringExtra(EXTRA_DART_ENTRYPOINT);
1108 String desiredDartEntrypoint =
1109 metaData !=
null ? metaData.getString(DART_ENTRYPOINT_META_DATA_KEY) :
null;
1110 return desiredDartEntrypoint !=
null ? desiredDartEntrypoint : DEFAULT_DART_ENTRYPOINT;
1111 }
catch (PackageManager.NameNotFoundException
e) {
1112 return DEFAULT_DART_ENTRYPOINT;
1125 return (
List<String>) getIntent().getSerializableExtra(EXTRA_DART_ENTRYPOINT_ARGS);
1146 String desiredDartLibraryUri =
1147 metaData !=
null ? metaData.getString(DART_ENTRYPOINT_URI_META_DATA_KEY) :
null;
1148 return desiredDartLibraryUri;
1149 }
catch (PackageManager.NameNotFoundException
e) {
1179 if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
1180 return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
1185 String desiredInitialRoute =
1186 metaData !=
null ? metaData.getString(INITIAL_ROUTE_META_DATA_KEY) :
null;
1187 return desiredInitialRoute;
1188 }
catch (PackageManager.NameNotFoundException
e) {
1211 if (isDebuggable() && Intent.ACTION_RUN.equals(getIntent().getAction())) {
1212 String appBundlePath = getIntent().getDataString();
1213 if (appBundlePath !=
null) {
1214 return appBundlePath;
1226 private boolean isDebuggable() {
1227 return (getApplicationInfo().
flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
1250 ? TransparencyMode.opaque
1262 if (getIntent().hasExtra(EXTRA_BACKGROUND_MODE)) {
1263 return BackgroundMode.valueOf(getIntent().getStringExtra(EXTRA_BACKGROUND_MODE));
1302 protected Bundle
getMetaData() throws PackageManager.NameNotFoundException {
1303 ActivityInfo activityInfo =
1304 getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
1305 return activityInfo.metaData;
1311 @Nullable Activity activity, @NonNull
FlutterEngine flutterEngine) {
1329 if (
delegate.isFlutterEngineFromHost()) {
1408 metaData !=
null ? metaData.getBoolean(HANDLE_DEEPLINKING_META_DATA_KEY) :
false;
1410 }
catch (PackageManager.NameNotFoundException
e) {
1446 if (getIntent().hasExtra(EXTRA_ENABLE_STATE_RESTORATION)) {
1447 return getIntent().getBooleanExtra(EXTRA_ENABLE_STATE_RESTORATION,
false);
1495 private boolean stillAttachedForEvent(String
event) {
1497 Log.
w(TAG,
"FlutterActivity " + hashCode() +
" " +
event +
" called after release.");
1501 Log.
w(TAG,
"FlutterActivity " + 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 updateBackGestureProgress(@NonNull BackEvent backEvent)
void onAttach(@NonNull Context context)
void startBackGesture(@NonNull BackEvent backEvent)
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()
CachedEngineIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode)
Intent build(@NonNull Context context)
CachedEngineIntentBuilder destroyEngineWithActivity(boolean destroyEngineWithActivity)
CachedEngineIntentBuilder( @NonNull Class<? extends FlutterActivity > activityClass, @NonNull String engineId)
NewEngineInGroupIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode)
NewEngineInGroupIntentBuilder( @NonNull Class<? extends FlutterActivity > activityClass, @NonNull String engineGroupId)
Intent build(@NonNull Context context)
NewEngineInGroupIntentBuilder initialRoute(@NonNull String initialRoute)
NewEngineInGroupIntentBuilder dartEntrypoint(@NonNull String dartEntrypoint)
NewEngineIntentBuilder initialRoute(@NonNull String initialRoute)
NewEngineIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode)
NewEngineIntentBuilder(@NonNull Class<? extends FlutterActivity > activityClass)
Intent build(@NonNull Context context)
NewEngineIntentBuilder dartEntrypointArgs(@Nullable List< String > dartEntrypointArgs)
void setFrameworkHandlesBack(boolean frameworkHandlesBack)
boolean popSystemNavigator()
static CachedEngineIntentBuilder withCachedEngine(@NonNull String cachedEngineId)
void onWindowFocusChanged(boolean hasFocus)
void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView)
void setDelegate(@NonNull FlutterActivityAndFragmentDelegate delegate)
void registerOnBackInvokedCallback()
boolean shouldRestoreAndSaveState()
FlutterShellArgs getFlutterShellArgs()
BackgroundMode getBackgroundMode()
String getAppBundlePath()
void updateBackGestureProgress(@NonNull BackEvent backEvent)
void onNewIntent(@NonNull Intent intent)
void updateSystemUiOverlays()
void onFlutterUiNoLongerDisplayed()
void onFlutterUiDisplayed()
boolean shouldDispatchAppLifecycleState()
void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView)
TransparencyMode getTransparencyMode()
void onTrimMemory(int level)
void onSaveInstanceState(Bundle outState)
void detachFromFlutterEngine()
void startBackGesture(@NonNull BackEvent backEvent)
FlutterEngine provideFlutterEngine(@NonNull Context context)
ExclusiveAppComponent< Activity > getExclusiveAppComponent()
PlatformPlugin providePlatformPlugin( @Nullable Activity activity, @NonNull FlutterEngine flutterEngine)
boolean attachToEngineAutomatically()
static Intent createDefaultIntent(@NonNull Context launchContext)
static NewEngineInGroupIntentBuilder withNewEngineInGroup(@NonNull String engineGroupId)
String getCachedEngineId()
static NewEngineIntentBuilder withNewEngine()
List< String > getDartEntrypointArgs()
void onCreate(@Nullable Bundle savedInstanceState)
void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine)
boolean shouldAttachEngineToActivity()
FlutterActivityAndFragmentDelegate delegate
OnBackInvokedCallback getOnBackInvokedCallback()
FlutterEngine getFlutterEngine()
void onActivityResult(int requestCode, int resultCode, Intent data)
boolean shouldHandleDeeplinking()
RenderMode getRenderMode()
String getDartEntrypointFunctionName()
static final int FLUTTER_VIEW_ID
boolean shouldDestroyEngineWithHost()
String getDartEntrypointLibraryUri()
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine)
void unregisterOnBackInvokedCallback()
String getCachedEngineGroupId()
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
def Build(configs, env, options)
std::shared_ptr< const fml::Mapping > data