diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index bfd6f47d5071d..7cc9c05902f1f 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -416,6 +416,7 @@ action("robolectric_tests") { "test/io/flutter/SmokeTest.java", "test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java", "test/io/flutter/embedding/android/FlutterActivityTest.java", + "test/io/flutter/embedding/android/FlutterAndroidComponentTest.java", "test/io/flutter/embedding/android/FlutterFragmentTest.java", "test/io/flutter/embedding/android/FlutterViewTest.java", "test/io/flutter/embedding/engine/FlutterEngineCacheTest.java", diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index a2f13160eb010..a478c053bd40f 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -399,6 +399,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { delegate = new FlutterActivityAndFragmentDelegate(this); delegate.onAttach(this); + delegate.onActivityCreated(savedInstanceState); configureWindowForTransparency(); setContentView(createFlutterView()); @@ -557,6 +558,12 @@ protected void onStop() { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP); } + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + delegate.onSaveInstanceState(outState); + } + @Override protected void onDestroy() { super.onDestroy(); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 9176ad6f5486d..2895ba19c470e 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -142,8 +142,6 @@ FlutterEngine getFlutterEngine() { void onAttach(@NonNull Context context) { ensureAlive(); - initializeFlutter(context); - // When "retain instance" is true, the FlutterEngine will survive configuration // changes. Therefore, we create a new one only if one does not already exist. if (flutterEngine == null) { @@ -178,13 +176,6 @@ void onAttach(@NonNull Context context) { host.configureFlutterEngine(flutterEngine); } - private void initializeFlutter(@NonNull Context context) { - FlutterMain.ensureInitializationComplete( - context.getApplicationContext(), - host.getFlutterShellArgs().toArray() - ); - } - /** * Obtains a reference to a FlutterEngine to back this delegate and its {@code host}. *
@@ -223,7 +214,7 @@ private void setupFlutterEngine() { // FlutterView. Log.d(TAG, "No preferred FlutterEngine was provided. Creating a new FlutterEngine for" + " this FlutterFragment."); - flutterEngine = new FlutterEngine(host.getContext()); + flutterEngine = new FlutterEngine(host.getContext(), host.getFlutterShellArgs().toArray()); isFlutterEngineFromHost = false; } @@ -257,6 +248,15 @@ View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nulla return flutterSplashView; } + void onActivityCreated(@Nullable Bundle bundle) { + Log.v(TAG, "onActivityCreated. Giving plugins an opportunity to restore state."); + ensureAlive(); + + if (host.shouldAttachEngineToActivity()) { + flutterEngine.getActivityControlSurface().onRestoreInstanceState(bundle); + } + } + /** * Invoke this from {@code Activity#onStart()} or {@code Fragment#onStart()}. *
@@ -404,6 +404,15 @@ void onDestroyView() { flutterView.removeOnFirstFrameRenderedListener(flutterUiDisplayListener); } + void onSaveInstanceState(@Nullable Bundle bundle) { + Log.v(TAG, "onSaveInstanceState. Giving plugins an opportunity to save state."); + ensureAlive(); + + if (host.shouldAttachEngineToActivity()) { + flutterEngine.getActivityControlSurface().onSaveInstanceState(bundle); + } + } + /** * Invoke this from {@code Activity#onDestroy()} or {@code Fragment#onDetach()}. *
diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 6ad1037e3f4e0..1cc9d892a4f0d 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -586,6 +586,12 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, return delegate.onCreateView(inflater, container, savedInstanceState); } + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + delegate.onActivityCreated(savedInstanceState); + } + @Override public void onStart() { super.onStart(); @@ -622,6 +628,12 @@ public void onDestroyView() { delegate.onDestroyView(); } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + delegate.onSaveInstanceState(outState); + } + @Override public void onDetach() { super.onDetach(); diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 5a4ec289ccf2f..6a55007a32375 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -8,6 +8,7 @@ import android.arch.lifecycle.LifecycleOwner; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import java.util.HashSet; import java.util.Set; @@ -143,7 +144,29 @@ public void onPreEngineRestart() { * and {@link FlutterLoader#ensureInitializationComplete(Context, String[])}. */ public FlutterEngine(@NonNull Context context) { - this(context, FlutterLoader.getInstance(), new FlutterJNI()); + this(context, null); + } + + /** + * Same as {@link #FlutterEngine(Context)} with added support for passing Dart + * VM arguments. + *
+ * If the Dart VM has already started, the given arguments will have no effect.
+ */
+ public FlutterEngine(@NonNull Context context, @Nullable String[] dartVmArgs) {
+ this(context, FlutterLoader.getInstance(), new FlutterJNI(), dartVmArgs);
+ }
+
+ /**
+ * Same as {@link #FlutterEngine(Context, FlutterLoader, FlutterJNI, String[])} but with no Dart
+ * VM flags.
+ */
+ public FlutterEngine(
+ @NonNull Context context,
+ @NonNull FlutterLoader flutterLoader,
+ @NonNull FlutterJNI flutterJNI
+ ) {
+ this(context, flutterLoader, flutterJNI, null);
}
/**
@@ -151,10 +174,15 @@ public FlutterEngine(@NonNull Context context) {
*
* {@code flutterJNI} should be a new instance that has never been attached to an engine before.
*/
- public FlutterEngine(@NonNull Context context, @NonNull FlutterLoader flutterLoader, @NonNull FlutterJNI flutterJNI) {
+ public FlutterEngine(
+ @NonNull Context context,
+ @NonNull FlutterLoader flutterLoader,
+ @NonNull FlutterJNI flutterJNI,
+ @Nullable String[] dartVmArgs
+ ) {
this.flutterJNI = flutterJNI;
flutterLoader.startInitialization(context);
- flutterLoader.ensureInitializationComplete(context, null);
+ flutterLoader.ensureInitializationComplete(context, dartVmArgs);
flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
attachToJni();
diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java
index 173aa915e663c..efa756acc313b 100644
--- a/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java
+++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java
@@ -11,6 +11,7 @@
import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -49,6 +50,8 @@ class FlutterEnginePluginRegistry implements PluginRegistry,
// Standard FlutterPlugin
@NonNull
+ private final FlutterEngine flutterEngine;
+ @NonNull
private final FlutterPlugin.FlutterPluginBinding pluginBinding;
@NonNull
private final FlutterEngineAndroidLifecycle flutterEngineAndroidLifecycle;
@@ -91,10 +94,14 @@ class FlutterEnginePluginRegistry implements PluginRegistry,
@NonNull FlutterEngine flutterEngine,
@NonNull FlutterEngineAndroidLifecycle lifecycle
) {
+ this.flutterEngine = flutterEngine;
flutterEngineAndroidLifecycle = lifecycle;
pluginBinding = new FlutterPlugin.FlutterPluginBinding(
appContext,
flutterEngine,
+ flutterEngine.getDartExecutor(),
+ flutterEngine.getRenderer(),
+ flutterEngine.getPlatformViewsController().getRegistry(),
lifecycle
);
}
@@ -288,16 +295,16 @@ public void attachToActivity(
detachFromAndroidComponent();
this.activity = activity;
- this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity);
+ this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity, lifecycle);
this.flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle);
// Activate the PlatformViewsController. This must happen before any plugins attempt
// to use it, otherwise an error stack trace will appear that says there is no
// flutter/platform_views channel.
- pluginBinding.getFlutterEngine().getPlatformViewsController().attach(
+ flutterEngine.getPlatformViewsController().attach(
activity,
- pluginBinding.getFlutterEngine().getRenderer(),
- pluginBinding.getFlutterEngine().getDartExecutor()
+ flutterEngine.getRenderer(),
+ flutterEngine.getDartExecutor()
);
// Notify all ActivityAware plugins that they are now attached to a new Activity.
@@ -322,7 +329,7 @@ public void detachFromActivityForConfigChanges() {
}
// Deactivate PlatformViewsController.
- pluginBinding.getFlutterEngine().getPlatformViewsController().detach();
+ flutterEngine.getPlatformViewsController().detach();
flutterEngineAndroidLifecycle.setBackingLifecycle(null);
activity = null;
@@ -341,7 +348,7 @@ public void detachFromActivity() {
}
// Deactivate PlatformViewsController.
- pluginBinding.getFlutterEngine().getPlatformViewsController().detach();
+ flutterEngine.getPlatformViewsController().detach();
flutterEngineAndroidLifecycle.setBackingLifecycle(null);
activity = null;
@@ -392,6 +399,26 @@ public void onUserLeaveHint() {
Log.e(TAG, "Attempted to notify ActivityAware plugins of onUserLeaveHint, but no Activity was attached.");
}
}
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle bundle) {
+ Log.v(TAG, "Forwarding onSaveInstanceState() to plugins.");
+ if (isAttachedToActivity()) {
+ activityPluginBinding.onSaveInstanceState(bundle);
+ } else {
+ Log.e(TAG, "Attempted to notify ActivityAware plugins of onSaveInstanceState, but no Activity was attached.");
+ }
+ }
+
+ @Override
+ public void onRestoreInstanceState(@Nullable Bundle bundle) {
+ Log.v(TAG, "Forwarding onRestoreInstanceState() to plugins.");
+ if (isAttachedToActivity()) {
+ activityPluginBinding.onRestoreInstanceState(bundle);
+ } else {
+ Log.e(TAG, "Attempted to notify ActivityAware plugins of onRestoreInstanceState, but no Activity was attached.");
+ }
+ }
//------- End ActivityControlSurface -----
//----- Start ServiceControlSurface ----
@@ -400,13 +427,13 @@ private boolean isAttachedToService() {
}
@Override
- public void attachToService(@NonNull Service service, @NonNull Lifecycle lifecycle, boolean isForeground) {
+ public void attachToService(@NonNull Service service, @Nullable Lifecycle lifecycle, boolean isForeground) {
Log.v(TAG, "Attaching to a Service: " + service);
// If we were already attached to an Android component, detach from it.
detachFromAndroidComponent();
this.service = service;
- this.servicePluginBinding = new FlutterEngineServicePluginBinding(service);
+ this.servicePluginBinding = new FlutterEngineServicePluginBinding(service, lifecycle);
flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle);
// Notify all ServiceAware plugins that they are now attached to a new Service.
@@ -523,6 +550,8 @@ private static class FlutterEngineActivityPluginBinding implements ActivityPlugi
@NonNull
private final Activity activity;
@NonNull
+ private final Lifecycle lifecycle;
+ @NonNull
private final Set
- * The Android side of a Flutter plugin can be thought of as applying itself to a {@link FlutterEngine}.
- * Use {@link FlutterPluginBinding#getFlutterEngine()} to retrieve the {@link FlutterEngine} that
- * the {@code FlutterPlugin} is attached to. To register a
- * {@link io.flutter.plugin.common.MethodChannel}, obtain the {@link FlutterEngine}'s
- * {@link io.flutter.embedding.engine.dart.DartExecutor} with {@link FlutterEngine#getDartExecutor()},
- * then pass the {@link io.flutter.embedding.engine.dart.DartExecutor} to the
- * {@link io.flutter.plugin.common.MethodChannel} as a {@link io.flutter.plugin.common.BinaryMessenger}.
+ * To register a {@link io.flutter.plugin.common.MethodChannel}, obtain a {@link BinaryMessenger}
+ * via the {@link FlutterPluginBinding}.
*
* An Android Flutter plugin may require access to app resources or other artifacts that can only
* be retrieved through a {@link Context}. Developers can access the application context via
@@ -81,30 +79,34 @@ public interface FlutterPlugin {
/**
* Resources made available to all plugins registered with a given {@link FlutterEngine}.
*
- * The {@code FlutterPluginBinding}'s {@code flutterEngine} refers to the {@link FlutterEngine}
- * that the associated {@code FlutterPlugin} is intended to apply to. For example, if a
- * {@code FlutterPlugin} needs to setup a communication channel with its associated Flutter app,
- * that can be done by wrapping a {@code MethodChannel} around
- * {@link FlutterEngine#getDartExecutor()}.
+ * The provided {@link BinaryMessenger} can be used to communicate with Dart code running
+ * in the Flutter context associated with this plugin binding.
*
- * A {@link FlutterEngine} may move from foreground to background, from an {@code Activity} to
- * 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.
+ * Plugins that need to respond to {@code Lifecycle} events should implement the additional
+ * {@link ActivityAware} and/or {@link ServiceAware} interfaces, where a {@link Lifecycle}
+ * reference can be obtained.
*/
class FlutterPluginBinding implements LifecycleOwner {
private final Context applicationContext;
private final FlutterEngine flutterEngine;
+ private final BinaryMessenger binaryMessenger;
+ private final TextureRegistry textureRegistry;
+ private final PlatformViewRegistry platformViewRegistry;
private final Lifecycle lifecycle;
public FlutterPluginBinding(
@NonNull Context applicationContext,
@NonNull FlutterEngine flutterEngine,
+ @NonNull BinaryMessenger binaryMessenger,
+ @NonNull TextureRegistry textureRegistry,
+ @NonNull PlatformViewRegistry platformViewRegistry,
@NonNull Lifecycle lifecycle
) {
this.applicationContext = applicationContext;
this.flutterEngine = flutterEngine;
+ this.binaryMessenger = binaryMessenger;
+ this.textureRegistry = textureRegistry;
+ this.platformViewRegistry = platformViewRegistry;
this.lifecycle = lifecycle;
}
@@ -113,11 +115,37 @@ public Context getApplicationContext() {
return applicationContext;
}
+ /**
+ * @deprecated
+ * Use {@code getBinaryMessenger()}, {@code getTextureRegistry()}, or
+ * {@code getPlatformViewRegistry()} instead.
+ */
+ @Deprecated
@NonNull
public FlutterEngine getFlutterEngine() {
return flutterEngine;
}
+ @NonNull
+ public BinaryMessenger getBinaryMessenger() {
+ return binaryMessenger;
+ }
+
+ @NonNull
+ public TextureRegistry getTextureRegistry() {
+ return textureRegistry;
+ }
+
+ @NonNull
+ public PlatformViewRegistry getPlatformViewRegistry() {
+ return platformViewRegistry;
+ }
+
+ /**
+ * @deprecated
+ * Use ActivityPluginBinding Lifecycle or ServicePluginBinding Lifecycle instead.
+ */
+ @Deprecated
@Override
@NonNull
public Lifecycle getLifecycle() {
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 0f51c78d9595f..432f2e278f3b8 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
@@ -7,6 +7,7 @@
import android.app.Activity;
import android.arch.lifecycle.Lifecycle;
import android.content.Intent;
+import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -98,4 +99,19 @@ public interface ActivityControlSurface {
* {@link FlutterEngine} and the associated method in the {@link Activity} is invoked.
*/
void onUserLeaveHint();
+
+ /**
+ * Call this method from the {@link Activity} or {@code Fragment} that is attached to this
+ * {@code ActivityControlSurface}'s {@link FlutterEngine} when the associated method is invoked
+ * in the {@link Activity} or {@code Fragment}.
+ */
+ void onSaveInstanceState(@NonNull Bundle bundle);
+
+ /**
+ * Call this method from the {@link Activity} or {@code Fragment} that is attached to this
+ * {@code ActivityControlSurface}'s {@link FlutterEngine} when {@link Activity#onCreate(Bundle)}
+ * or {@code Fragment#onActivityCreated(Bundle)} is invoked in the {@link Activity} or
+ * {@code Fragment}.
+ */
+ void onRestoreInstanceState(@Nullable Bundle bundle);
}
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java b/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java
index 2958d79a81322..7bd8647842e6c 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/activity/ActivityPluginBinding.java
@@ -5,10 +5,12 @@
package io.flutter.embedding.engine.plugins.activity;
import android.app.Activity;
+import android.arch.lifecycle.Lifecycle;
+import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import io.flutter.plugin.common.PluginRegistry;
-import io.flutter.plugin.platform.PlatformViewsController;
/**
* Binding that gives {@link ActivityAware} plugins access to an associated {@link Activity} and
@@ -23,6 +25,12 @@ public interface ActivityPluginBinding {
@NonNull
Activity getActivity();
+ /**
+ * Returns the {@link Lifecycle} associated with the attached {@code Activity}.
+ */
+ @NonNull
+ Lifecycle getLifecycle();
+
/**
* Adds a listener that is invoked whenever the associated {@link Activity}'s
* {@code onRequestPermissionsResult(...)} method is invoked.
@@ -66,4 +74,30 @@ public interface ActivityPluginBinding {
* Removes a listener that was added in {@link #addOnUserLeaveHintListener(PluginRegistry.UserLeaveHintListener)}.
*/
void removeOnUserLeaveHintListener(@NonNull PluginRegistry.UserLeaveHintListener listener);
+
+ /**
+ * Adds a listener that is invoked when the associated {@code Activity} or {@code Fragment}
+ * saves and restores instance state.
+ */
+ void addOnSaveStateListener(@NonNull OnSaveInstanceStateListener listener);
+
+ /**
+ * Removes a listener that was added in {@link #addOnSaveStateListener(OnSaveInstanceStateListener)}.
+ */
+ void removeOnSaveStateListener(@NonNull OnSaveInstanceStateListener listener);
+
+ interface OnSaveInstanceStateListener {
+ /**
+ * Invoked when the associated {@code Activity} or {@code Fragment} executes
+ * {@link Activity#onSaveInstanceState(Bundle)}.
+ */
+ void onSaveInstanceState(@NonNull Bundle bundle);
+
+ /**
+ * Invoked when the associated {@code Activity} executes
+ * {@link Activity#onCreate(Bundle)} or associated {@code Fragment} executes
+ * {@code Fragment#onActivityCreated(Bundle)}.
+ */
+ void onRestoreInstanceState(@Nullable Bundle bundle);
+ }
}
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java b/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java
index 82c513d6718c4..352379d88fd3d 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServiceControlSurface.java
@@ -7,6 +7,7 @@
import android.app.Service;
import android.arch.lifecycle.Lifecycle;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
/**
* Control surface through which a {@link Service} attaches to a {@link FlutterEngine}.
@@ -27,7 +28,7 @@ public interface ServiceControlSurface {
* {@code isForeground} should be true if the given {@link Service} is running in the foreground,
* false otherwise.
*/
- void attachToService(@NonNull Service service, @NonNull Lifecycle lifecycle, boolean isForeground);
+ void attachToService(@NonNull Service service, @Nullable Lifecycle lifecycle, boolean isForeground);
/**
* Call this method from the {@link Service} that is attached to this {@code ServiceControlSurfaces}'s
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java b/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java
index 8621bc90a1e81..45a2dbf2f5d58 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/service/ServicePluginBinding.java
@@ -5,7 +5,9 @@
package io.flutter.embedding.engine.plugins.service;
import android.app.Service;
+import android.arch.lifecycle.Lifecycle;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
/**
* Binding that gives {@link ServiceAware} plugins access to an associated {@link Service}.
@@ -19,6 +21,12 @@ public interface ServicePluginBinding {
@NonNull
Service getService();
+ /**
+ * Returns the {@link Lifecycle} associated with the attached {@code Service}.
+ */
+ @Nullable
+ Lifecycle getLifecycle();
+
/**
* Adds the given {@code listener} to be notified when the associated {@link Service} goes
* from background to foreground, or foreground to background.
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java b/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
index 39e5ea5764353..3e88d31144174 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
@@ -64,17 +64,17 @@ public Context activeContext() {
@Override
public BinaryMessenger messenger() {
- return pluginBinding != null ? pluginBinding.getFlutterEngine().getDartExecutor() : null;
+ return pluginBinding != null ? pluginBinding.getBinaryMessenger() : null;
}
@Override
public TextureRegistry textures() {
- return pluginBinding != null ? pluginBinding.getFlutterEngine().getRenderer() : null;
+ return pluginBinding != null ? pluginBinding.getTextureRegistry() : null;
}
@Override
public PlatformViewRegistry platformViewRegistry() {
- return pluginBinding != null ? pluginBinding.getFlutterEngine().getPlatformViewsController().getRegistry() : null;
+ return pluginBinding != null ? pluginBinding.getPlatformViewRegistry() : null;
}
@Override
diff --git a/shell/platform/android/test/io/flutter/FlutterTestSuite.java b/shell/platform/android/test/io/flutter/FlutterTestSuite.java
index b400fb5625e1c..2eae27cb3aa4c 100644
--- a/shell/platform/android/test/io/flutter/FlutterTestSuite.java
+++ b/shell/platform/android/test/io/flutter/FlutterTestSuite.java
@@ -9,6 +9,7 @@
import org.junit.runners.Suite.SuiteClasses;
import io.flutter.embedding.android.FlutterActivityTest;
+import io.flutter.embedding.android.FlutterAndroidComponentTest;
import io.flutter.embedding.android.FlutterFragmentTest;
import io.flutter.embedding.android.FlutterViewTest;
import io.flutter.embedding.engine.FlutterEngineCacheTest;
@@ -23,8 +24,9 @@
@RunWith(Suite.class)
@SuiteClasses({
- // FlutterActivityAndFragmentDelegateTest.class, TODO(mklim): Fix and re-enable this
+ //FlutterActivityAndFragmentDelegateTest.class, //TODO(mklim): Fix and re-enable this
FlutterActivityTest.class,
+ FlutterAndroidComponentTest.class,
FlutterEngineCacheTest.class,
FlutterFragmentTest.class,
FlutterJNITest.class,
diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java
new file mode 100644
index 0000000000000..0104250789be3
--- /dev/null
+++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java
@@ -0,0 +1,273 @@
+package io.flutter.embedding.android;
+
+import android.app.Activity;
+import android.arch.lifecycle.Lifecycle;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import io.flutter.embedding.engine.FlutterEngine;
+import io.flutter.embedding.engine.FlutterEngineCache;
+import io.flutter.embedding.engine.FlutterJNI;
+import io.flutter.embedding.engine.FlutterShellArgs;
+import io.flutter.embedding.engine.loader.FlutterLoader;
+import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.embedding.engine.plugins.activity.ActivityAware;
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
+import io.flutter.plugin.platform.PlatformPlugin;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+@Config(manifest=Config.NONE)
+@RunWith(RobolectricTestRunner.class)
+public class FlutterAndroidComponentTest {
+ @Test
+ public void pluginsReceiveFlutterPluginBinding() {
+ // ---- Test setup ----
+ // Place a FlutterEngine in the static cache.
+ FlutterLoader mockFlutterLoader = mock(FlutterLoader.class);
+ FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
+ when(mockFlutterJni.isAttached()).thenReturn(true);
+ FlutterEngine cachedEngine = spy(new FlutterEngine(RuntimeEnvironment.application, mockFlutterLoader, mockFlutterJni));
+ FlutterEngineCache.getInstance().put("my_flutter_engine", cachedEngine);
+
+ // Add mock plugin.
+ FlutterPlugin mockPlugin = mock(FlutterPlugin.class);
+ cachedEngine.getPlugins().add(mockPlugin);
+
+ // Create a fake Host, which is required by the delegate.
+ FlutterActivityAndFragmentDelegate.Host fakeHost = new FakeHost(cachedEngine);
+
+ // Create the real object that we're testing.
+ FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(fakeHost);
+
+ // --- Execute the behavior under test ---
+ // Push the delegate through all lifecycle methods all the way to destruction.
+ delegate.onAttach(RuntimeEnvironment.application);
+
+ // Verify that the plugin is attached to the FlutterEngine.
+ ArgumentCaptor