@@ -66,6 +66,7 @@ public class FlutterFragment extends Fragment {
6666 protected static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args" ;
6767 protected static final String ARG_FLUTTERVIEW_RENDER_MODE = "flutterview_render_mode" ;
6868 protected static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE = "flutterview_transparency_mode" ;
69+ protected static final String ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY = "should_attach_engine_to_activity" ;
6970
7071 /**
7172 * Builder that creates a new {@code FlutterFragment} with {@code arguments} that correspond
@@ -118,6 +119,7 @@ public static class Builder {
118119 private FlutterShellArgs shellArgs = null ;
119120 private FlutterView .RenderMode renderMode = FlutterView .RenderMode .surface ;
120121 private FlutterView .TransparencyMode transparencyMode = FlutterView .TransparencyMode .transparent ;
122+ private boolean shouldAttachEngineToActivity = true ;
121123
122124 /**
123125 * Constructs a {@code Builder} that is configured to construct an instance of
@@ -199,6 +201,46 @@ public Builder transparencyMode(@NonNull FlutterView.TransparencyMode transparen
199201 return this ;
200202 }
201203
204+ /**
205+ * Whether or not this {@code FlutterFragment} should automatically attach its
206+ * {@code Activity} as a control surface for its {@link FlutterEngine}.
207+ * <p>
208+ * Control surfaces are used to provide Android resources and lifecycle events to
209+ * plugins that are attached to the {@link FlutterEngine}. If {@code shouldAttachEngineToActivity}
210+ * is true then this {@code FlutterFragment} will connect its {@link FlutterEngine} to the
211+ * surrounding {@code Activity}, along with any plugins that are registered with that
212+ * {@link FlutterEngine}. This allows plugins to access the {@code Activity}, as well as
213+ * receive {@code Activity}-specific calls, e.g., {@link android.app.Activity#onNewIntent(Intent)}.
214+ * If {@code shouldAttachEngineToActivity} is false, then this {@code FlutterFragment} will not
215+ * automatically manage the connection between its {@link FlutterEngine} and the surrounding
216+ * {@code Activity}. The {@code Activity} will need to be manually connected to this
217+ * {@code FlutterFragment}'s {@link FlutterEngine} by the app developer. See
218+ * {@link FlutterEngine#getActivityControlSurface()}.
219+ * <p>
220+ * One reason that a developer might choose to manually manage the relationship between the
221+ * {@code Activity} and {@link FlutterEngine} is if the developer wants to move the
222+ * {@link FlutterEngine} somewhere else. For example, a developer might want the
223+ * {@link FlutterEngine} to outlive the surrounding {@code Activity} so that it can be used
224+ * later in a different {@code Activity}. To accomplish this, the {@link FlutterEngine} will
225+ * need to be disconnected from the surrounding {@code Activity} at an unusual time, preventing
226+ * this {@code FlutterFragment} from correctly managing the relationship between the
227+ * {@link FlutterEngine} and the surrounding {@code Activity}.
228+ * <p>
229+ * Another reason that a developer might choose to manually manage the relationship between the
230+ * {@code Activity} and {@link FlutterEngine} is if the developer wants to prevent, or explicitly
231+ * control when the {@link FlutterEngine}'s plugins have access to the surrounding {@code Activity}.
232+ * For example, imagine that this {@code FlutterFragment} only takes up part of the screen and
233+ * the app developer wants to ensure that none of the Flutter plugins are able to manipulate
234+ * the surrounding {@code Activity}. In this case, the developer would not want the
235+ * {@link FlutterEngine} to have access to the {@code Activity}, which can be accomplished by
236+ * setting {@code shouldAttachEngineToActivity} to {@code false}.
237+ */
238+ @ NonNull
239+ public Builder shouldAttachEngineToActivity (boolean shouldAttachEngineToActivity ) {
240+ this .shouldAttachEngineToActivity = shouldAttachEngineToActivity ;
241+ return this ;
242+ }
243+
202244 /**
203245 * Creates a {@link Bundle} of arguments that are assigned to the new {@code FlutterFragment}.
204246 * <p>
@@ -217,6 +259,7 @@ protected Bundle createArgs() {
217259 }
218260 args .putString (ARG_FLUTTERVIEW_RENDER_MODE , renderMode != null ? renderMode .name () : FlutterView .RenderMode .surface .name ());
219261 args .putString (ARG_FLUTTERVIEW_TRANSPARENCY_MODE , transparencyMode != null ? transparencyMode .name () : FlutterView .TransparencyMode .transparent .name ());
262+ args .putBoolean (ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY , shouldAttachEngineToActivity );
220263 return args ;
221264 }
222265
@@ -303,10 +346,12 @@ public void onAttach(Context context) {
303346 // use-cases.
304347 platformPlugin = new PlatformPlugin (getActivity (), flutterEngine .getPlatformChannel ());
305348
306- // Notify any plugins that are currently attached to our FlutterEngine that they
307- // are now attached to an Activity.
308- // TODO(mattcarroll): send in a real lifecycle.
309- flutterEngine .getActivityControlSurface ().attachToActivity (getActivity (), null );
349+ if (shouldAttachEngineToActivity ()) {
350+ // Notify any plugins that are currently attached to our FlutterEngine that they
351+ // are now attached to an Activity.
352+ // TODO(mattcarroll): send in a real lifecycle.
353+ flutterEngine .getActivityControlSurface ().attachToActivity (getActivity (), null );
354+ }
310355 }
311356
312357 private void initializeFlutter (@ NonNull Context context ) {
@@ -543,9 +588,11 @@ public void onDetach() {
543588 super .onDetach ();
544589 Log .d (TAG , "onDetach()" );
545590
546- // Notify plugins that they are no longer attached to an Activity.
547- // TODO(mattcarroll): differentiate between detaching for config changes and otherwise.
548- flutterEngine .getActivityControlSurface ().detachFromActivity ();
591+ if (shouldAttachEngineToActivity ()) {
592+ // Notify plugins that they are no longer attached to an Activity.
593+ // TODO(mattcarroll): differentiate between detaching for config changes and otherwise.
594+ flutterEngine .getActivityControlSurface ().detachFromActivity ();
595+ }
549596
550597 // Null out the platformPlugin to avoid a possible retain cycle between the plugin, this Fragment,
551598 // and this Fragment's Activity.
@@ -572,6 +619,10 @@ protected boolean retainFlutterEngineAfterFragmentDestruction() {
572619 return false ;
573620 }
574621
622+ protected boolean shouldAttachEngineToActivity () {
623+ return getArguments ().getBoolean (ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY );
624+ }
625+
575626 /**
576627 * The hardware back button was pressed.
577628 *
0 commit comments