mirror of
https://github.com/Gathin23/cleanyourtv.git
synced 2026-10-27 19:54:45 +00:00
docs: an HDMI row opens any app that claims the channel MIME type (#805)
openInput() sends an implicit ACTION_VIEW on the passthrough channel URI and only tries the theme's input_action when nothing claims it. On an RCA Android TV 9 (RTK2851P) the firmware has no Live TV app for that URI and ES File Explorer declares a VIEW filter for the same MIME type, so HDMI 1 opened the file manager. Records the mechanism, the query-activities check, why live_tv_package (setPackage on the Live TV row only) cannot filter it, and the source_panel_service workaround. Pins the note in themes/README's input_action row.
This commit is contained in:
1 parent
59332f4442
commit
483aaed6f8
3 files changed
+135
-1
No files matched your search
@@ -118,6 +118,26 @@ Things that bit us or contributors, so they don't bite you. Commands use `tools/
|
||||
tools/tv.py 'pm enable --user 0 com.google.android.apps.mediashell'
|
||||
```
|
||||
Keep the package out of your list if you use Stremio on the TV, or cast from a phone.
|
||||
- **Picking HDMI 1 in the Inputs menu opened an unrelated app**, seen on an RCA Android TV 9
|
||||
(Toptech/Zeasn firmware `RTK2851P`, Realtek RTD2851P,
|
||||
[#805](https://github.com/Gathin23/cleanyourtv/issues/805)). The launcher switches to a passthrough
|
||||
input with an *implicit* `ACTION_VIEW` on the input's channel URI
|
||||
(`vnd.android.cursor.item/channel`), and only sends the theme's `input_action` when nothing claims
|
||||
that intent at all. "Nothing claims it" is the catch: that firmware has no Live TV app for the URI,
|
||||
and ES File Explorer (`com.estrongs.android.pop/.app.transferstation.FileTransferStationActivity`)
|
||||
declares a `VIEW` filter for the same MIME type, so HDMI 1 opened the file manager and
|
||||
`input_action` was never reached. A set with no handler at least shows "Not available on this TV";
|
||||
a set with one wrong handler opens that app. Ask which app would take a row before blaming the
|
||||
launcher:
|
||||
```sh
|
||||
tools/tv.py 'cmd package query-activities --brief -a android.intent.action.VIEW -t vnd.android.cursor.item/channel'
|
||||
```
|
||||
`live_tv_package` does not help: it is applied as `setPackage` on the Live TV row only, and the
|
||||
HDMI and AV rows carry no package. Until the launcher checks that the handler is a TV-input app,
|
||||
hide the rows instead: a theme with `source_panel_service` set and `live_tv_package` empty makes
|
||||
the Inputs pill open the TV's own source panel (what the reporter did), or disable the app that
|
||||
answers. Report another one rather than reading it as a firmware quirk: the wrong-handler case needs
|
||||
a source change, not a setting.
|
||||
- **`adb exec-out screencap -p` gives a broken PNG** on some MediaTek sets (Xiaomi, and Amazon's
|
||||
own Fire TV smart TVs): the binary prints `Init wrapper sys mutex successful` on stdout first.
|
||||
Save on the TV and pull the file instead: `screencap -p /data/local/tmp/s.png`, or cut
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
"""The Inputs-menu hijack note (#805), and the theme key it explains.
|
||||
|
||||
Documentation only, so the tests pin what a reader has to be able to act on: the intent the launcher
|
||||
sends for an HDMI row, the command that names the app which would take it, why `live_tv_package`
|
||||
cannot help, and the one workaround that needs no rebuild. If the launcher ever restricts the row to
|
||||
a TV-input package, the bullet has to lose its "until" clause - that is a doc change, not a test change.
|
||||
|
||||
Run from the repository root: python3 -m unittest discover -s tests -v
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
TROUBLE = ROOT / "docs" / "TROUBLESHOOTING.md"
|
||||
THEMES = ROOT / "themes" / "README.md"
|
||||
ISSUE = "https://github.com/Gathin23/cleanyourtv/issues/805"
|
||||
START = "- **Picking HDMI 1 in the Inputs menu opened an unrelated app**"
|
||||
CHANNEL = "vnd.android.cursor.item/channel"
|
||||
|
||||
LINK = re.compile(r"\]\(([^)\s]+)\)")
|
||||
|
||||
|
||||
def bullet(text, start):
|
||||
"""The markdown bullet that begins with `start`, up to the next top-level bullet."""
|
||||
lines = text.split("\n")
|
||||
first = next(i for i, line in enumerate(lines) if line.startswith(start))
|
||||
out = [lines[first]]
|
||||
for line in lines[first + 1:]:
|
||||
if line.startswith("- **") or line.startswith("## "):
|
||||
break
|
||||
out.append(line)
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def broken_links(path):
|
||||
broken = []
|
||||
for target in LINK.findall(path.read_text(encoding="utf-8")):
|
||||
if target.startswith(("http://", "https://", "mailto:", "#")):
|
||||
continue
|
||||
local = target.split("#", 1)[0]
|
||||
if local and not (path.parent / local).exists():
|
||||
broken.append(target)
|
||||
return broken
|
||||
|
||||
|
||||
class InputIntentNoteTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.trouble_text = TROUBLE.read_text(encoding="utf-8")
|
||||
cls.theme_text = THEMES.read_text(encoding="utf-8")
|
||||
cls.note = bullet(cls.trouble_text, START)
|
||||
|
||||
def test_bullet_exists_once(self):
|
||||
self.assertEqual(self.trouble_text.count(START), 1)
|
||||
|
||||
def test_bullet_links_the_issue(self):
|
||||
self.assertIn(f"[#805]({ISSUE})", self.note)
|
||||
|
||||
def test_bullet_says_the_intent_is_implicit(self):
|
||||
self.assertIn("implicit", self.note)
|
||||
self.assertIn(CHANNEL, self.note)
|
||||
self.assertIn("ACTION_VIEW", self.note)
|
||||
|
||||
def test_bullet_gives_the_query_command_verbatim(self):
|
||||
# The flags are what make `query-activities` answer for the same intent the row sends; a
|
||||
# reordered or abbreviated command is what a reader would then report as "no handler".
|
||||
self.assertIn(
|
||||
"tools/tv.py 'cmd package query-activities --brief -a android.intent.action.VIEW "
|
||||
f"-t {CHANNEL}'",
|
||||
self.note,
|
||||
)
|
||||
|
||||
def test_bullet_names_the_app_that_took_the_row(self):
|
||||
self.assertIn(
|
||||
"com.estrongs.android.pop/.app.transferstation.FileTransferStationActivity", self.note
|
||||
)
|
||||
|
||||
def test_bullet_explains_why_live_tv_package_does_not_help(self):
|
||||
self.assertIn("`live_tv_package`", self.note)
|
||||
self.assertIn("`setPackage`", self.note)
|
||||
self.assertIn("Live TV row", self.note)
|
||||
|
||||
def test_bullet_contrasts_the_two_failures(self):
|
||||
self.assertIn('"Not available on this TV"', self.note)
|
||||
|
||||
def test_bullet_gives_the_workaround_with_both_keys(self):
|
||||
self.assertIn("`source_panel_service`", self.note)
|
||||
self.assertIn("`live_tv_package` empty", self.note)
|
||||
self.assertIn("source panel", self.note)
|
||||
|
||||
def test_bullet_does_not_promise_a_launcher_fix(self):
|
||||
self.assertIn("needs\n a source change, not a setting", self.note.replace("\r", ""))
|
||||
|
||||
def test_theme_row_says_when_input_action_is_reached(self):
|
||||
rows = [line for line in self.theme_text.split("\n")
|
||||
if line.startswith("| `input_action` |")]
|
||||
self.assertEqual(len(rows), 1, "the input_action row moved or was duplicated")
|
||||
row = rows[0]
|
||||
self.assertIn("nothing handles the standard `VIEW`", row)
|
||||
self.assertIn("query-activities", row)
|
||||
self.assertIn(f"[#805]({ISSUE})", row)
|
||||
|
||||
def test_theme_readme_still_lists_the_workaround_keys(self):
|
||||
self.assertIn("| `source_panel_service`, `source_panel_action` |", self.theme_text)
|
||||
self.assertIn("| `live_tv_package`, `live_tv_action` |", self.theme_text)
|
||||
|
||||
def test_no_broken_relative_links(self):
|
||||
self.assertEqual(broken_links(TROUBLE), [])
|
||||
self.assertEqual(broken_links(THEMES), [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+1
-1
@@ -41,7 +41,7 @@ is ignored, and a file that doesn't parse is ignored as a whole, so a theme can
|
||||
| `launch_actions` | list of `"package=action"` | Tiles that open a screen of the app instead of its start screen; an action that no longer resolves opens the app normally (MagentaTV's guide: `com.telekom.onetv.tv.pl=com.telekom.onetv.tv.pl.action.PROGRAM_GUIDE`) |
|
||||
| `app_labels` | list of `"package=Name"` | A tile's name instead of the app's own (MagentaTV as `com.telekom.onetv.tv.pl=TV`) |
|
||||
| `app_banners` | list of `"package=banner_name"` | A tile's artwork from a `banner_*` drawable bundled with the launcher (`banner_tv`: magenta with the Live TV glyph) |
|
||||
| `input_action` | string | Action sent with an HDMI/AV row's channel URI when nothing handles the standard `VIEW` (XGIMI: `com.xgimi.action.hdmiPlayer`) |
|
||||
| `input_action` | string | Action sent with an HDMI/AV row's channel URI when nothing handles the standard `VIEW` (XGIMI: `com.xgimi.action.hdmiPlayer`). Only a handler-less set gets here; any app that claims the channel MIME type takes the row instead, so check with `query-activities` ([#805](https://github.com/Gathin23/cleanyourtv/issues/805)) |
|
||||
| `input_uri_scheme` | string | Scheme an HDMI/AV row's passthrough URI is sent with instead of `content://`, with no MIME type (YaOS: `live-tv`, which its source player answers) |
|
||||
| `input_sources` | list, `config.xml` only | Vendor source numbers for the Inputs menu, `HW<n>=<number>` by the input id's last part; a mapped input opens by sending `input_action` with the number as the int extra `input`, and `HW<n>=-` leaves a port the set doesn't have out of the menu. Xiaomi/Redmi China firmware: [redmi-mitv-mftp0](../examples/redmi-mitv-mftp0/). Not read from a theme |
|
||||
| `columns` | 1 to 8 | Tiles per row; tiles shrink to fit from 5 up |
|
||||
|
||||
Reference in new issue
Block a user