• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package io.flutter.embedding.engine;
6 
7 import android.app.Activity;
8 import android.app.Service;
9 import android.arch.lifecycle.Lifecycle;
10 import android.content.BroadcastReceiver;
11 import android.content.ContentProvider;
12 import android.content.Context;
13 import android.content.Intent;
14 import android.support.annotation.NonNull;
15 import android.support.annotation.Nullable;
16 
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.Map;
20 import java.util.Set;
21 
22 import io.flutter.Log;
23 import io.flutter.embedding.engine.plugins.FlutterPlugin;
24 import io.flutter.embedding.engine.plugins.PluginRegistry;
25 import io.flutter.embedding.engine.plugins.activity.ActivityAware;
26 import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface;
27 import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
28 import io.flutter.embedding.engine.plugins.broadcastreceiver.BroadcastReceiverAware;
29 import io.flutter.embedding.engine.plugins.broadcastreceiver.BroadcastReceiverControlSurface;
30 import io.flutter.embedding.engine.plugins.broadcastreceiver.BroadcastReceiverPluginBinding;
31 import io.flutter.embedding.engine.plugins.contentprovider.ContentProviderAware;
32 import io.flutter.embedding.engine.plugins.contentprovider.ContentProviderControlSurface;
33 import io.flutter.embedding.engine.plugins.contentprovider.ContentProviderPluginBinding;
34 import io.flutter.embedding.engine.plugins.service.ServiceAware;
35 import io.flutter.embedding.engine.plugins.service.ServiceControlSurface;
36 import io.flutter.embedding.engine.plugins.service.ServicePluginBinding;
37 import io.flutter.plugin.platform.PlatformViewsController;
38 
39 class FlutterEnginePluginRegistry implements PluginRegistry,
40     ActivityControlSurface,
41     ServiceControlSurface,
42     BroadcastReceiverControlSurface,
43     ContentProviderControlSurface {
44   private static final String TAG = "FlutterEnginePluginRegistry";
45 
46   // PluginRegistry
47   @NonNull
48   private final Map<Class<? extends FlutterPlugin>, FlutterPlugin> plugins = new HashMap<>();
49 
50   // Standard FlutterPlugin
51   @NonNull
52   private final FlutterPlugin.FlutterPluginBinding pluginBinding;
53   @NonNull
54   private final FlutterEngineAndroidLifecycle flutterEngineAndroidLifecycle;
55 
56   // ActivityAware
57   @NonNull
58   private final Map<Class<? extends FlutterPlugin>, ActivityAware> activityAwarePlugins = new HashMap<>();
59   @Nullable
60   private Activity activity;
61   @Nullable
62   private FlutterEngineActivityPluginBinding activityPluginBinding;
63   private boolean isWaitingForActivityReattachment = false;
64 
65   // ServiceAware
66   @NonNull
67   private final Map<Class<? extends FlutterPlugin>, ServiceAware> serviceAwarePlugins = new HashMap<>();
68   @Nullable
69   private Service service;
70   @Nullable
71   private FlutterEngineServicePluginBinding servicePluginBinding;
72 
73   // BroadcastReceiver
74   @NonNull
75   private final Map<Class<? extends FlutterPlugin>, BroadcastReceiverAware> broadcastReceiverAwarePlugins = new HashMap<>();
76   @Nullable
77   private BroadcastReceiver broadcastReceiver;
78   @Nullable
79   private FlutterEngineBroadcastReceiverPluginBinding broadcastReceiverPluginBinding;
80 
81   // ContentProvider
82   @NonNull
83   private final Map<Class<? extends FlutterPlugin>, ContentProviderAware> contentProviderAwarePlugins = new HashMap<>();
84   @Nullable
85   private ContentProvider contentProvider;
86   @Nullable
87   private FlutterEngineContentProviderPluginBinding contentProviderPluginBinding;
88 
FlutterEnginePluginRegistry( @onNull Context appContext, @NonNull FlutterEngine flutterEngine, @NonNull FlutterEngineAndroidLifecycle lifecycle )89   FlutterEnginePluginRegistry(
90       @NonNull Context appContext,
91       @NonNull FlutterEngine flutterEngine,
92       @NonNull FlutterEngineAndroidLifecycle lifecycle
93   ) {
94     flutterEngineAndroidLifecycle = lifecycle;
95     pluginBinding = new FlutterPlugin.FlutterPluginBinding(
96         appContext,
97         flutterEngine,
98         lifecycle
99     );
100   }
101 
destroy()102   public void destroy() {
103     Log.d(TAG, "Destroying.");
104     // Detach from any Android component that we may currently be attached to, e.g., Activity, Service,
105     // BroadcastReceiver, ContentProvider. This must happen before removing all plugins so that the
106     // plugins have an opportunity to clean up references as a result of component detachment.
107     detachFromAndroidComponent();
108 
109     // Push FlutterEngine's Lifecycle to the DESTROYED state. This must happen before removing all
110     // plugins so that the plugins have an opportunity to clean up references as a result of moving
111     // to the DESTROYED state.
112     flutterEngineAndroidLifecycle.destroy();
113 
114     // Remove all registered plugins.
115     removeAll();
116   }
117 
118   @Override
add(@onNull FlutterPlugin plugin)119   public void add(@NonNull FlutterPlugin plugin) {
120     Log.v(TAG, "Adding plugin: " + plugin);
121     // Add the plugin to our generic set of plugins and notify the plugin
122     // that is has been attached to an engine.
123     plugins.put(plugin.getClass(), plugin);
124     plugin.onAttachedToEngine(pluginBinding);
125 
126     // For ActivityAware plugins, add the plugin to our set of ActivityAware
127     // plugins, and if this engine is currently attached to an Activity,
128     // notify the ActivityAware plugin that it is now attached to an Activity.
129     if (plugin instanceof ActivityAware) {
130       ActivityAware activityAware = (ActivityAware) plugin;
131       activityAwarePlugins.put(plugin.getClass(), activityAware);
132 
133       if (isAttachedToActivity()) {
134         activityAware.onAttachedToActivity(activityPluginBinding);
135       }
136     }
137 
138     // For ServiceAware plugins, add the plugin to our set of ServiceAware
139     // plugins, and if this engine is currently attached to a Service,
140     // notify the ServiceAware plugin that it is now attached to a Service.
141     if (plugin instanceof ServiceAware) {
142       ServiceAware serviceAware = (ServiceAware) plugin;
143       serviceAwarePlugins.put(plugin.getClass(), serviceAware);
144 
145       if (isAttachedToService()) {
146         serviceAware.onAttachedToService(servicePluginBinding);
147       }
148     }
149 
150     // For BroadcastReceiverAware plugins, add the plugin to our set of BroadcastReceiverAware
151     // plugins, and if this engine is currently attached to a BroadcastReceiver,
152     // notify the BroadcastReceiverAware plugin that it is now attached to a BroadcastReceiver.
153     if (plugin instanceof BroadcastReceiverAware) {
154       BroadcastReceiverAware broadcastReceiverAware = (BroadcastReceiverAware) plugin;
155       broadcastReceiverAwarePlugins.put(plugin.getClass(), broadcastReceiverAware);
156 
157       if (isAttachedToBroadcastReceiver()) {
158         broadcastReceiverAware.onAttachedToBroadcastReceiver(broadcastReceiverPluginBinding);
159       }
160     }
161 
162     // For ContentProviderAware plugins, add the plugin to our set of ContentProviderAware
163     // plugins, and if this engine is currently attached to a ContentProvider,
164     // notify the ContentProviderAware plugin that it is now attached to a ContentProvider.
165     if (plugin instanceof ContentProviderAware) {
166       ContentProviderAware contentProviderAware = (ContentProviderAware) plugin;
167       contentProviderAwarePlugins.put(plugin.getClass(), contentProviderAware);
168 
169       if (isAttachedToContentProvider()) {
170         contentProviderAware.onAttachedToContentProvider(contentProviderPluginBinding);
171       }
172     }
173   }
174 
175   @Override
add(@onNull Set<FlutterPlugin> plugins)176   public void add(@NonNull Set<FlutterPlugin> plugins) {
177     for (FlutterPlugin plugin : plugins) {
178       add(plugin);
179     }
180   }
181 
182   @Override
has(@onNull Class<? extends FlutterPlugin> pluginClass)183   public boolean has(@NonNull Class<? extends FlutterPlugin> pluginClass) {
184     return plugins.containsKey(pluginClass);
185   }
186 
187   @Override
get(@onNull Class<? extends FlutterPlugin> pluginClass)188   public FlutterPlugin get(@NonNull Class<? extends FlutterPlugin> pluginClass) {
189     return plugins.get(pluginClass);
190   }
191 
192   @Override
remove(@onNull Class<? extends FlutterPlugin> pluginClass)193   public void remove(@NonNull Class<? extends FlutterPlugin> pluginClass) {
194     FlutterPlugin plugin = plugins.get(pluginClass);
195     if (plugin != null) {
196       Log.v(TAG, "Removing plugin: " + plugin);
197       // For ActivityAware plugins, notify the plugin that it is detached from
198       // an Activity if an Activity is currently attached to this engine. Then
199       // remove the plugin from our set of ActivityAware plugins.
200       if (plugin instanceof ActivityAware) {
201         if (isAttachedToActivity()) {
202           ActivityAware activityAware = (ActivityAware) plugin;
203           activityAware.onDetachedFromActivity();
204         }
205         activityAwarePlugins.remove(pluginClass);
206       }
207 
208       // For ServiceAware plugins, notify the plugin that it is detached from
209       // a Service if a Service is currently attached to this engine. Then
210       // remove the plugin from our set of ServiceAware plugins.
211       if (plugin instanceof ServiceAware) {
212         if (isAttachedToService()) {
213           ServiceAware serviceAware = (ServiceAware) plugin;
214           serviceAware.onDetachedFromService();
215         }
216         serviceAwarePlugins.remove(pluginClass);
217       }
218 
219       // For BroadcastReceiverAware plugins, notify the plugin that it is detached from
220       // a BroadcastReceiver if a BroadcastReceiver is currently attached to this engine. Then
221       // remove the plugin from our set of BroadcastReceiverAware plugins.
222       if (plugin instanceof BroadcastReceiverAware) {
223         if (isAttachedToBroadcastReceiver()) {
224           BroadcastReceiverAware broadcastReceiverAware = (BroadcastReceiverAware) plugin;
225           broadcastReceiverAware.onDetachedFromBroadcastReceiver();
226         }
227         broadcastReceiverAwarePlugins.remove(pluginClass);
228       }
229 
230       // For ContentProviderAware plugins, notify the plugin that it is detached from
231       // a ContentProvider if a ContentProvider is currently attached to this engine. Then
232       // remove the plugin from our set of ContentProviderAware plugins.
233       if (plugin instanceof ContentProviderAware) {
234         if (isAttachedToContentProvider()) {
235           ContentProviderAware contentProviderAware = (ContentProviderAware) plugin;
236           contentProviderAware.onDetachedFromContentProvider();
237         }
238         contentProviderAwarePlugins.remove(pluginClass);
239       }
240 
241       // Notify the plugin that is now detached from this engine. Then remove
242       // it from our set of generic plugins.
243       plugin.onDetachedFromEngine(pluginBinding);
244       plugins.remove(pluginClass);
245     }
246   }
247 
248   @Override
remove(@onNull Set<Class<? extends FlutterPlugin>> pluginClasses)249   public void remove(@NonNull Set<Class<? extends FlutterPlugin>> pluginClasses) {
250     for (Class<? extends FlutterPlugin> pluginClass : pluginClasses) {
251       remove(pluginClass);
252     }
253   }
254 
255   @Override
removeAll()256   public void removeAll() {
257     // We copy the keys to a new set so that we can mutate the set while using
258     // the keys.
259     remove(new HashSet<>(plugins.keySet()));
260     plugins.clear();
261   }
262 
detachFromAndroidComponent()263   private void detachFromAndroidComponent() {
264     if (isAttachedToActivity()) {
265       detachFromActivity();
266     } else if (isAttachedToService()) {
267       detachFromService();
268     } else if (isAttachedToBroadcastReceiver()) {
269       detachFromBroadcastReceiver();
270     } else if (isAttachedToContentProvider()) {
271       detachFromContentProvider();
272     }
273   }
274 
275   //-------- Start ActivityControlSurface -------
isAttachedToActivity()276   private boolean isAttachedToActivity() {
277     return activity != null;
278   }
279 
280   @Override
attachToActivity( @onNull Activity activity, @NonNull Lifecycle lifecycle )281   public void attachToActivity(
282       @NonNull Activity activity,
283       @NonNull Lifecycle lifecycle
284   ) {
285     Log.v(TAG, "Attaching to an Activity: " + activity + "."
286         + (isWaitingForActivityReattachment ? " This is after a config change." : ""));
287     // If we were already attached to an Android component, detach from it.
288     detachFromAndroidComponent();
289 
290     this.activity = activity;
291     this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity);
292     this.flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle);
293 
294     // Activate the PlatformViewsController. This must happen before any plugins attempt
295     // to use it, otherwise an error stack trace will appear that says there is no
296     // flutter/platform_views channel.
297     pluginBinding.getFlutterEngine().getPlatformViewsController().attach(
298         activity,
299         pluginBinding.getFlutterEngine().getRenderer(),
300         pluginBinding.getFlutterEngine().getDartExecutor()
301     );
302 
303     // Notify all ActivityAware plugins that they are now attached to a new Activity.
304     for (ActivityAware activityAware : activityAwarePlugins.values()) {
305       if (isWaitingForActivityReattachment) {
306         activityAware.onReattachedToActivityForConfigChanges(activityPluginBinding);
307       } else {
308         activityAware.onAttachedToActivity(activityPluginBinding);
309       }
310     }
311     isWaitingForActivityReattachment = false;
312   }
313 
314   @Override
detachFromActivityForConfigChanges()315   public void detachFromActivityForConfigChanges() {
316     if (isAttachedToActivity()) {
317       Log.v(TAG, "Detaching from an Activity for config changes: " + activity);
318       isWaitingForActivityReattachment = true;
319 
320       for (ActivityAware activityAware : activityAwarePlugins.values()) {
321         activityAware.onDetachedFromActivityForConfigChanges();
322       }
323 
324       // Deactivate PlatformViewsController.
325       pluginBinding.getFlutterEngine().getPlatformViewsController().detach();
326 
327       flutterEngineAndroidLifecycle.setBackingLifecycle(null);
328       activity = null;
329       activityPluginBinding = null;
330     } else {
331       Log.e(TAG, "Attempted to detach plugins from an Activity when no Activity was attached.");
332     }
333   }
334 
335   @Override
detachFromActivity()336   public void detachFromActivity() {
337     if (isAttachedToActivity()) {
338       Log.v(TAG, "Detaching from an Activity: " + activity);
339       for (ActivityAware activityAware : activityAwarePlugins.values()) {
340         activityAware.onDetachedFromActivity();
341       }
342 
343       // Deactivate PlatformViewsController.
344       pluginBinding.getFlutterEngine().getPlatformViewsController().detach();
345 
346       flutterEngineAndroidLifecycle.setBackingLifecycle(null);
347       activity = null;
348       activityPluginBinding = null;
349     } else {
350       Log.e(TAG, "Attempted to detach plugins from an Activity when no Activity was attached.");
351     }
352   }
353 
354   @Override
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResult)355   public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResult) {
356     Log.v(TAG, "Forwarding onRequestPermissionsResult() to plugins.");
357     if (isAttachedToActivity()) {
358       return activityPluginBinding.onRequestPermissionsResult(requestCode, permissions, grantResult);
359     } else {
360       Log.e(TAG, "Attempted to notify ActivityAware plugins of onRequestPermissionsResult, but no Activity was attached.");
361       return false;
362     }
363   }
364 
365   @Override
onActivityResult(int requestCode, int resultCode, @Nullable Intent data)366   public boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
367     Log.v(TAG, "Forwarding onActivityResult() to plugins.");
368     if (isAttachedToActivity()) {
369       return activityPluginBinding.onActivityResult(requestCode, resultCode, data);
370     } else {
371       Log.e(TAG, "Attempted to notify ActivityAware plugins of onActivityResult, but no Activity was attached.");
372       return false;
373     }
374   }
375 
376   @Override
onNewIntent(@onNull Intent intent)377   public void onNewIntent(@NonNull Intent intent) {
378     Log.v(TAG, "Forwarding onNewIntent() to plugins.");
379     if (isAttachedToActivity()) {
380       activityPluginBinding.onNewIntent(intent);
381     } else {
382       Log.e(TAG, "Attempted to notify ActivityAware plugins of onNewIntent, but no Activity was attached.");
383     }
384   }
385 
386   @Override
onUserLeaveHint()387   public void onUserLeaveHint() {
388     Log.v(TAG, "Forwarding onUserLeaveHint() to plugins.");
389     if (isAttachedToActivity()) {
390       activityPluginBinding.onUserLeaveHint();
391     } else {
392       Log.e(TAG, "Attempted to notify ActivityAware plugins of onUserLeaveHint, but no Activity was attached.");
393     }
394   }
395   //------- End ActivityControlSurface -----
396 
397   //----- Start ServiceControlSurface ----
isAttachedToService()398   private boolean isAttachedToService() {
399     return service != null;
400   }
401 
402   @Override
attachToService(@onNull Service service, @NonNull Lifecycle lifecycle, boolean isForeground)403   public void attachToService(@NonNull Service service, @NonNull Lifecycle lifecycle, boolean isForeground) {
404     Log.v(TAG, "Attaching to a Service: " + service);
405     // If we were already attached to an Android component, detach from it.
406     detachFromAndroidComponent();
407 
408     this.service = service;
409     this.servicePluginBinding = new FlutterEngineServicePluginBinding(service);
410     flutterEngineAndroidLifecycle.setBackingLifecycle(lifecycle);
411 
412     // Notify all ServiceAware plugins that they are now attached to a new Service.
413     for (ServiceAware serviceAware : serviceAwarePlugins.values()) {
414       serviceAware.onAttachedToService(servicePluginBinding);
415     }
416   }
417 
418   @Override
detachFromService()419   public void detachFromService() {
420     if (isAttachedToService()) {
421       Log.v(TAG, "Detaching from a Service: " + service);
422       // Notify all ServiceAware plugins that they are no longer attached to a Service.
423       for (ServiceAware serviceAware : serviceAwarePlugins.values()) {
424         serviceAware.onDetachedFromService();
425       }
426 
427       flutterEngineAndroidLifecycle.setBackingLifecycle(null);
428       service = null;
429       servicePluginBinding = null;
430     } else {
431       Log.e(TAG, "Attempted to detach plugins from a Service when no Service was attached.");
432     }
433   }
434 
435   @Override
onMoveToForeground()436   public void onMoveToForeground() {
437     if (isAttachedToService()) {
438       Log.v(TAG, "Attached Service moved to foreground.");
439       servicePluginBinding.onMoveToForeground();
440     }
441   }
442 
443   @Override
onMoveToBackground()444   public void onMoveToBackground() {
445     if (isAttachedToService()) {
446       Log.v(TAG, "Attached Service moved to background.");
447       servicePluginBinding.onMoveToBackground();
448     }
449   }
450   //----- End ServiceControlSurface ---
451 
452   //----- Start BroadcastReceiverControlSurface ---
isAttachedToBroadcastReceiver()453   private boolean isAttachedToBroadcastReceiver() {
454     return broadcastReceiver != null;
455   }
456 
457   @Override
attachToBroadcastReceiver(@onNull BroadcastReceiver broadcastReceiver, @NonNull Lifecycle lifecycle)458   public void attachToBroadcastReceiver(@NonNull BroadcastReceiver broadcastReceiver, @NonNull Lifecycle lifecycle) {
459     Log.v(TAG, "Attaching to BroadcastReceiver: " + broadcastReceiver);
460     // If we were already attached to an Android component, detach from it.
461     detachFromAndroidComponent();
462 
463     this.broadcastReceiver = broadcastReceiver;
464     this.broadcastReceiverPluginBinding = new FlutterEngineBroadcastReceiverPluginBinding(broadcastReceiver);
465     // TODO(mattcarroll): resolve possibility of different lifecycles between this and engine attachment
466 
467     // Notify all BroadcastReceiverAware plugins that they are now attached to a new BroadcastReceiver.
468     for (BroadcastReceiverAware broadcastReceiverAware : broadcastReceiverAwarePlugins.values()) {
469       broadcastReceiverAware.onAttachedToBroadcastReceiver(broadcastReceiverPluginBinding);
470     }
471   }
472 
473   @Override
detachFromBroadcastReceiver()474   public void detachFromBroadcastReceiver() {
475     if (isAttachedToBroadcastReceiver()) {
476       Log.v(TAG, "Detaching from BroadcastReceiver: " + broadcastReceiver);
477       // Notify all BroadcastReceiverAware plugins that they are no longer attached to a BroadcastReceiver.
478       for (BroadcastReceiverAware broadcastReceiverAware : broadcastReceiverAwarePlugins.values()) {
479         broadcastReceiverAware.onDetachedFromBroadcastReceiver();
480       }
481     } else {
482       Log.e(TAG, "Attempted to detach plugins from a BroadcastReceiver when no BroadcastReceiver was attached.");
483     }
484   }
485   //----- End BroadcastReceiverControlSurface ----
486 
487   //----- Start ContentProviderControlSurface ----
isAttachedToContentProvider()488   private boolean isAttachedToContentProvider() {
489     return contentProvider != null;
490   }
491 
492   @Override
attachToContentProvider(@onNull ContentProvider contentProvider, @NonNull Lifecycle lifecycle)493   public void attachToContentProvider(@NonNull ContentProvider contentProvider, @NonNull Lifecycle lifecycle) {
494     Log.v(TAG, "Attaching to ContentProvider: " + contentProvider);
495     // If we were already attached to an Android component, detach from it.
496     detachFromAndroidComponent();
497 
498     this.contentProvider = contentProvider;
499     this.contentProviderPluginBinding = new FlutterEngineContentProviderPluginBinding(contentProvider);
500     // TODO(mattcarroll): resolve possibility of different lifecycles between this and engine attachment
501 
502     // Notify all ContentProviderAware plugins that they are now attached to a new ContentProvider.
503     for (ContentProviderAware contentProviderAware : contentProviderAwarePlugins.values()) {
504       contentProviderAware.onAttachedToContentProvider(contentProviderPluginBinding);
505     }
506   }
507 
508   @Override
detachFromContentProvider()509   public void detachFromContentProvider() {
510     if (isAttachedToContentProvider()) {
511       Log.v(TAG, "Detaching from ContentProvider: " + contentProvider);
512       // Notify all ContentProviderAware plugins that they are no longer attached to a ContentProvider.
513       for (ContentProviderAware contentProviderAware : contentProviderAwarePlugins.values()) {
514         contentProviderAware.onDetachedFromContentProvider();
515       }
516     } else {
517       Log.e(TAG, "Attempted to detach plugins from a ContentProvider when no ContentProvider was attached.");
518     }
519   }
520   //----- End ContentProviderControlSurface -----
521 
522   private static class FlutterEngineActivityPluginBinding implements ActivityPluginBinding {
523     @NonNull
524     private final Activity activity;
525     @NonNull
526     private final Set<io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener> onRequestPermissionsResultListeners = new HashSet<>();
527     @NonNull
528     private final Set<io.flutter.plugin.common.PluginRegistry.ActivityResultListener> onActivityResultListeners = new HashSet<>();
529     @NonNull
530     private final Set<io.flutter.plugin.common.PluginRegistry.NewIntentListener> onNewIntentListeners = new HashSet<>();
531     @NonNull
532     private final Set<io.flutter.plugin.common.PluginRegistry.UserLeaveHintListener> onUserLeaveHintListeners = new HashSet<>();
533 
FlutterEngineActivityPluginBinding(@onNull Activity activity)534     public FlutterEngineActivityPluginBinding(@NonNull Activity activity) {
535       this.activity = activity;
536     }
537 
538     @Override
539     @NonNull
getActivity()540     public Activity getActivity() {
541       return activity;
542     }
543 
544     @Override
addRequestPermissionsResultListener(@onNull io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener listener)545     public void addRequestPermissionsResultListener(@NonNull io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener listener) {
546       onRequestPermissionsResultListeners.add(listener);
547     }
548 
549     @Override
removeRequestPermissionsResultListener(@onNull io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener listener)550     public void removeRequestPermissionsResultListener(@NonNull io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener listener) {
551       onRequestPermissionsResultListeners.remove(listener);
552     }
553 
554     /**
555      * Invoked by the {@link FlutterEngine} that owns this {@code ActivityPluginBinding} when its
556      * associated {@link Activity} has its {@code onRequestPermissionsResult(...)} method invoked.
557      */
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResult)558     boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResult) {
559       boolean didConsumeResult = false;
560       for (io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener listener : onRequestPermissionsResultListeners) {
561         didConsumeResult = listener.onRequestPermissionsResult(requestCode, permissions, grantResult) || didConsumeResult;
562       }
563       return didConsumeResult;
564     }
565 
566     @Override
addActivityResultListener(@onNull io.flutter.plugin.common.PluginRegistry.ActivityResultListener listener)567     public void addActivityResultListener(@NonNull io.flutter.plugin.common.PluginRegistry.ActivityResultListener listener) {
568       onActivityResultListeners.add(listener);
569     }
570 
571     @Override
removeActivityResultListener(@onNull io.flutter.plugin.common.PluginRegistry.ActivityResultListener listener)572     public void removeActivityResultListener(@NonNull io.flutter.plugin.common.PluginRegistry.ActivityResultListener listener) {
573       onActivityResultListeners.remove(listener);
574     }
575 
576     /**
577      * Invoked by the {@link FlutterEngine} that owns this {@code ActivityPluginBinding} when its
578      * associated {@link Activity} has its {@code onActivityResult(...)} method invoked.
579      */
onActivityResult(int requestCode, int resultCode, @Nullable Intent data)580     boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
581       boolean didConsumeResult = false;
582       for (io.flutter.plugin.common.PluginRegistry.ActivityResultListener listener : onActivityResultListeners) {
583         didConsumeResult = listener.onActivityResult(requestCode, resultCode, data) || didConsumeResult;
584       }
585       return didConsumeResult;
586     }
587 
588     @Override
addOnNewIntentListener(@onNull io.flutter.plugin.common.PluginRegistry.NewIntentListener listener)589     public void addOnNewIntentListener(@NonNull io.flutter.plugin.common.PluginRegistry.NewIntentListener listener) {
590       onNewIntentListeners.add(listener);
591     }
592 
593     @Override
removeOnNewIntentListener(@onNull io.flutter.plugin.common.PluginRegistry.NewIntentListener listener)594     public void removeOnNewIntentListener(@NonNull io.flutter.plugin.common.PluginRegistry.NewIntentListener listener) {
595       onNewIntentListeners.remove(listener);
596     }
597 
598     /**
599      * Invoked by the {@link FlutterEngine} that owns this {@code ActivityPluginBinding} when its
600      * associated {@link Activity} has its {@code onNewIntent(...)} method invoked.
601      */
onNewIntent(@ullable Intent intent)602     void onNewIntent(@Nullable Intent intent) {
603       for (io.flutter.plugin.common.PluginRegistry.NewIntentListener listener : onNewIntentListeners) {
604         listener.onNewIntent(intent);
605       }
606     }
607 
608     @Override
addOnUserLeaveHintListener(@onNull io.flutter.plugin.common.PluginRegistry.UserLeaveHintListener listener)609     public void addOnUserLeaveHintListener(@NonNull io.flutter.plugin.common.PluginRegistry.UserLeaveHintListener listener) {
610       onUserLeaveHintListeners.add(listener);
611     }
612 
613     @Override
removeOnUserLeaveHintListener(@onNull io.flutter.plugin.common.PluginRegistry.UserLeaveHintListener listener)614     public void removeOnUserLeaveHintListener(@NonNull io.flutter.plugin.common.PluginRegistry.UserLeaveHintListener listener) {
615       onUserLeaveHintListeners.remove(listener);
616     }
617 
618     /**
619      * Invoked by the {@link FlutterEngine} that owns this {@code ActivityPluginBinding} when its
620      * associated {@link Activity} has its {@code onUserLeaveHint()} method invoked.
621      */
onUserLeaveHint()622     void onUserLeaveHint() {
623       for (io.flutter.plugin.common.PluginRegistry.UserLeaveHintListener listener : onUserLeaveHintListeners) {
624         listener.onUserLeaveHint();
625       }
626     }
627   }
628 
629   private static class FlutterEngineServicePluginBinding implements ServicePluginBinding {
630     @NonNull
631     private final Service service;
632     @NonNull
633     private final Set<ServiceAware.OnModeChangeListener> onModeChangeListeners = new HashSet<>();
634 
FlutterEngineServicePluginBinding(@onNull Service service)635     FlutterEngineServicePluginBinding(@NonNull Service service) {
636       this.service = service;
637     }
638 
639     @Override
640     @NonNull
getService()641     public Service getService() {
642       return service;
643     }
644 
645     @Override
addOnModeChangeListener(@onNull ServiceAware.OnModeChangeListener listener)646     public void addOnModeChangeListener(@NonNull ServiceAware.OnModeChangeListener listener) {
647       onModeChangeListeners.add(listener);
648     }
649 
650     @Override
removeOnModeChangeListener(@onNull ServiceAware.OnModeChangeListener listener)651     public void removeOnModeChangeListener(@NonNull ServiceAware.OnModeChangeListener listener) {
652       onModeChangeListeners.remove(listener);
653     }
654 
onMoveToForeground()655     void onMoveToForeground() {
656       for (ServiceAware.OnModeChangeListener listener : onModeChangeListeners) {
657         listener.onMoveToForeground();
658       }
659     }
660 
onMoveToBackground()661     void onMoveToBackground() {
662       for (ServiceAware.OnModeChangeListener listener : onModeChangeListeners) {
663         listener.onMoveToBackground();
664       }
665     }
666   }
667 
668   private static class FlutterEngineBroadcastReceiverPluginBinding implements BroadcastReceiverPluginBinding {
669     @NonNull
670     private final BroadcastReceiver broadcastReceiver;
671 
FlutterEngineBroadcastReceiverPluginBinding(@onNull BroadcastReceiver broadcastReceiver)672     FlutterEngineBroadcastReceiverPluginBinding(@NonNull BroadcastReceiver broadcastReceiver) {
673       this.broadcastReceiver = broadcastReceiver;
674     }
675 
676     @NonNull
677     @Override
getBroadcastReceiver()678     public BroadcastReceiver getBroadcastReceiver() {
679       return broadcastReceiver;
680     }
681   }
682 
683   private static class FlutterEngineContentProviderPluginBinding implements ContentProviderPluginBinding {
684     @NonNull
685     private final ContentProvider contentProvider;
686 
FlutterEngineContentProviderPluginBinding(@onNull ContentProvider contentProvider)687     FlutterEngineContentProviderPluginBinding(@NonNull ContentProvider contentProvider) {
688       this.contentProvider = contentProvider;
689     }
690 
691     @NonNull
692     @Override
getContentProvider()693     public ContentProvider getContentProvider() {
694       return contentProvider;
695     }
696   }
697 }
698