-
Notifications
You must be signed in to change notification settings - Fork 1
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
[WIP] Add support for Android TV devices #1
base: master
Are you sure you want to change the base?
Conversation
@kmagiera I've added checks to prevent |
@@ -65,7 +67,7 @@ public ReactActivityDelegate( | |||
} | |||
|
|||
protected ReactRootView createRootView() { | |||
return new ReactRootView(getContext()); | |||
return new ReactAndroidTVViewManager(getContext()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should find some other way instead of making changes here. I'd suggest that we:
- Add necessary overrides to ReactRootView (seems like just adding
dispatchKeyEvent
should be enough) - Proxy call to this method to a new class called
ReactAndroidTVRootViewHelper
where all the TV related logic from TVViewMagaer will be put
pt 2 will help with not bloating the rootview class with a lot of code that is specific to some small fraction of devices
@@ -34,6 +34,7 @@ | |||
<intent-filter> | |||
<action android:name="android.intent.action.MAIN" /> | |||
<category android:name="android.intent.category.LAUNCHER" /> | |||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment here what is this needed for (android TV)
@@ -56,4 +62,9 @@ private static String getServerIpAddress(int port) { | |||
|
|||
return String.format(Locale.US, "%s:%d", ipAddress, port); | |||
} | |||
|
|||
public static boolean isRunningOnTV(ReactContext reactContext) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code does not belong here. This class provides methods that are used by the code loader (most typically in debug mode). You can just put this code directly in AndroidInfoModule
as it is not being used anywhere outside of that module (as opposed to other methods from this class).
Also I'd change the naming strategy here. With "running" it looks weird as we don't use "isRunningOnAndroid", just "platform == 'android'". Perhaps we could find something similar to "interfaceIdiom" exported on iOS. It looks like maybe "uiMode" would be a good choice as it could be TV, NORMAL, CAR etc (https://developer.android.com/reference/android/content/res/Configuration.html#uiMode) much like interfaceIdiom on iOS
Nice progress there! Can you also add a section to this PR description outlining the feature set that your PR makes available on TV (e.g. navigating with arrows, play button, scrollview paging, auto focus) |
|
||
public static boolean isRunningOnTV(ReactContext reactContext) { | ||
UiModeManager uiModeManager = (UiModeManager) reactContext.getSystemService(UI_MODE_SERVICE); | ||
return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment with a link to this:
https://developer.android.com/training/tv/start/hardware.html#runtime-check
@@ -11,10 +11,35 @@ | |||
*/ | |||
'use strict'; | |||
|
|||
function TVEventHandler() {} | |||
const React = require('React'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we consolidate TVEventHandler.android.js and TVEventHandler.ios.js? From what I understand the only difference is that the native module we pass to NativeEventEmitter for iOS does not exists on android (in which case its undefined which seems to be ok with this code)
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); | ||
DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter = reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class); | ||
mAndroidTVRootViewHelper.handleKeyEvent(ev, eventEmitter); | ||
return super.dispatchKeyEvent(ev); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we return true here? similarly to what we do with touches we can pretty safely assume the key press event is going to be consumed by the react app. Calling into super will just default to returning false.
This is only relevant to apps that embed react native root views, but if we both handle the key and return false the "master" app may also pass the same key event to some other view which is undesirable
@@ -158,7 +158,9 @@ var TouchableNativeFeedback = createReactClass({ | |||
touchableHandleActivePressIn: function(e: Event) { | |||
this.props.onPressIn && this.props.onPressIn(e); | |||
this._dispatchPressedStateChange(true); | |||
this._dispatchHotspotUpdate(this.pressInLocation.locationX, this.pressInLocation.locationY); | |||
if (!Platform.isTV) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check instead if this.pressInLocation
is defined
Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName())); | ||
FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); | ||
Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); | ||
((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); | ||
if (canHandleIntent(serviceIntent)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we perhaps want to put the log and a toast from the lines above into this if block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said, this is just a temporary workaround and the app will still crash when trying to display redbox alert. Do you think we can come up with a more bullet-proof solution for this?
|
||
private static final String IS_TESTING = "IS_TESTING"; | ||
|
||
private ReactContext mReactContext; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When extending ContextBaseJavaModule
I think you don't need to keep reference to the context yourselves – you should be able to call getReactApplicationContext()
to get reference to the context
|
||
private ReactRootView mReactRootView; | ||
|
||
public ReactAndroidTVRootViewHelper(ReactRootView mReactRootView) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename argument to reactRootView
, then you don't have to use this.sth = sth
below
emitter.emit("onTVNavEvent", event); | ||
} | ||
|
||
private View getFocusedView(ViewGroup viewGroup) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to findFocusedView
("get" is reserved for operations that are rather simple whereas this performs a search)
@@ -331,7 +331,7 @@ var TouchableMixin = { | |||
} else if (evt.eventType === 'blur') { | |||
cmp.touchableHandleActivePressOut && cmp.touchableHandleActivePressOut(evt); | |||
} else if (evt.eventType === 'select') { | |||
cmp.touchableHandlePress && cmp.touchableHandlePress(evt); | |||
cmp.touchableHandlePress && !cmp.props.disabled && cmp.touchableHandlePress(evt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kmagiera Note: I'm not exactly sure this is the correct way to handle that, as it relies on cmp.props
directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call to this touchableHandleStartShouldSetResponder()
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or nevermind, this looks ok to me, TouchableMixin is already accesing that prop in this method: touchableHandleStartShouldSetResponder
KeyEvent.KEYCODE_DPAD_RIGHT | ||
); | ||
|
||
private View mLastFocusedView = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that we only need view ID for sending blur event later on. In that case I'd prefer not to keep a reference to a view but just the ID
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, are you sure there is no other way for the view to lose focus? If not maybe there is a way for the rootview to notify this handler class when it looses focus so we can send the blur event earlier
super.requestChildFocus(child, focused); | ||
} | ||
|
||
private DeviceEventManagerModule.RCTDeviceEventEmitter getDeviceEventEmitter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kmagiera Do you think this is a good idea to separate this (and maybe also the part with null checking catalyst instance) to a separate method, since it is repeated multiple times in these proxy methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we will save much by doing this. Not worth changing at this moment
mLastFocusedViewId = View.NO_ID; | ||
} | ||
|
||
private void handlePlayPauseEvent(RCTDeviceEventEmitter emitter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking about inlining handlePlayPauseEvent
and handleSelectEvent
directly into handleKeyEvent
switch statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); | ||
return; | ||
} | ||
mAndroidTVRootViewHelper.clearFocus(getDeviceEventEmitter()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I'm not sure about this but I assume that since it is the RootView
that looses its focus that means another (native?) part of the app is now focused and we should send blur event to react-native views.
int eventKeyAction = ev.getAction(); | ||
View targetView = findFocusedView(mReactRootView); | ||
if (targetView != null) { | ||
if (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE == eventKeyCode && eventKeyAction == KeyEvent.ACTION_UP) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kmagiera Now that I think about it, maybe we should dispatch the "playPause" event event without having a focused view? It does not include the view id after all.
At first I thought that it would make no sense to send playPause events without having any view focused, but maybe I'm wrong.
@kmagiera I've added an experimental support for opening dev menu by long pressing the playPause button on remote controller. |
@krzysztofciombor I think its ok. Events should be processed in rootview as it should be possible to have multiple rootviews each providing events to a correct react views subtree (e.g. usecase when native app has few react native screens embedded). As for long play press we shouldn't delay it being sent to RN because of the fact we may want to show the dev menu. I don't think it matters if we dispatch it to JS in case you want to open the menu, as usually after that step you will reload the app |
docs/BuildingForAppleTV.md
Outdated
@@ -23,6 +23,12 @@ The RNTester app supports Apple TV; use the `RNTester-tvOS` build target to buil | |||
|
|||
```js | |||
var Platform = require('Platform'); | |||
var running_on_apple_tv = Platform.isTV; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should perhaps be changed to sth like:
var running_on_tv = Platform.isTV
// If you want to be more specific and only detect devices running tvOS (but no Android TV devices) you can use:
var running_on_apple_tv = Platform.isTVOS
docs/BuildingForAndroidTV.md
Outdated
|
||
## Code changes | ||
|
||
- *Access to touchable controls*: When running on Android TV the Android framework will automatically apply a directional navigation scheme based on relative position of focusable elements in your views. The `Touchable` mixin has code added to detect focus changes and use existing methods to style the components properly and initiate the proper actions when the view is selected using the TV remote, so `TouchableHighlight`, `TouchableOpacity` and `TouchableNativeFeedback` will "just work". In particular: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there is a point in duplicating this information. Maybe we can add a section "Building for TV devices" and move most of this stuff there. We can split the section re installation by platform in a way its done here: http://facebook.github.io/react-native/docs/running-on-device.html
@@ -0,0 +1,112 @@ | |||
package com.facebook.react.views.androidtv; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add copyright headers
This looks good! I added a few minor comments inline. I think its quite ready to be submitted as a PR upstream. Can you also restructure the description of this PR in a following way:
|
099b841
to
dcb6ef7
Compare
Summary: <!-- Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html Happy contributing! --> * To be on par with Apple TV support, this makes it possible to run React Native apps on Android TV devices (See also: https://react-native.canny.io/feature-requests/p/android-tv-support) * These changes also make it possible to navigate through the app using D-PAD buttons that are present on some mobile devices * Since these changes affect, among others, `ReactRootView.java` and `Touchable.js` code and are closely related to Apple TV implementation, it makes sense for them to be included in the core - React native apps can be launched on Android TV devices and properly render their content - Navigation is possible using left, right, top, bottom arrows from the remote (or D-PAD) - Touchable components can handle D-PAD center button press events and correctly fire their `onPress` handlers - Touchable components will receive `onPressIn` and `onPressOut` events and can react to focus/blur changes appropriately (just like on Apple TV) - `Platform` constants allow to check if the react-native app is running on TV (`Platform.isTV`) - `ScrollView`s behave correctly (same as native implementation) when switching to view outside bounds – that is, the container would scroll such that the newly focused element is fully visible - Native "clicking" sounds are played when moving between focusable elements - Play/Pause click event is send to `TVEventHandler` - Rewind and FastForward events are send to `TVEventHandler` - Back button behaves as a normal Android back button - Diagonal buttons work correctly on Android TV, e.g. if there is no button directly to the right from the focused one, but there is one to the right but a bit higher/lower it will grab focus - Dev menu can be accessed by long pressing fast forward button A demo showing RNTester app running on Android TV device (Amazon Fire TV Stick) can be found here: [![RNAndroidTVDemo](http://img.youtube.com/vi/EzIQErHhY20/0.jpg)](http://www.youtube.com/watch?v=EzIQErHhY20) - `TextInput` will not work on Android TV devices. There's an issue with native `ReactEditText` implementation that prevents it from receiving focus. This makes it impossible to navigate to `TextInput`. This will be fixed next, but will be included in a separate Pull Request - ~Overlay permissions cannot be granted on Android TV devices running Android version >= 6.0 This is because the overlay permission can only be granted by firing an Intent to open settings page (`ACTION_MANAGE_OVERLAY_PERMISSION`). Since this page does not exist on TV devices the permission cannot be requested. This will make the app crash when trying to open dev menu (⌘+M) or displaying a redbox error. Note: This does not affect devices running Android version < 6.0 (for example Amazon Fire TV Stick)~ This is now fixed by: #16596 * Launch the RNTester app on Android TV device. * Ensure it launches without a crash * Ensure basic navigation is possible * Ensure Touchable components can receive select events * Ensure the changes do not break current Android and iOS mobile devices functionality. * Ensure the changes do not break current Apple TV functionality. [RNAndroidTVDemo video](http://img.youtube.com/vi/EzIQErHhY20/0.jpg) * Added `ReactAndroidTVViewManager` that handles TV `KeyEvent`s and dispatches events to JS - This is the core that enables basic navigation functionality on Android TV devices * Following the above change we copy `TVEventHandler.ios.js` into `TVEventHandler.android.js` to enable JS to pick up those native navigation events and dispatch them further to subscribed views. (Note: We do not have a native `TVNavigationEventEmitter` implementation on Android, thus this file is slightly modified, e.g. it does pass `null` to `NativeEventEmitter` constructor) * Added `uiMode` to `AndroidInfoModule`. (**Note**: This required changing `extends BaseJavaModule` to `extends ReactContextBaseJavaModule` to be able to use `getSystemService` which requires `Context` instance! * Added `isTV` constants to both `Platform.ios.js` (keeping the deprecated `isTVOS` as well) and `Platform.android.js` * Changed condition check on `Touchable.js` to use the newly added `isTV` flag to properly handle TV navigation events on Android as well * Added `LEANBACK_LAUNCHER` to `RNTester` `intent-filter` so that it is possible to launch it on Android TV devices. * See also a PR to `react-native-website` repo with updated docs for Android TV: facebook/react-native-website#59 - [ ] Fix `TextInput` components handling by allowing them to be focused and making a proper navigation between them (and/or other components) possible. One thing to note here that the default behavior to immediately open software keyboard when focused on `TextInput` field will need to be adjusted on Android TV as well) - [x] Fix overlay permissions issue by changing the way redbox/dev menu are displayed (see: #16596) - [ ] Adjust placement of TV-related files (e.g. the `TVEventHandler.js` file is placed inside `AppleTV` directory which is not accurate, since it does handle Android TV events as well) Previous discussion: software-mansion-labs#1 <!-- Help reviewers and the release process by writing your own release notes **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.** CATEGORY [----------] TYPE [ CLI ] [-------------] LOCATION [ DOCS ] [ BREAKING ] [-------------] [ GENERAl ] [ BUGFIX ] [-{Component}-] [ INTERNAL ] [ ENHANCEMENT ] [ {File} ] [ IOS ] [ FEATURE ] [ {Directory} ] |-----------| [ ANDROID ] [ MINOR ] [ {Framework} ] - | {Message} | [----------] [-------------] [-------------] |-----------| [CATEGORY] [TYPE] [LOCATION] - MESSAGE EXAMPLES: [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see --> [ANDROID] [FEATURE] [TV] - Added support for Android TV devices Closes #16500 Differential Revision: D6536847 Pulled By: hramos fbshipit-source-id: 17bbb11e8583b97f195ced5fd9762f8902fb8a3d
Summary: <!-- Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html Happy contributing! --> * To be on par with Apple TV support, this makes it possible to run React Native apps on Android TV devices (See also: https://react-native.canny.io/feature-requests/p/android-tv-support) * These changes also make it possible to navigate through the app using D-PAD buttons that are present on some mobile devices * Since these changes affect, among others, `ReactRootView.java` and `Touchable.js` code and are closely related to Apple TV implementation, it makes sense for them to be included in the core - React native apps can be launched on Android TV devices and properly render their content - Navigation is possible using left, right, top, bottom arrows from the remote (or D-PAD) - Touchable components can handle D-PAD center button press events and correctly fire their `onPress` handlers - Touchable components will receive `onPressIn` and `onPressOut` events and can react to focus/blur changes appropriately (just like on Apple TV) - `Platform` constants allow to check if the react-native app is running on TV (`Platform.isTV`) - `ScrollView`s behave correctly (same as native implementation) when switching to view outside bounds – that is, the container would scroll such that the newly focused element is fully visible - Native "clicking" sounds are played when moving between focusable elements - Play/Pause click event is send to `TVEventHandler` - Rewind and FastForward events are send to `TVEventHandler` - Back button behaves as a normal Android back button - Diagonal buttons work correctly on Android TV, e.g. if there is no button directly to the right from the focused one, but there is one to the right but a bit higher/lower it will grab focus - Dev menu can be accessed by long pressing fast forward button A demo showing RNTester app running on Android TV device (Amazon Fire TV Stick) can be found here: [![RNAndroidTVDemo](http://img.youtube.com/vi/EzIQErHhY20/0.jpg)](http://www.youtube.com/watch?v=EzIQErHhY20) - `TextInput` will not work on Android TV devices. There's an issue with native `ReactEditText` implementation that prevents it from receiving focus. This makes it impossible to navigate to `TextInput`. This will be fixed next, but will be included in a separate Pull Request - ~Overlay permissions cannot be granted on Android TV devices running Android version >= 6.0 This is because the overlay permission can only be granted by firing an Intent to open settings page (`ACTION_MANAGE_OVERLAY_PERMISSION`). Since this page does not exist on TV devices the permission cannot be requested. This will make the app crash when trying to open dev menu (⌘+M) or displaying a redbox error. Note: This does not affect devices running Android version < 6.0 (for example Amazon Fire TV Stick)~ This is now fixed by: facebook/react-native#16596 * Launch the RNTester app on Android TV device. * Ensure it launches without a crash * Ensure basic navigation is possible * Ensure Touchable components can receive select events * Ensure the changes do not break current Android and iOS mobile devices functionality. * Ensure the changes do not break current Apple TV functionality. [RNAndroidTVDemo video](http://img.youtube.com/vi/EzIQErHhY20/0.jpg) * Added `ReactAndroidTVViewManager` that handles TV `KeyEvent`s and dispatches events to JS - This is the core that enables basic navigation functionality on Android TV devices * Following the above change we copy `TVEventHandler.ios.js` into `TVEventHandler.android.js` to enable JS to pick up those native navigation events and dispatch them further to subscribed views. (Note: We do not have a native `TVNavigationEventEmitter` implementation on Android, thus this file is slightly modified, e.g. it does pass `null` to `NativeEventEmitter` constructor) * Added `uiMode` to `AndroidInfoModule`. (**Note**: This required changing `extends BaseJavaModule` to `extends ReactContextBaseJavaModule` to be able to use `getSystemService` which requires `Context` instance! * Added `isTV` constants to both `Platform.ios.js` (keeping the deprecated `isTVOS` as well) and `Platform.android.js` * Changed condition check on `Touchable.js` to use the newly added `isTV` flag to properly handle TV navigation events on Android as well * Added `LEANBACK_LAUNCHER` to `RNTester` `intent-filter` so that it is possible to launch it on Android TV devices. * See also a PR to `react-native-website` repo with updated docs for Android TV: facebook/react-native-website#59 - [ ] Fix `TextInput` components handling by allowing them to be focused and making a proper navigation between them (and/or other components) possible. One thing to note here that the default behavior to immediately open software keyboard when focused on `TextInput` field will need to be adjusted on Android TV as well) - [x] Fix overlay permissions issue by changing the way redbox/dev menu are displayed (see: facebook/react-native#16596) - [ ] Adjust placement of TV-related files (e.g. the `TVEventHandler.js` file is placed inside `AppleTV` directory which is not accurate, since it does handle Android TV events as well) Previous discussion: software-mansion-labs/react-native#1 <!-- Help reviewers and the release process by writing your own release notes **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.** CATEGORY [----------] TYPE [ CLI ] [-------------] LOCATION [ DOCS ] [ BREAKING ] [-------------] [ GENERAl ] [ BUGFIX ] [-{Component}-] [ INTERNAL ] [ ENHANCEMENT ] [ {File} ] [ IOS ] [ FEATURE ] [ {Directory} ] |-----------| [ ANDROID ] [ MINOR ] [ {Framework} ] - | {Message} | [----------] [-------------] [-------------] |-----------| [CATEGORY] [TYPE] [LOCATION] - MESSAGE EXAMPLES: [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see --> [ANDROID] [FEATURE] [TV] - Added support for Android TV devices Closes facebook/react-native#16500 Differential Revision: D6536847 Pulled By: hramos fbshipit-source-id: 17bbb11e8583b97f195ced5fd9762f8902fb8a3d
Add support for Android TV devices
Motivation
ReactRootView.java
andTouchable.js
code and are closely related to Apple TV implementation, it makes sense for them to be included in the coreSupported Android TV features
onPress
handlersonPressIn
andonPressOut
events and can react to focus/blur changes appropriately (just like on Apple TV)Platform
constants allow to check if the react-native app is running on TV (Platform.isTV
)ScrollView
s behave correctly (same as native implementation) when switching to view outside bounds – that is, the container would scroll such that the newly focused element is fully visibleTVEventHandler
TVEventHandler
A demo showing RNTester app running on Android TV device (Amazon Fire TV Stick) can be found here:
Caveats
TextInput
will not work on Android TV devices. There's an issue with nativeReactEditText
implementation that prevents it from receiving focus. This makes it impossible to navigate toTextInput
.This will be fixed next, but will be included in a separate Pull Request
This is because the overlay permission can only be granted by firing an Intent to open settings page (
ACTION_MANAGE_OVERLAY_PERMISSION
). Since this page does not exist on TV devices the permission cannot be requested. This will make the app crash when trying to open dev menu (⌘+M) or displaying a redbox error.Note: This does not affect devices running Android version < 6.0 (for example Amazon Fire TV Stick)
Test Plan
RNAndroidTVDemo video
Changes
ReactAndroidTVViewManager
that handles TVKeyEvent
s and dispatches events to JS - This is the core that enables basic navigation functionality on Android TV devicesTVEventHandler.ios.js
intoTVEventHandler.android.js
to enable JS to pick up those native navigation events and dispatch them further to subscribed views. (Note: We do not have a nativeTVNavigationEventEmitter
implementation on Android, thus this file is slightly modified, e.g. it does passnull
toNativeEventEmitter
constructor)uiMode
toAndroidInfoModule
. (Note: This required changingextends BaseJavaModule
toextends ReactContextBaseJavaModule
to be able to usegetSystemService
which requiresContext
instance!isTV
constants to bothPlatform.ios.js
(keeping the deprecatedisTVOS
as well) andPlatform.android.js
Touchable.js
to use the newly addedisTV
flag to properly handle TV navigation events on Android as wellLEANBACK_LAUNCHER
toRNTester
intent-filter
so that it is possible to launch it on Android TV devices.Future work
TextInput
components handling by allowing them to be focused and making a proper navigation between them (and/or other components) possible. One thing to note here that the default behavior to immediately open software keyboard when focused onTextInput
field will need to be adjusted on Android TV as well)TVEventHandler.js
file is placed insideAppleTV
directory which is not accurate, since it does handle Android TV events as well)Previous discussion: #1
Release Notes
[ANDROID] [FEATURE] [TV] - Added support for Android TV devices