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