hunk.code_window:       return;
       }
       WritableMap result = Arguments.createMap();
       result.putString("type", "dismiss");
       mOpenBrowserPromise.resolve(result);
       mOpenBrowserPromise = null;
  
hunk.labels: keep keep add keep keep keep keep
hunk.after_edit:     EventBus.getDefault().unregister(this);
  
hunk.file_path: android/app/src/main/java/abi17_0_0/host/exp/exponent/modules/api/WebBrowserModule.java
hunk.type: add
file: /**
   * Copyright 2013-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   *
   * @providesModule EventPluginHub
   */
  
  'use strict';
  
  var EventPluginRegistry = require('EventPluginRegistry');
  var EventPluginUtils = require('EventPluginUtils');
  var ReactErrorUtils = require('ReactErrorUtils');
  
  var accumulateInto = require('accumulateInto');
  var forEachAccumulated = require('forEachAccumulated');
  var invariant = require('fbjs/lib/invariant');
  
  /**
   * Internal queue of events that have accumulated their dispatches and are
   * waiting to have their dispatches executed.
   */
  var eventQueue = null;
  
  /**
   * Dispatches an event and releases it back into the pool, unless persistent.
   *
   * @param {?object} event Synthetic event to be dispatched.
   * @param {boolean} simulated If the event is simulated (changes exn behavior)
   * @private
   */
  var executeDispatchesAndRelease = function(event, simulated) {
    if (event) {
      EventPluginUtils.executeDispatchesInOrder(event, simulated);
  
      if (!event.isPersistent()) {
        event.constructor.release(event);
      }
    }
  };
  var executeDispatchesAndReleaseSimulated = function(e) {
    return executeDispatchesAndRelease(e, true);
  };
  var executeDispatchesAndReleaseTopLevel = function(e) {
    return executeDispatchesAndRelease(e, false);
  };
  
  function isInteractive(tag) {
    return (
      tag === 'button' || tag === 'input' ||
      tag === 'select' || tag === 'textarea'
    );
  }
  
  function shouldPreventMouseEvent(name, type, props) {
    switch (name) {
      case 'onClick':
      case 'onClickCapture':
      case 'onDoubleClick':
      case 'onDoubleClickCapture':
      case 'onMouseDown':
      case 'onMouseDownCapture':
      case 'onMouseMove':
      case 'onMouseMoveCapture':
      case 'onMouseUp':
      case 'onMouseUpCapture':
        return !!(props.disabled && isInteractive(type));
      default:
        return false;
    }
  }
  
  /**
   * This is a unified interface for event plugins to be installed and configured.
   *
   * Event plugins can implement the following properties:
   *
   *   `extractEvents` {function(string, DOMEventTarget, string, object): *}
   *     Required. When a top-level event is fired, this method is expected to
   *     extract synthetic events that will in turn be queued and dispatched.
   *
   *   `eventTypes` {object}
   *     Optional, plugins that fire events must publish a mapping of registration
   *     names that are used to register listeners. Values of this mapping must
   *     be objects that contain `registrationName` or `phasedRegistrationNames`.
   *
   *   `executeDispatch` {function(object, function, string)}
   *     Optional, allows plugins to override how an event gets dispatched. By
   *     default, the listener is simply invoked.
   *
   * Each plugin that is injected into `EventsPluginHub` is immediately operable.
   *
   * @public
   */
  var EventPluginHub = {
  
    /**
     * Methods for injecting dependencies.
     */
    injection: {
  
      /**
       * @param {array} InjectedEventPluginOrder
       * @public
       */
      injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
  
      /**
       * @param {object} injectedNamesToPlugins Map from names to plugin modules.
       */
      injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName,
  
    },
  
    /**
     * @param {object} inst The instance, which is the source of events.
     * @param {string} registrationName Name of listener (e.g. `onClick`).
     * @return {?function} The stored callback.
     */
    getListener: function(inst, registrationName) {
      var listener;
  
      // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
      // live here; needs to be moved to a better place soon
      if (typeof inst.tag === 'number') {
        const props = EventPluginUtils.getFiberCurrentPropsFromNode(
          inst.stateNode
        );
        if (!props) {
          // Work in progress.
          return null;
        }
        listener = props[registrationName];
        if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
          return null;
        }
      } else {
        if (typeof inst._currentElement === 'string') {
          // Text node, let it bubble through.
          return null;
        }
        if (!inst._rootNodeID) {
          // If the instance is already unmounted, we have no listeners.
          return null;
        }
        const props = inst._currentElement.props;
        listener = props[registrationName];
        if (shouldPreventMouseEvent(registrationName, inst._currentElement.type, props)) {
          return null;
        }
      }
  
      invariant(
        !listener || typeof listener === 'function',
        'Expected %s listener to be a function, instead got type %s',
        registrationName,
        typeof listener
      );
      return listener;
    },
  
    /**
     * Allows registered plugins an opportunity to extract events from top-level
     * native browser events.
     *
     * @return {*} An accumulation of synthetic events.
     * @internal
     */
    extractEvents: function(
        topLevelType,
        targetInst,
        nativeEvent,
        nativeEventTarget) {
      var events;
      var plugins = EventPluginRegistry.plugins;
      for (var i = 0; i < plugins.length; i++) {
        // Not every plugin in the ordering may be loaded at runtime.
        var possiblePlugin = plugins[i];
        if (possiblePlugin) {
          var extractedEvents = possiblePlugin.extractEvents(
            topLevelType,
            targetInst,
            nativeEvent,
            nativeEventTarget
          );
          if (extractedEvents) {
            events = accumulateInto(events, extractedEvents);
          }
        }
      }
      return events;
    },
  
    /**
     * Enqueues a synthetic event that should be dispatched when
     * `processEventQueue` is invoked.
     *
     * @param {*} events An accumulation of synthetic events.
     * @internal
     */
    enqueueEvents: function(events) {
      if (events) {
        eventQueue = accumulateInto(eventQueue, events);
      }
    },
  
    /**
     * Dispatches all synthetic events on the event queue.
     *
     * @internal
     */
    processEventQueue: function(simulated) {
      // Set `eventQueue` to null before processing it so that we can tell if more
      // events get enqueued while processing.
      var processingEventQueue = eventQueue;
      eventQueue = null;
      if (simulated) {
        forEachAccumulated(
          processingEventQueue,
          executeDispatchesAndReleaseSimulated
        );
      } else {
        forEachAccumulated(
          processingEventQueue,
          executeDispatchesAndReleaseTopLevel
        );
      }
      invariant(
        !eventQueue,
        'processEventQueue(): Additional events were enqueued while processing ' +
        'an event queue. Support for this has not yet been implemented.'
      );
      // This would be a good time to rethrow if any of the event handlers threw.
      ReactErrorUtils.rethrowCaughtError();
    },
  
  };
  
  module.exports = EventPluginHub;
  