react-native/Libraries/Utilities/BackAndroid.android.js
Serhij Korochanskyj b8576312ca Fix BackAndroid subscriptions calls
Summary:
`BackAndroid` JS event subscriptions should be called in reverse order
(the subscription from the latest `addEventLister` should run first).

Also if listener returns true, don't call other listeners.

**Motivation**: We use `BackAndroid` listeners to prevent closing screens with user's input.
When we have two screens in stack (each screen with listener, which show alerts),
we want to show alert only from the last screen listener, not from all.
Closes https://github.com/facebook/react-native/pull/8929

Differential Revision: D3598978

Pulled By: dmmiller

fbshipit-source-id: a7b0762b36a60755a844e90fffd58887f89c9ffb
2016-07-21 08:58:24 -07:00

83 lines
2.0 KiB
JavaScript

/**
* Copyright (c) 2015-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 BackAndroid
*/
'use strict';
var DeviceEventManager = require('NativeModules').DeviceEventManager;
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var DEVICE_BACK_EVENT = 'hardwareBackPress';
type BackPressEventName = $Enum<{
backPress: string;
}>;
var _backPressSubscriptions = new Set();
RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
var backPressSubscriptions = new Set(_backPressSubscriptions);
var invokeDefault = true;
var subscriptions = [...backPressSubscriptions].reverse();
for (var i = 0; i < subscriptions.length; ++i) {
if (subscriptions[i]()) {
invokeDefault = false;
break;
};
}
if (invokeDefault) {
BackAndroid.exitApp();
}
});
/**
* Detect hardware back button presses, and programmatically invoke the default back button
* functionality to exit the app if there are no listeners or if none of the listeners return true.
*
* Example:
*
* ```js
* BackAndroid.addEventListener('hardwareBackPress', function() {
* if (!this.onMainScreen()) {
* this.goBack();
* return true;
* }
* return false;
* });
* ```
*/
var BackAndroid = {
exitApp: function() {
DeviceEventManager.invokeDefaultBackPressHandler();
},
addEventListener: function (
eventName: BackPressEventName,
handler: Function
): {remove: () => void} {
_backPressSubscriptions.add(handler);
return {
remove: () => BackAndroid.removeEventListener(eventName, handler),
};
},
removeEventListener: function(
eventName: BackPressEventName,
handler: Function
): void {
_backPressSubscriptions.delete(handler);
},
};
module.exports = BackAndroid;