-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Android TV compatibility (fixes #1363, #899) #2701
Conversation
AppBarLayout mostly gets it, but we still need to uphold our own part - expanding it back after focus returns to it
We don't hide MainFragment when search is show, so FocusFinder sometimes gives focus to (obscured) main content
GridLayoutManager is buggy - https://issuetracker.google.com/issues/37067220: it randomly loses or incorrectly assigns focus when being scrolled via direction-based navigation. This commit reimplements onFocusSearchFailed() on top of scrollBy() to work around that problem. Ordinary touch-based navigation should not be affected.
Focus isn't needed for marquee, only selection
The same logic is present in RecyclerView, ScrollView etc. Android really should default to this behavior for all Views with isScrollContainer = true
* Hide player controls when back is pressed (only on TV devices) * Do not hide control after click unless in touch mode * Show player controls on dpad usage * Notably increase control hide timeout when not in touch mode
Buttons are more likely to have "correct" styling and are focusable/clickable out of box
Upstream DrawerLayout does override addFocusables, but incorrectly checks for isDrawerOpen instread of isDrawerVisible
It is still buggy because of NavigationView (why the hell is NavigationMenuView marked as focusable?) but at least initial opening works as intended
could you try whether the bugs of RecyclerView and GridLayoutManager are still present with the latest beta version? Changelog: https://developer.android.com/jetpack/androidx/releases/recyclerview |
I re-checked with I believe, that it is described in this Google issue: https://issuetracker.google.com/issues/37067220. See attached video file for example of problematic behavior. This is how it works after applying my workaround. |
5e70744
to
c5b818c
Compare
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.
Code looks good to me, though I have never done anything with TVs and devices without touch. I only asked for some clarifications.
I couldn't test this since I do not have an Android TV.
public FlingBehavior(Context context, AttributeSet attrs) { | ||
super(context, attrs); | ||
} | ||
|
||
@Override | ||
@SuppressLint("NewApi") |
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.
Couldn't this cause crashes in Android versions where the new api is used?
https://stackoverflow.com/questions/16601601/understanding-suppresslintnewapi-annotation
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 specific @SuppressLint
looks like something, that was added a while ago, and have been rendered obsolete without me noticing. No idea, what is it supposed to suppress.
import org.schabi.newpipe.App; | ||
|
||
public class FireTvUtils { | ||
@SuppressLint("InlinedApi") |
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.
Are you sure this is ok? https://stackoverflow.com/questions/19291844/what-is-the-use-of-suppresslintinlinedapi
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 passes inlined constant "android.software.leanback" to PackageManager in order to check whether current device supports Leanback (e,g. it is TV). If it runs on Android version, that does not known what "android.software.leanback" is, hasSystemFeature
will simply return false
.
The Lint warning there is meaningless.
|
||
@Override | ||
public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) { | ||
this.listener = l == null ? null : new NestedListener(l); |
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.
Please add some parenthesis.
Android Studio has presets and system images for Android TV devices, you can use those to test. |
I made some emulator tests with an Android 9 image. No videos play and the player is squashed to phone format. I'll upload some screenshots later. I know that playing videos was no problem when I did some tests with a KitKat image last year. I'll investigate further when I have more spare time. |
This is very odd. I have tested my changes on real hardware with Android 4 and Android 7. Former does not even have "Leanback" feature, so I had to use custom patches (not included in this PR) to check for specific model in Are you sure, that you tested on TV virtual device? If so, could you try with Android 7? |
Closed since I don't have to for this anymore. I will try to revisit this in my spare time. |
Most development for Android TV is done with "Leanback" support library. There are two issues with it:
In absence of Leanback one has to directly face challenges of designing for TV devices: handling focus and TV-friendly design.
Focus-based (aka "directional") navigation is a must because TV devices are remote-driven. Many standard View/ViewGroup subclasses are poorly suited for directional navigation and must be heavily augmented to work with it. Some components have notional support for focus handling but contain annoying bugs due to code rot or lack of testing.
TV-friendly design means two things: clearly highlighting focused element and using big readable fonts everywhere (since most big TV screens have low resolution and questionable LCD panel quality). This pull request does not address font size issues, but does contain a workaround to visually distinguish currently focused element.
There are many known issues with this PR:
In order to apply fix from 3c4d62c everywhere, every RecyclerView in NewPipe and every adapter must be replaces with NewPipeRecyclerView and FixedGridAdapter/SuperScrollAdapter. I avoided doing so to reduce number of conflicts during rebasing, so please do it yourself if you merge this PR
Regarding focus-based navigation, — it needs extra explanation.
The general approach to handling focus in Android is to call isInTouchMode(), and make decisions depending on returned value. Ideally, there should be no need to distinguish between Android TV devices, Android Auto, Android phones with dpad and other kinds of devices — directional navigation should work that same way everywhere. In real world this is not so simple: for example, hiding side drawer on back press might not be useful on most Android devices with touchscreens (because it is easier to dismiss it with finger), but is absolutely mandatory on TV devices, controlled with IR remote. And we can't easily check if device has touchsreen — some devices lie that they have it, because apps refuse to work or install otherwise, but in reality they have some kind of less-that-perfect touchscreen emulator. So there are still some checks for isFireTV() (which now detects any TV devices) and some checks for isInTouchMode().
fixes #1363, #899