Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move BackAndroid -> BackHandler, add Apple TV support for back nav #12571

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cfacc0f
Move BackAndroid -> BackHandler, add Apple TV support for back nav
douglowder Feb 24, 2017
901af84
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Feb 27, 2017
480c694
Generate warnings when BackAndroid is used
douglowder Feb 27, 2017
529bde3
Add BackHandler to docs list
douglowder Feb 27, 2017
f20012f
Doc comments for BackHandler and BackAndroid
douglowder Feb 27, 2017
c266c80
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Feb 27, 2017
19ad6af
Remove trailing spaces
douglowder Feb 27, 2017
d481d41
Remove extra lines, var -> const
douglowder Feb 28, 2017
d577afb
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 1, 2017
24b0d4d
Fix warning import in VirtualizedSectionList
douglowder Mar 1, 2017
819355d
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 2, 2017
e4f00f0
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 3, 2017
027ce13
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 3, 2017
441e60c
Fix UIExplorer example code to use BackHandler
douglowder Mar 3, 2017
2656bdc
Fix VirtualizedList for tvOS (FlatList example in UIExplorer is broke…
douglowder Mar 4, 2017
1f233dc
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 4, 2017
c2406cc
ScrollView shouldn't automatically use RefreshControl on tvOS
douglowder Mar 4, 2017
2e0376f
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 6, 2017
db26995
Merge remote-tracking branch 'upstream/master' into tvos-backhandler
douglowder Mar 6, 2017
883d255
Back out RefreshControl change for submission as a separate PR
douglowder Mar 6, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Examples/UIExplorer/js/UIExplorerApp.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

const AppRegistry = require('AppRegistry');
const AsyncStorage = require('AsyncStorage');
const BackAndroid = require('BackAndroid');
const BackHandler = require('BackHandler');
const Dimensions = require('Dimensions');
const DrawerLayoutAndroid = require('DrawerLayoutAndroid');
const Linking = require('Linking');
Expand Down Expand Up @@ -73,7 +73,7 @@ class UIExplorerApp extends React.Component {
state: UIExplorerNavigationState;

componentWillMount() {
BackAndroid.addEventListener('hardwareBackPress', this._handleBackButtonPress);
BackHandler.addEventListener('hardwareBackPress', this._handleBackButtonPress);
}

componentDidMount() {
Expand Down
5 changes: 5 additions & 0 deletions Examples/UIExplorer/js/UIExplorerApp.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
'use strict';

const AsyncStorage = require('AsyncStorage');
const BackHandler = require('BackHandler');
const Linking = require('Linking');
const React = require('react');
const ReactNative = require('react-native');
Expand Down Expand Up @@ -68,6 +69,10 @@ class UIExplorerApp extends React.Component {
props: Props;
state: UIExplorerNavigationState;

componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this._handleBack);
}

componentDidMount() {
Linking.getInitialURL().then((url) => {
AsyncStorage.getItem(APP_STATE_KEY, (err, storedString) => {
Expand Down
1 change: 1 addition & 0 deletions Libraries/Components/ScrollView/ScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ const ScrollView = React.createClass({
}

const refreshControl = this.props.refreshControl;

if (refreshControl) {
if (Platform.OS === 'ios') {
// On iOS the RefreshControl is a child of the ScrollView.
Expand Down
4 changes: 2 additions & 2 deletions Libraries/ReactNative/renderApplication.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ var ReactNative = require('ReactNative');

var invariant = require('fbjs/lib/invariant');

// require BackAndroid so it sets the default handler that exits the app if no listeners respond
require('BackAndroid');
// require BackHandler so it sets the default handler that exits the app if no listeners respond
require('BackHandler');

function renderApplication<Props: Object>(
RootComponent: ReactClass<Props>,
Expand Down
28 changes: 0 additions & 28 deletions Libraries/Utilities/BackAndroid.ios.js

This file was deleted.

49 changes: 49 additions & 0 deletions Libraries/Utilities/BackAndroid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* 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.
*
* BackAndroid has been moved to BackHandler. This stub calls BackHandler methods
* after generating a warning to remind users to move to the new BackHandler module.
*
* @providesModule BackAndroid
*/

'use strict';

var BackHandler = require('BackHandler');

var warning = require('fbjs/lib/warning');

/**
* Deprecated. Use BackHandler instead.
*/
var BackAndroid = {

exitApp: function() {
warning(false, 'BackAndroid is deprecated. Please use BackHandler instead.');
BackHandler.exitApp();
},

addEventListener: function (
eventName: BackPressEventName,
handler: Function
): {remove: () => void} {
warning(false, 'BackAndroid is deprecated. Please use BackHandler instead.');
return BackHandler.addEventListener(eventName, handler);
},

removeEventListener: function(
eventName: BackPressEventName,
handler: Function
): void {
warning(false, 'BackAndroid is deprecated. Please use BackHandler instead.');
BackHandler.removeEventListener(eventName, handler);
},

};

module.exports = BackAndroid;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* 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
* @providesModule BackHandler
*/

'use strict';
Expand Down Expand Up @@ -34,20 +34,29 @@ RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no-trailing-spaces: Trailing spaces not allowed.


if (invokeDefault) {
BackAndroid.exitApp();
BackHandler.exitApp();
}
});

/**
* Detect hardware back button presses, and programmatically invoke the default back button
* Detect hardware button presses for back navigation.
*
* Android: 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.
*
* tvOS: Detect presses of the menu button on the TV remote. (Still to be implemented:
* programmatically disable menu button handling
* functionality to exit the app if there are no listeners or if none of the listeners return true.)
*
* iOS: Not applicable.
*
* The event subscriptions are called in reverse order (i.e. last registered subscription first),
* and if one subscription returns true then subscriptions registered earlier will not be called.
*
* Example:
*
* ```javascript
* BackAndroid.addEventListener('hardwareBackPress', function() {
* BackHandler.addEventListener('hardwareBackPress', function() {
* // this.onMainScreen and this.goBack are just examples, you need to use your own implementation here
* // Typically you would use the navigator here to go to the last state.
*
Expand All @@ -59,7 +68,7 @@ RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
* });
* ```
*/
var BackAndroid = {
var BackHandler = {

exitApp: function() {
DeviceEventManager.invokeDefaultBackPressHandler();
Expand All @@ -71,7 +80,7 @@ var BackAndroid = {
): {remove: () => void} {
_backPressSubscriptions.add(handler);
return {
remove: () => BackAndroid.removeEventListener(eventName, handler),
remove: () => BackHandler.removeEventListener(eventName, handler),
};
},

Expand All @@ -84,4 +93,4 @@ var BackAndroid = {

};

module.exports = BackAndroid;
module.exports = BackHandler;
116 changes: 116 additions & 0 deletions Libraries/Utilities/BackHandler.ios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* 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.
*
* On Apple TV, this implements back navigation using the TV remote's menu button.
* On iOS, this just implements a stub.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no-trailing-spaces: Trailing spaces not allowed.

*
* @providesModule BackHandler
*/

'use strict';

const Platform = require('Platform');
const TVEventHandler = require('TVEventHandler');

type BackPressEventName = $Enum<{
backPress: string,
}>;

function emptyFunction() {}

/**
* Detect hardware button presses for back navigation.
*
* Android: 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.
*
* tvOS: Detect presses of the menu button on the TV remote. (Still to be implemented:
* programmatically disable menu button handling
* functionality to exit the app if there are no listeners or if none of the listeners return true.)
*
* iOS: Not applicable.
*
* The event subscriptions are called in reverse order (i.e. last registered subscription first),
* and if one subscription returns true then subscriptions registered earlier will not be called.
*
* Example:
*
* ```javascript
* BackHandler.addEventListener('hardwareBackPress', function() {
* // this.onMainScreen and this.goBack are just examples, you need to use your own implementation here
* // Typically you would use the navigator here to go to the last state.
*
* if (!this.onMainScreen()) {
* this.goBack();
* return true;
* }
* return false;
* });
* ```
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: new line after comment

let BackHandler;

if (Platform.isTVOS) {
const _tvEventHandler = new TVEventHandler();
var _backPressSubscriptions = new Set();

_tvEventHandler.enable(this, function(cmp, evt) {
if (evt && evt.eventType === 'menu') {
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) {
BackHandler.exitApp();
}
}
});

BackHandler = {
exitApp: emptyFunction,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary new line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes the code more readable.

addEventListener: function (
eventName: BackPressEventName,
handler: Function
): {remove: () => void} {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type should be extracted out to the top,

type BackHandlerSubscription = {
  remove: () => void
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm leaving this as is because it's copied from the existing code in the previous BackAndroid.android.js

_backPressSubscriptions.add(handler);
return {
remove: () => BackHandler.removeEventListener(eventName, handler),
};
},

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary new line

removeEventListener: function(
eventName: BackPressEventName,
handler: Function
): void {
_backPressSubscriptions.delete(handler);
},

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary new line

};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary new lines

} else {

BackHandler = {
exitApp: emptyFunction,
addEventListener() {
return {
remove: emptyFunction,
};
},
removeEventListener: emptyFunction,
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary new lines

}

module.exports = BackHandler;
4 changes: 3 additions & 1 deletion Libraries/react-native/react-native-implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ const ReactNative = {
get AppRegistry() { return require('AppRegistry'); },
get AppState() { return require('AppState'); },
get AsyncStorage() { return require('AsyncStorage'); },
get BackAndroid() { return require('BackAndroid'); },
get BackAndroid() { return require('BackAndroid'); }, // deprecated: use BackHandler instead
get BackHandler() { return require('BackHandler'); },
get CameraRoll() { return require('CameraRoll'); },
get Clipboard() { return require('Clipboard'); },
get DatePickerAndroid() { return require('DatePickerAndroid'); },
Expand All @@ -106,6 +107,7 @@ const ReactNative = {
get StyleSheet() { return require('StyleSheet'); },
get Systrace() { return require('Systrace'); },
get TimePickerAndroid() { return require('TimePickerAndroid'); },
get TVEventHandler() { return require('TVEventHandler'); },
get UIManager() { return require('UIManager'); },
get Vibration() { return require('Vibration'); },
get VibrationIOS() { return require('VibrationIOS'); },
Expand Down
4 changes: 3 additions & 1 deletion website/server/docsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ const apis = [
'../Libraries/ReactNative/AppRegistry.js',
'../Libraries/AppState/AppState.js',
'../Libraries/Storage/AsyncStorage.js',
'../Libraries/Utilities/BackAndroid.android.js',
'../Libraries/Utilities/BackAndroid.js',
'../Libraries/Utilities/BackHandler.ios.js',
'../Libraries/Utilities/BackHandler.android.js',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this cause there to be 3 separate pages? Lets consolidate it so that all the BackHandler docs are on one page.

Copy link
Contributor Author

@douglowder douglowder Mar 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were only two pages when I tested this, one for BackHandler, and one for BackAndroid to let users know that it is deprecated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, fair enough

'../Libraries/CameraRoll/CameraRoll.js',
'../Libraries/Components/Clipboard/Clipboard.js',
'../Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js',
Expand Down