diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 85a74cd7c93f1..d96769394603f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -543,6 +543,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flutt FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngineAndroidLifecycle.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index d6dfd85120359..80fda97ad63db 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -128,6 +128,7 @@ action("flutter_shell_java") { "io/flutter/embedding/android/FlutterTextureView.java", "io/flutter/embedding/android/FlutterView.java", "io/flutter/embedding/engine/FlutterEngine.java", + "io/flutter/embedding/engine/FlutterEngineAndroidLifecycle.java", "io/flutter/embedding/engine/FlutterEnginePluginRegistry.java", "io/flutter/embedding/engine/FlutterJNI.java", "io/flutter/embedding/engine/FlutterShellArgs.java", @@ -216,6 +217,8 @@ action("flutter_shell_java") { "//third_party/android_support/android_support_annotations.jar", "//third_party/android_support/android_support_fragment.jar", "//third_party/android_support/android_arch_lifecycle_common.jar", + "//third_party/android_support/android_arch_lifecycle_common_java8.jar", + "//third_party/android_support/android_arch_lifecycle_runtime.jar", "//third_party/android_support/android_arch_lifecycle_viewmodel.jar", ] diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 34a6aad3730fd..d77a06f1fcc88 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -274,9 +274,26 @@ protected FlutterFragment createFlutterFragment() { .flutterShellArgs(FlutterShellArgs.fromIntent(getIntent())) .renderMode(FlutterView.RenderMode.surface) .transparencyMode(FlutterView.TransparencyMode.opaque) + .shouldAttachEngineToActivity(shouldAttachEngineToActivity()) .build(); } + /** + * Hook for subclasses to control whether or not the {@link FlutterFragment} within this + * {@code Activity} automatically attaches its {@link FlutterEngine} to this {@code Activity}. + *

+ * For an explanation of why this control exists, see {@link FlutterFragment.Builder#shouldAttachEngineToActivity()}. + *

+ * This property is controlled with a protected method instead of an {@code Intent} argument because + * the only situation where changing this value would help, is a situation in which + * {@code FlutterActivity} is being subclassed to utilize a custom and/or cached {@link FlutterEngine}. + *

+ * Defaults to {@code true}. + */ + protected boolean shouldAttachEngineToActivity() { + return true; + } + @Override public void onPostResume() { super.onPostResume(); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 9dc152917dd94..b5596ac3e6184 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -66,6 +66,7 @@ public class FlutterFragment extends Fragment { protected static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args"; protected static final String ARG_FLUTTERVIEW_RENDER_MODE = "flutterview_render_mode"; protected static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE = "flutterview_transparency_mode"; + protected static final String ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY = "should_attach_engine_to_activity"; /** * Builder that creates a new {@code FlutterFragment} with {@code arguments} that correspond @@ -118,6 +119,7 @@ public static class Builder { private FlutterShellArgs shellArgs = null; private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface; private FlutterView.TransparencyMode transparencyMode = FlutterView.TransparencyMode.transparent; + private boolean shouldAttachEngineToActivity = true; /** * Constructs a {@code Builder} that is configured to construct an instance of @@ -199,6 +201,46 @@ public Builder transparencyMode(@NonNull FlutterView.TransparencyMode transparen return this; } + /** + * Whether or not this {@code FlutterFragment} should automatically attach its + * {@code Activity} as a control surface for its {@link FlutterEngine}. + *

+ * Control surfaces are used to provide Android resources and lifecycle events to + * plugins that are attached to the {@link FlutterEngine}. If {@code shouldAttachEngineToActivity} + * is true then this {@code FlutterFragment} will connect its {@link FlutterEngine} to the + * surrounding {@code Activity}, along with any plugins that are registered with that + * {@link FlutterEngine}. This allows plugins to access the {@code Activity}, as well as + * receive {@code Activity}-specific calls, e.g., {@link android.app.Activity#onNewIntent(Intent)}. + * If {@code shouldAttachEngineToActivity} is false, then this {@code FlutterFragment} will not + * automatically manage the connection between its {@link FlutterEngine} and the surrounding + * {@code Activity}. The {@code Activity} will need to be manually connected to this + * {@code FlutterFragment}'s {@link FlutterEngine} by the app developer. See + * {@link FlutterEngine#getActivityControlSurface()}. + *

+ * One reason that a developer might choose to manually manage the relationship between the + * {@code Activity} and {@link FlutterEngine} is if the developer wants to move the + * {@link FlutterEngine} somewhere else. For example, a developer might want the + * {@link FlutterEngine} to outlive the surrounding {@code Activity} so that it can be used + * later in a different {@code Activity}. To accomplish this, the {@link FlutterEngine} will + * need to be disconnected from the surrounding {@code Activity} at an unusual time, preventing + * this {@code FlutterFragment} from correctly managing the relationship between the + * {@link FlutterEngine} and the surrounding {@code Activity}. + *

+ * Another reason that a developer might choose to manually manage the relationship between the + * {@code Activity} and {@link FlutterEngine} is if the developer wants to prevent, or explicitly + * control when the {@link FlutterEngine}'s plugins have access to the surrounding {@code Activity}. + * For example, imagine that this {@code FlutterFragment} only takes up part of the screen and + * the app developer wants to ensure that none of the Flutter plugins are able to manipulate + * the surrounding {@code Activity}. In this case, the developer would not want the + * {@link FlutterEngine} to have access to the {@code Activity}, which can be accomplished by + * setting {@code shouldAttachEngineToActivity} to {@code false}. + */ + @NonNull + public Builder shouldAttachEngineToActivity(boolean shouldAttachEngineToActivity) { + this.shouldAttachEngineToActivity = shouldAttachEngineToActivity; + return this; + } + /** * Creates a {@link Bundle} of arguments that are assigned to the new {@code FlutterFragment}. *

@@ -217,6 +259,7 @@ protected Bundle createArgs() { } args.putString(ARG_FLUTTERVIEW_RENDER_MODE, renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name()); args.putString(ARG_FLUTTERVIEW_TRANSPARENCY_MODE, transparencyMode != null ? transparencyMode.name() : FlutterView.TransparencyMode.transparent.name()); + args.putBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY, shouldAttachEngineToActivity); return args; } @@ -303,10 +346,12 @@ public void onAttach(Context context) { // use-cases. platformPlugin = new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel()); - // Notify any plugins that are currently attached to our FlutterEngine that they - // are now attached to an Activity. - // TODO(mattcarroll): send in a real lifecycle. - flutterEngine.getActivityControlSurface().attachToActivity(getActivity(), null); + if (shouldAttachEngineToActivity()) { + // Notify any plugins that are currently attached to our FlutterEngine that they + // are now attached to an Activity. + // TODO(mattcarroll): send in a real lifecycle. + flutterEngine.getActivityControlSurface().attachToActivity(getActivity(), null); + } } private void initializeFlutter(@NonNull Context context) { @@ -543,9 +588,11 @@ public void onDetach() { super.onDetach(); Log.d(TAG, "onDetach()"); - // Notify plugins that they are no longer attached to an Activity. - // TODO(mattcarroll): differentiate between detaching for config changes and otherwise. - flutterEngine.getActivityControlSurface().detachFromActivity(); + if (shouldAttachEngineToActivity()) { + // Notify plugins that they are no longer attached to an Activity. + // TODO(mattcarroll): differentiate between detaching for config changes and otherwise. + flutterEngine.getActivityControlSurface().detachFromActivity(); + } // Null out the platformPlugin to avoid a possible retain cycle between the plugin, this Fragment, // and this Fragment's Activity. @@ -572,6 +619,10 @@ protected boolean retainFlutterEngineAfterFragmentDestruction() { return false; } + protected boolean shouldAttachEngineToActivity() { + return getArguments().getBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY); + } + /** * The hardware back button was pressed. * diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 1a7612dec8593..452804df581b9 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -4,6 +4,8 @@ package io.flutter.embedding.engine; +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleOwner; import android.content.Context; import android.support.annotation.NonNull; @@ -48,7 +50,7 @@ * a {@link io.flutter.embedding.android.FlutterView} as a {@link FlutterRenderer.RenderSurface}. */ // TODO(mattcarroll): re-evaluate system channel APIs - some are not well named or differentiated -public class FlutterEngine { +public class FlutterEngine implements LifecycleOwner { private static final String TAG = "FlutterEngine"; @NonNull @@ -59,6 +61,8 @@ public class FlutterEngine { private final DartExecutor dartExecutor; @NonNull private final FlutterEnginePluginRegistry pluginRegistry; + @NonNull + private final FlutterEngineAndroidLifecycle androidLifecycle; // System channels. @NonNull @@ -125,11 +129,11 @@ public FlutterEngine(@NonNull Context context) { systemChannel = new SystemChannel(dartExecutor); textInputChannel = new TextInputChannel(dartExecutor); - // TODO(mattcarroll): bring in Lifecycle. + androidLifecycle = new FlutterEngineAndroidLifecycle(this); this.pluginRegistry = new FlutterEnginePluginRegistry( context.getApplicationContext(), this, - null + androidLifecycle ); } @@ -154,7 +158,8 @@ private boolean isAttachedToJni() { * This {@code FlutterEngine} instance should be discarded after invoking this method. */ public void destroy() { - pluginRegistry.removeAll(); + // The order that these things are destroyed is important. + pluginRegistry.destroy(); dartExecutor.onDetachedFromJNI(); flutterJNI.removeEngineLifecycleListener(engineLifecycleListener); flutterJNI.detachFromNativeAndReleaseResources(); @@ -288,6 +293,13 @@ public ContentProviderControlSurface getContentProviderControlSurface() { return pluginRegistry; } + // TODO(mattcarroll): determine if we really need to expose this from FlutterEngine vs making PluginBinding a LifecycleOwner + @NonNull + @Override + public Lifecycle getLifecycle() { + return androidLifecycle; + } + /** * Lifecycle callbacks for Flutter engine lifecycle events. */ diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineAndroidLifecycle.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineAndroidLifecycle.java new file mode 100644 index 0000000000000..671a6ecbbbb7e --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineAndroidLifecycle.java @@ -0,0 +1,126 @@ +package io.flutter.embedding.engine; + +import android.arch.lifecycle.DefaultLifecycleObserver; +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleObserver; +import android.arch.lifecycle.LifecycleOwner; +import android.arch.lifecycle.LifecycleRegistry; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +/** + * Android {@link Lifecycle} that is owned by a {@link FlutterEngine}. + *

+ * {@code FlutterEngineAndroidLifecycle} exists so that {@code FlutterPlugin}s can monitor Android + * lifecycle events. When the associated {@link FlutterEngine} is running in an {@code Activity}, + * that {@code Activity}'s {@link Lifecycle} can be set as the {@code backingLifecycle} of this + * class, allowing all Flutter plugins to receive the {@code Activity}'s lifecycle events. Likewise, + * when the associated {@link FlutterEngine} is running in a {@code Service}, that {@code Service}'s + * {@link Lifecycle} can be set as the {@code backingLifecycle}. + *

+ * Sometimes a {@link FlutterEngine} exists in a non-lifecycle location, e.g., an {@code Application}, + * {@code ContentProvider}, or {@code BroadcastReceiver}. In these cases, this lifecycle reports + * itself in the {@link Lifecycle.State#CREATED} state. + *

+ * Regardless of what happens to a backing {@code Activity} or @{code Service}, this lifecycle + * will only report itself as {@link Lifecycle.State#DESTROYED} when the associated {@link FlutterEngine} + * itself is destroyed. This is because a {@link Lifecycle} is not allowed to emit any events after + * going to the {@link Lifecycle.State#DESTROYED} state. Thus, this lifecycle cannot emit such an + * event until its associated {@link FlutterEngine} is destroyed. This then begs the question, what + * happens when the backing {@code Activity} or {@code Service} is destroyed? This lifecycle will + * report the process up to the {@link Lifecycle.Event#ON_STOP} event, but will ignore the + * {@link Lifecycle.Event#ON_DESTROY} event. At that point, this lifecycle will be back in its + * default {@link Lifecycle.State#CREATED} state until some other backing {@link Lifecycle} is + * registered. + */ +final class FlutterEngineAndroidLifecycle extends LifecycleRegistry { + private static final String TAG = "FlutterEngineAndroidLifecycle"; + + @Nullable + private Lifecycle backingLifecycle; + private boolean isDestroyed = false; + + private final LifecycleObserver forwardingObserver = new DefaultLifecycleObserver() { + @Override + public void onCreate(@NonNull LifecycleOwner owner) { + // No-op. The FlutterEngine's Lifecycle is always at least Created + // until it is Destroyed, so we ignore onCreate() events from + // backing Lifecycles. + } + + @Override + public void onStart(@NonNull LifecycleOwner owner) { + handleLifecycleEvent(Event.ON_START); + } + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + handleLifecycleEvent(Event.ON_RESUME); + } + + @Override + public void onPause(@NonNull LifecycleOwner owner) { + handleLifecycleEvent(Event.ON_PAUSE); + } + + @Override + public void onStop(@NonNull LifecycleOwner owner) { + handleLifecycleEvent(Event.ON_STOP); + } + + @Override + public void onDestroy(@NonNull LifecycleOwner owner) { + // No-op. We don't allow FlutterEngine's Lifecycle to report destruction + // until the FlutterEngine itself is destroyed. This is because a Lifecycle + // is contractually obligated to send no more event once it gets to the + // Destroyed state, which would prevent FlutterEngine from switching to + // the next Lifecycle that is attached. + } + }; + + FlutterEngineAndroidLifecycle(@NonNull LifecycleOwner provider) { + super(provider); + } + + public void setBackingLifecycle(@Nullable Lifecycle lifecycle) { + ensureNotDestroyed(); + + // We no longer want to propagate events from the old Lifecycle. Deregister our forwarding observer. + if (backingLifecycle != null) { + backingLifecycle.removeObserver(forwardingObserver); + } + + // Manually move us to the Stopped state before we switch out the underlying Lifecycle. + handleLifecycleEvent(Event.ON_STOP); + + // Switch out the underlying lifecycle. + backingLifecycle = lifecycle; + + if (backingLifecycle != null) { + // Add our forwardingObserver to the new backing Lifecycle so that this PluginRegistry is + // controlled by that backing lifecycle. Adding our forwarding observer will automatically + // result in invocations of the necessary Lifecycle events to bring us up to speed with the + // new backingLifecycle, e.g., onStart(), onResume(). + lifecycle.addObserver(forwardingObserver); + } + } + + @Override + public void handleLifecycleEvent(@NonNull Event event) { + ensureNotDestroyed(); + super.handleLifecycleEvent(event); + } + + public void destroy() { + ensureNotDestroyed(); + setBackingLifecycle(null); + markState(State.DESTROYED); + isDestroyed = true; + } + + private void ensureNotDestroyed() { + if (isDestroyed) { + throw new IllegalStateException("Tried to invoke a method on a destroyed FlutterEngineAndroidLifecycle."); + } + } +} diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java index d79b9d52b41fb..3d99e397bb70d 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java @@ -47,6 +47,7 @@ class FlutterEnginePluginRegistry implements PluginRegistry, // Standard FlutterPlugin private final FlutterPlugin.FlutterPluginBinding pluginBinding; + private final FlutterEngineAndroidLifecycle flutterEngineAndroidLifecycle; // ActivityAware private final Map, ActivityAware> activityAwarePlugins = new HashMap<>(); @@ -71,8 +72,9 @@ class FlutterEnginePluginRegistry implements PluginRegistry, FlutterEnginePluginRegistry( @NonNull Context appContext, @NonNull FlutterEngine flutterEngine, - @NonNull Lifecycle lifecycle + @NonNull FlutterEngineAndroidLifecycle lifecycle ) { + flutterEngineAndroidLifecycle = lifecycle; pluginBinding = new FlutterPlugin.FlutterPluginBinding( appContext, flutterEngine, @@ -80,6 +82,21 @@ class FlutterEnginePluginRegistry implements PluginRegistry, ); } + public void destroy() { + // Detach from any Android component that we may currently be attached to, e.g., Activity, Service, + // BroadcastReceiver, ContentProvider. This must happen before removing all plugins so that the + // plugins have an opportunity to clean up references as a result of component detachment. + detachFromAndroidComponent(); + + // Push FlutterEngine's Lifecycle to the DESTROYED state. This must happen before removing all + // plugins so that the plugins have an opportunity to clean up references as a result of moving + // to the DESTROYED state. + flutterEngineAndroidLifecycle.destroy(); + + // Remove all registered plugins. + removeAll(); + } + public void add(@NonNull FlutterPlugin plugin) { // Add the plugin to our generic set of plugins and notify the plugin // that is has been attached to an engine. @@ -241,7 +258,7 @@ public void attachToActivity(@NonNull Activity activity, @NonNull Lifecycle life this.activity = activity; this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity); - // TODO(mattcarroll): resolve possibility of different lifecycles between this and engine attachment + this.flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle); // Notify all ActivityAware plugins that they are now attached to a new Activity. for (ActivityAware activityAware : activityAwarePlugins.values()) { @@ -257,6 +274,7 @@ public void detachFromActivityForConfigChanges() { activityAware.onDetachedFromActivityForConfigChanges(); } + flutterEngineAndroidLifecycle.setBackingLifecycle(null); activity = null; activityPluginBinding = null; } else { @@ -265,11 +283,12 @@ public void detachFromActivityForConfigChanges() { } @Override - public void reattachToActivityAfterConfigChange(@NonNull Activity activity) { + public void reattachToActivityAfterConfigChange(@NonNull Activity activity, @NonNull Lifecycle lifecycle) { Log.d(TAG, "Re-attaching to an Activity after config change."); if (!isAttachedToActivity()) { this.activity = activity; activityPluginBinding = new FlutterEngineActivityPluginBinding(activity); + this.flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle); for (ActivityAware activityAware : activityAwarePlugins.values()) { activityAware.onReattachedToActivityForConfigChanges(activityPluginBinding); @@ -287,6 +306,7 @@ public void detachFromActivity() { activityAware.onDetachedFromActivity(); } + flutterEngineAndroidLifecycle.setBackingLifecycle(null); activity = null; activityPluginBinding = null; } else { @@ -349,7 +369,7 @@ public void attachToService(@NonNull Service service, @NonNull Lifecycle lifecyc this.service = service; this.servicePluginBinding = new FlutterEngineServicePluginBinding(service); - // TODO(mattcarroll): resolve possibility of different lifecycles between this and engine attachment + flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle); // Notify all ServiceAware plugins that they are now attached to a new Service. for (ServiceAware serviceAware : serviceAwarePlugins.values()) { @@ -364,6 +384,10 @@ public void detachFromService() { for (ServiceAware serviceAware : serviceAwarePlugins.values()) { serviceAware.onDetachedFromService(); } + + flutterEngineAndroidLifecycle.setBackingLifecycle(null); + service = null; + servicePluginBinding = null; } else { Log.e(TAG, "Attempted to detach plugins from a Service when no Service was attached."); } diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/FlutterPlugin.java b/shell/platform/android/io/flutter/embedding/engine/plugins/FlutterPlugin.java index c6a65ed710068..3202d15dd45c8 100644 --- a/shell/platform/android/io/flutter/embedding/engine/plugins/FlutterPlugin.java +++ b/shell/platform/android/io/flutter/embedding/engine/plugins/FlutterPlugin.java @@ -5,6 +5,7 @@ package io.flutter.embedding.engine.plugins; import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleOwner; import android.content.Context; import android.support.annotation.NonNull; @@ -87,12 +88,12 @@ public interface FlutterPlugin { * {@link FlutterEngine#getDartExecutor()}. *

* A {@link FlutterEngine} may move from foreground to background, from an {@code Activity} to - * a {@code Service}, and {@code FlutterPluginBinding}'s {@code lifecycle} generalizes those + * a {@code Service}. {@code FlutterPluginBinding}'s {@code lifecycle} generalizes those * lifecycles so that a {@code FlutterPlugin} can react to lifecycle events without being * concerned about which Android Component is currently holding the {@link FlutterEngine}. * TODO(mattcarroll): add info about ActivityAware and ServiceAware for plugins that care. */ - class FlutterPluginBinding { + class FlutterPluginBinding implements LifecycleOwner { private final Context applicationContext; private final FlutterEngine flutterEngine; private final Lifecycle lifecycle; @@ -117,6 +118,7 @@ public FlutterEngine getFlutterEngine() { return flutterEngine; } + @Override @NonNull public Lifecycle getLifecycle() { return lifecycle; diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityControlSurface.java b/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityControlSurface.java index 52e1ab3f44f14..a99d41b5783ed 100644 --- a/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityControlSurface.java +++ b/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityControlSurface.java @@ -66,7 +66,7 @@ public interface ActivityControlSurface { * This method gives each {@link ActivityAware} plugin an opportunity to re-establish necessary * references to the given {@link Activity}. */ - void reattachToActivityAfterConfigChange(@NonNull Activity activity); + void reattachToActivityAfterConfigChange(@NonNull Activity activity, @NonNull Lifecycle lifecycle); /** * Call this method from the {@link Activity} that is attached to this {@code ActivityControlSurfaces}'s diff --git a/tools/android_support/files.json b/tools/android_support/files.json index 6c673e7fff8e6..565e143b731b3 100644 --- a/tools/android_support/files.json +++ b/tools/android_support/files.json @@ -1,5 +1,7 @@ { "android_arch_lifecycle_common.jar": "https://dl.google.com/dl/android/maven2/android/arch/lifecycle/common/1.1.1/common-1.1.1.jar", + "android_arch_lifecycle_common_java8.jar": "https://dl.google.com/dl/android/maven2/android/arch/lifecycle/common-java8/1.1.1/common-java8-1.1.1.jar", + "android_arch_lifecycle_runtime.jar": "https://dl.google.com/dl/android/maven2/android/arch/lifecycle/runtime/1.1.1/runtime-1.1.1.aar", "android_arch_lifecycle_viewmodel.jar": "https://dl.google.com/dl/android/maven2/android/arch/lifecycle/viewmodel/1.1.1/viewmodel-1.1.1.aar", "android_support_fragment.jar": "https://dl.google.com/dl/android/maven2/com/android/support/support-fragment/28.0.0/support-fragment-28.0.0.aar", "android_support_v13.jar": "https://dl.google.com/dl/android/maven2/com/android/support/support-v13/28.0.0/support-v13-28.0.0.aar",