fix(android): the stream stops fighting large displays and owns the cutout explicitly
The three Play Console pre-release findings for 0.22.3, resolved: - Orientation restriction: the in-stream SENSOR_LANDSCAPE lock is now applied on compact devices (sw < 600 dp) only. On tablets/foldables/desktop windows it is a large-display anti-pattern (Android 16+ ignores it there outright) and unnecessary — the aspect-ratio letterbox renders correctly in any orientation; the lock was always a phone-ergonomics choice. No manifest restriction existed, and resizeability stays unrestricted. - Edge-to-edge determinism: the stream window now sets LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS explicitly (and restores it on the way out) — SDK-35 enforcement makes that the immersive default, pre-15 devices letterboxed the notch as a dead bar; being explicit gives both the same, correct behaviour. The stream's own letterbox is black, so the cutout region can never show anything wrong. - Deprecated edge-to-edge APIs: audited — no in-app use of setStatusBarColor/setNavigationBarColor/systemUiVisibility/translucent flags or theme attrs; enableEdgeToEdge (androidx.activity 1.13.0) is already in place with explicit SystemBarStyle. What the scanner sees are androidx's own API-level-guarded compat branches, which Google documents as ignorable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -235,13 +235,39 @@ fun StreamScreen(session: ActiveSession, onDisconnect: () -> Unit) {
|
||||
val priorSoftInput = window?.attributes?.softInputMode
|
||||
?: WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
|
||||
// Draw under the display cutout, explicitly. Android 15's SDK-35 edge-to-edge enforcement
|
||||
// makes ALWAYS the immersive default, but pre-15 devices letterbox the notch as a dead
|
||||
// black bar unless asked — and the stream's own letterbox is black anyway, so the cutout
|
||||
// region can never show anything wrong. Captured + restored like the rest of the window
|
||||
// state so the menus keep their platform-default behaviour.
|
||||
val priorCutout = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window?.attributes?.layoutInDisplayCutoutMode
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window?.let { w ->
|
||||
w.attributes = w.attributes.apply {
|
||||
layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|
||||
}
|
||||
}
|
||||
}
|
||||
// Lock to landscape while streaming — the host streams a landscape desktop, so pin the device
|
||||
// there (either landscape direction is fine) and stop it rotating to portrait mid-session. The
|
||||
// activity declares configChanges=orientation, so this re-lays out the surface in place without
|
||||
// recreating the activity (no stream restart). On TV (fixed landscape) it's a harmless no-op.
|
||||
// The prior request is captured and restored on the way out.
|
||||
//
|
||||
// COMPACT devices only (sw < 600 dp): on tablets/foldables/desktop windows the lock is a
|
||||
// large-display anti-pattern (Play flags it; Android 16+ ignores it there outright), and the
|
||||
// stream doesn't need it — the aspect-ratio letterbox renders correctly in any orientation,
|
||||
// the lock is purely a phone-ergonomics choice.
|
||||
val compactDevice = context.resources.configuration.smallestScreenWidthDp < 600
|
||||
val priorOrientation = activity?.requestedOrientation
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
if (compactDevice) {
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
}
|
||||
activity?.streamHandle = handle // route hardware keys to this session
|
||||
// Multi-controller router: a stable wire pad index per connected controller, per-device axis
|
||||
// state, Arrival/Remove on hot-plug, and feedback routed back by pad index. Forwards every
|
||||
@@ -463,6 +489,11 @@ fun StreamScreen(session: ActiveSession, onDisconnect: () -> Unit) {
|
||||
}
|
||||
controller?.hide(WindowInsetsCompat.Type.ime()) // drop any keyboard left showing
|
||||
window?.setSoftInputMode(priorSoftInput)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && priorCutout != null) {
|
||||
window?.let { w ->
|
||||
w.attributes = w.attributes.apply { layoutInDisplayCutoutMode = priorCutout }
|
||||
}
|
||||
}
|
||||
controller?.show(WindowInsetsCompat.Type.systemBars())
|
||||
window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
if (lowLatencyMode && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
Reference in New Issue
Block a user