feat(android): obwodka fokusu pilota, tablet bez blokady pionu na starcie

RN 0.76 nie przekazuje onFocus/onBlur do JS na Androidzie, a Android TV nie
rysuje systemowego podswietlenia, wiec na Fire TV nie bylo widac, gdzie jest
pilot (zgloszenie 7768ae0c). Globalny nasluch zmiany fokusu w MainActivity
daje widokowi z fokusem foreground z jasna obwodka; w trybie dotykowym nic.
Tablet (sw >= 600 dp) nie dostaje juz pionu w onCreate. Wymaga nowego APK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
goon-foss 2026-10-15 12:26:55 +02:00
parent ca9ccf29f1
commit bc674c2ec4

View file

@ -5,9 +5,14 @@ import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.view.View
import java.lang.ref.WeakReference
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
@ -37,7 +42,9 @@ import expo.modules.ReactActivityDelegateWrapper
*/
open class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
if (!isTelevision()) {
// Tablet (krotszy bok >= 600 dp) zostaje bez blokady: pion na tablecie trzymanym w poziomie
// to waski pasek, a zdjecie blokady z JS (src/lib/tablet.ts) i tak przychodzi chwile pozniej.
if (!isTelevision() && resources.configuration.smallestScreenWidthDp < 600) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
// Set the theme to AppTheme BEFORE onCreate to support
@ -55,6 +62,40 @@ open class MainActivity : ReactActivity() {
} catch (e: Throwable) {
Log.w("Goon", "Cast niedostepny na tym urzadzeniu: " + e.javaClass.simpleName)
}
installFocusRing()
}
// Obwodka wokol elementu z fokusem pilota (Fire TV, Android TV, klawiatura).
//
// Pilot chodzi po zwyklych przyciskach RN, ale nic nie pokazywalo, gdzie jest fokus
// (zgloszenie 7768ae0c, Fire TV): widoki RN maja wlasne tlo bez stanu "focused", Android TV
// nie rysuje systemowego podswietlenia, a RN 0.76 na Androidzie nie przekazuje onFocus/onBlur
// do JS (sprawdzone 2026-10-15 na emulatorze: przycisk ma fokus, zdarzenie nie przychodzi).
// Dlatego natywnie: przy kazdej zmianie fokusu nowy widok dostaje foreground z obwodka,
// a poprzedni odzyskuje swoj. W trybie dotykowym (telefon) nic nie rysujemy.
private var ringView: WeakReference<View>? = null
private var ringPrevForeground: Drawable? = null
private fun installFocusRing() {
window.decorView.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
ringView?.get()?.let { it.foreground = ringPrevForeground }
ringView = null
ringPrevForeground = null
if (newFocus == null || newFocus.isInTouchMode) return@addOnGlobalFocusChangeListener
ringPrevForeground = newFocus.foreground
newFocus.foreground = makeFocusRing()
ringView = WeakReference(newFocus)
}
}
private fun makeFocusRing(): Drawable {
val dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, resources.displayMetrics)
return GradientDrawable().apply {
shape = GradientDrawable.RECTANGLE
cornerRadius = 12 * dp
setStroke((3 * dp).toInt(), 0xFFF5EDE0.toInt())
}
}
private fun isTelevision(): Boolean {