diff --git a/app/src/main/java/de/ggb/kwabatv/MainActivity.kt b/app/src/main/java/de/ggb/kwabatv/MainActivity.kt index 679afa9..3c35cd7 100644 --- a/app/src/main/java/de/ggb/kwabatv/MainActivity.kt +++ b/app/src/main/java/de/ggb/kwabatv/MainActivity.kt @@ -18,11 +18,27 @@ import android.webkit.WebViewClient * den einmaligen Autoplay-Ton-Klick eine vertrauenswuerdige Nutzereingabe, * die ein simuliertes KeyboardEvent nicht liefert. * - * KEYCODE_MENU wird bewusst NICHT abgefangen: das Oeffnen des TV-Menue- - * Popups wurde bereits gegen die echte Website in einem normalen Browser - * auf echter Fire-TV-Hardware bestaetigt, ohne dass diese App beteiligt - * war - unveraendertes Durchreichen ist die naechste Annaeherung an genau - * dieses schon erprobte Verhalten. + * KEYCODE_MENU wird NICHT als KEYCODE_MENU ins WebView weitergereicht, + * sondern als KEYCODE_X. Grund (per Diagnose-Log bestaetigt): Androids + * WebView.dispatchKeyEvent() liefert "System"-Keycodes (KEYCODE_MENU, + * HOME, BACK, CALL, VOLUME_*, ...) grundsaetzlich nicht an den Seiteninhalt + * aus - sendKey(KEYCODE_MENU) kam zwar in dispatchKeyEvent() an, aber + * webView.dispatchKeyEvent() meldete downConsumed=false/upConsumed=false + * und JS bekam weder keydown- noch contextmenu-Events. Ein gewoehnlicher + * Buchstaben-Keycode wie KEYCODE_P (fuer DPAD_UP) wird dagegen anstandslos + * durchgereicht (downConsumed=true). Die Website (room.js) behandelt 'x' + * deshalb als Alias fuer die 'ContextMenu'-Taste, ausschliesslich fuer + * diesen App-Anwendungsfall. + * + * DPAD Center/Up/Down (und die entsprechenden Medientasten) werden NUR + * innerhalb eines Raums remapped (Space/P/N - siehe Design-Spec). Auf der + * Raumliste (/tv) haben sie dort keine Bedeutung: die Raumliste hat ihr + * eigenes Tastaturschema (ArrowUp/ArrowDown/Enter, siehe tv-rooms.js auf + * der Website) und muss die echten, unveraenderten Tasten bekommen, sonst + * bewegt sich der Fokus zwischen den Raum-Kacheln nie (genau der Fehler, + * der beim ersten Hardware-Test auftrat: die Raumliste laed, aber keine + * Taste tut etwas, weil DPAD_DOWN/CENTER als 'n'/Space statt als + * ArrowDown/Enter ankamen). */ class MainActivity : Activity() { @@ -94,48 +110,37 @@ class MainActivity : Activity() { sendKey(keyCode, shift = true) } + /** Ob dispatchKeyEvent diese Taste ueberhaupt anfasst - fuer ACTION_DOWN + * und ACTION_UP gleich ausgewertet, damit nie nur die eine Haelfte eines + * Tastendrucks abgefangen wird (sonst haengt Chromiums interner + * Tastenstatus fest, weil ein Keydown ohne passendes Keyup ankaeme). */ + private fun shouldIntercept(keyCode: Int): Boolean = when (keyCode) { + KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, + KeyEvent.KEYCODE_MENU -> true + KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, + KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, + KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_MEDIA_NEXT -> !isRoomList() + else -> false + } + override fun dispatchKeyEvent(event: KeyEvent): Boolean { - if (event.action != KeyEvent.ACTION_DOWN) { - return when (event.keyCode) { - KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, - KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, - KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, - KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_MEDIA_NEXT, - KeyEvent.KEYCODE_BACK -> true // ACTION_UP derselben Tasten verschlucken, wir haben schon auf ACTION_DOWN reagiert - else -> super.dispatchKeyEvent(event) + if (!shouldIntercept(event.keyCode)) return super.dispatchKeyEvent(event) + if (event.action != KeyEvent.ACTION_DOWN) return true // ACTION_UP der abgefangenen Taste verschlucken, ACTION_DOWN hat schon reagiert + + when (event.keyCode) { + KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> sendKey(KeyEvent.KEYCODE_SPACE) + KeyEvent.KEYCODE_DPAD_LEFT -> handleSeek(KeyEvent.KEYCODE_DPAD_LEFT, event.repeatCount > 0) + KeyEvent.KEYCODE_DPAD_RIGHT -> handleSeek(KeyEvent.KEYCODE_DPAD_RIGHT, event.repeatCount > 0) + KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS -> sendKey(KeyEvent.KEYCODE_P) + KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT -> sendKey(KeyEvent.KEYCODE_N) + KeyEvent.KEYCODE_MENU -> sendKey(KeyEvent.KEYCODE_X) + KeyEvent.KEYCODE_BACK -> when { + isRoomList() -> { /* verschluckt, keine weitere Aktion */ } + isFullscreen() -> sendKey(KeyEvent.KEYCODE_ESCAPE) + else -> webView.loadUrl(BuildConfig.WEBSITE_URL) } } - return when (event.keyCode) { - KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { - sendKey(KeyEvent.KEYCODE_SPACE) - true - } - KeyEvent.KEYCODE_DPAD_LEFT -> { - handleSeek(KeyEvent.KEYCODE_DPAD_LEFT, event.repeatCount > 0) - true - } - KeyEvent.KEYCODE_DPAD_RIGHT -> { - handleSeek(KeyEvent.KEYCODE_DPAD_RIGHT, event.repeatCount > 0) - true - } - KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS -> { - sendKey(KeyEvent.KEYCODE_P) - true - } - KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT -> { - sendKey(KeyEvent.KEYCODE_N) - true - } - KeyEvent.KEYCODE_BACK -> { - when { - isRoomList() -> { /* verschluckt, keine weitere Aktion */ } - isFullscreen() -> sendKey(KeyEvent.KEYCODE_ESCAPE) - else -> webView.loadUrl(BuildConfig.WEBSITE_URL) - } - true - } - else -> super.dispatchKeyEvent(event) - } + return true } companion object { diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index d282ffb..683208f 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -1,6 +1,6 @@ - +