Skip to content

feat(client/android): add Android TV support - #2864

Open
vad612 wants to merge 6 commits into
OutlineFoundation:masterfrom
vad612:feat/android-tv
Open

vad612 wants to merge 6 commits into
OutlineFoundation:masterfrom
vad612:feat/android-tv

Conversation

@vad612

@vad612 vad612 commented Sep 26, 2026 •

Copy link
Copy Markdown

Closes #735

Why

The Android client can already run on Android TV, but its portrait-only manifest and pointer-oriented web UI make it impractical to use with a TV remote. Users cannot reliably move focus, activate controls, navigate dialogs and menus, or use the server list without a mouse.

What changes

  • Keep a single Android APK and the existing org.outline.android.client application ID for phones, tablets, and TVs.
  • Advertise an optional Leanback launcher and optional touchscreen support, and package a correctly sized TV banner.
  • Detect Android TV at runtime through the Cordova plugin and lazily enable TV-only navigation behavior.
  • Add D-pad spatial navigation across nested Shadow DOM, dialogs, menus, the navigation drawer, server cards, and text-entry boundaries.
  • Add visible keyboard/remote focus states and keyboard activation semantics to interactive controls.
  • Let Android use the device's natural orientation, so TV devices render in landscape.
  • Document the shared Android/TV build behavior.

The navigation module is loaded only on detected Android TV devices, so the regular phone/tablet interaction path remains unchanged.

Testing

Automated:

  • npm run action client/web/build
  • npm run action client/web/test — 75 tests passed
  • ESLint on all changed JavaScript and TypeScript files
  • GTS lint on all changed TypeScript files
  • npm run lint:lit — 0 errors (three pre-existing CSS container-query warnings)
  • License-header check on all changed source files
  • Android debug APK build

Manual:

  • Android Studio Television (1080p) emulator
  • Xiaomi Mi TV (MiTV_MOOQ1) over ADB
  • Verified D-pad traversal and activation for the server list, connect/disconnect control, navigation drawer, settings lists, add-access-key dialog, and server overflow/delete menu
  • Verified closing the navigation drawer with Right and closing/reselecting drawer destinations
  • Verified installation under the existing package ID, TV launcher banner, access-key import, and a successful VPN connection

Long access keys can be entered with the Android TV remote keyboard or another external keyboard; the D-pad can then move from the text field to the dialog actions.

@vad612
vad612 requested a review from a team as a code owner September 26, 2026 10:49
@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Adds Android TV support with D-pad navigation.

The PR appears safe to merge based on the reviewed changes.

Summary

The PR adds Android TV launcher resources and runtime detection to both Android hosts, then enables D-pad navigation in the shared client UI.

  • The changes since the previous review extend TV setup to Capacitor, adjust off-screen focus and dialog navigation, and guard errored connection controls.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Android app starts] --> B{Cordova or Capacitor}
  B --> C[Native Android TV detection]
  C --> D[Set TV flag and dispatch ready event]
  D --> E{TV device?}
  E -- Yes --> F[Load shared D-pad navigation]
  E -- No --> G[Keep standard interaction]
Loading

Reviews (2) · Last reviewed commit: "fix(client/android): address Android TV ..."

Comment thread client/web/ui_components/tv-navigation.js
Comment thread client/web/views/root_view/add_access_key_dialog/index.ts Outdated
Comment thread client/web/ui_components/app-root.js Outdated
@fortuna

fortuna commented Sep 26, 2026

Copy link
Copy Markdown
Collaborator

A big question for tv is how to enter the access key. How do you propose we do that? Topping the whole thing is not practical.

@vad612

vad612 commented Sep 26, 2026

Copy link
Copy Markdown
Author

Thanks for raising this. I don’t expect users to type the full access key with the D-pad. The intended MVP flow is Android TV’s standard remote text input: focus the field, open the keyboard in a phone’s TV remote app, and paste the complete Outline key there. I verified this end to end on a Xiaomi TV using an iOS remote keyboard — I copied the key on the iPhone and pasted it directly into the TV field. The existing ss:// intent is also available when the link can be opened on the TV.

I intentionally left a QR-code or phone-pairing flow out of this PR to keep its scope focused on making the existing client usable with a remote. If you consider a first-party quick-transfer flow necessary for Android TV support, I can implement it, either in this PR or as a follow-up.

@fortuna
fortuna requested a review from ohnorobo September 28, 2026 09:45
@fortuna

fortuna commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

Thanks. I think a QR code flow would be helpful, but I agree it should be a separate change.

@vad612 can you please share screenshots of how it looks like so we know the layout is not broken?

@ohnorobo please review.

Comment thread client/capacitor/plugins/capacitor-plugin-outline/src/web.ts
Comment thread client/web/views/servers_view/server_connection_indicator/index.ts
Comment thread client/package.json Outdated
@vad612

vad612 commented Sep 28, 2026

Copy link
Copy Markdown
Author
image image image image

@ohnorobo

ohnorobo commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

@vad612 thanks so much for this contribution and all the testing on Android TV!

Currently in CI the client-web test is failing, which is causing some of the other CI not to run. I think the fix should be small. Could you fix that and see that the web tests are all passing, then I'll re-run the full CI?

Alternatively, if you make a vad612:master<-vad612:feat/android-tv PR within your repo fork you should be able to check the full set if CI runs without having to wait for me to approve them.

Comment thread client/capacitor/src/index.ts Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This file is a red flag to me. Why are we rolling our our own navigation? I'm sure other TV apps don't need to do that. What's the proper way to do this? We should not reinvent the wheel.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I investigated native and web spatial-navigation libraries. They can select the next element, but do not replace the integration needed for this WebView UI’s Shadow DOM, Material components, dialogs, and focus restoration. Our earlier Norigin attempt still required most of that integration code, so I kept the tested module rather than adding a dependency without substantially reducing it

Comment thread client/web/ui_components/app-root.js Outdated
Comment thread client/web/ui_components/app-root.js Outdated
Comment thread client/web/ui_components/app-root.js Outdated
Comment thread client/web/ui_components/app-root.js
Comment thread client/web/ui_components/app-root.js Outdated
Comment thread client/web/ui_components/app-root.js Outdated
Comment thread client/web/ui_components/app-root.js Outdated
Comment thread client/web/ui_components/app-root.js Outdated
if (this.tvNavigationLoad !== navigationLoad || !this.isConnected) {
return;
}
this.removeTvNavigation = installTvNavigation(this.shadowRoot);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does installTvNavigation do?

Can't we always install it? Please explain the tradeoff.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It installs D-pad, activation, Back, and focus handlers and returns a cleanup function. Enabling those handlers on phones or desktop would interfere with normal keyboard navigation, so installation is limited to Android TV

@vad612

vad612 commented Oct 7, 2026

Copy link
Copy Markdown
Author

Thank you for the thoughtful review and for recognizing the Android TV testing. I’ve been actively using Outline on my own Xiaomi TV for about two weeks, and I’d be happy to keep refining both the implementation and the remote-control experience until they meet the project’s quality bar.
I also took your CI guidance on board. Before updating this PR, I now validate changes in a PR within my fork; the latest revision passed the full CI there. I appreciate your help and feedback as we work toward a solid result.

@vad612
vad612 requested a review from fortuna October 8, 2026 14:35

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for Android TV

3 participants