From f06e8312fc56922e0969928f30817bccefc148b7 Mon Sep 17 00:00:00 2001 From: MoonCast Date: Thu, 22 Oct 2026 03:19:03 +0000 Subject: [PATCH 1/3] fix: quit prompts pick Cancel (handheld + TV), Recent only on a real start, battery-cap Auto bitrate (test244) Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 +++ .../handheld/HandheldHomeActivity.kt | 37 ++++++++++++------- .../java/com/limelight/home/BatteryCap.kt | 6 +++ .../java/com/limelight/home/HomeActivity.kt | 11 +++--- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d30e9fa83..843db81d46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0-test244 (2026-10-22) +- **Quit prompts pick Cancel.** "Quit X and start Y?", "Quit game?", Unpair and Remove now have Cancel selected, on the handheld and the TV, so pressing A (or OK on a remote) by habit doesn't do them. On 2026-10-21 an A on the pre-selected "Quit and start" quit Ryujinx. Wake it stays selected, since it's harmless. + - Handheld: while a dialog is open the hints say "B Cancel, A OK" instead of the page's "A Start", and a tapped A hint presses the dialog's selected button, not the game behind it. + - Handheld: a PC game moves to the front of Recent only once it really starts, not when the prompt opens, so Cancel no longer reshuffles the tiles. +- **On battery with bitrate Auto:** the bitrate was still the one for the uncapped size (80 Mbps for 4K on a 720p stream). It's now worked out for the capped size (about 15 Mbps for 720p60). + ## 1.0-test243 (2026-10-22) - Touch screen (Quick menu, PC), found by Saleh on test242: - The PC's pointer stayed in the picture with touch Off. With Off, MoonCast now moves it to the middle of the right edge, where it's off the screen, when the stream starts and when you switch to Off. (Not a corner: Windows' bottom-right corner is Show desktop.) diff --git a/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt b/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt index 4282d270b5..922fe82261 100644 --- a/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt +++ b/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt @@ -670,7 +670,7 @@ class HandheldHomeActivity : Activity() { foot.addView(sw.grow()) // button hints mean nothing without buttons: touch only (no controller) shows none if (!hasController()) { part(foot); return } - val h = when (page) { + val h = if (overlayKind != null) listOf("B" to "Cancel", "A" to "OK") else when (page) { Page.HOME -> listOf("Y" to (if (TvFinder.target(this) != null) "Play here" else "Play on TV"), "A" to "Start") Page.GAMES -> listOf("L R" to "Tabs", "X" to (if (sortAz) "Recent first" else "A to Z"), "B" to "Back", "A" to "Start") Page.CONSOLES -> listOf("B" to "Back", "A" to "Open") @@ -1545,11 +1545,10 @@ class HandheldHomeActivity : Activity() { when { g.pc != null && g.app != null -> { if (g.pc.state == ComputerDetails.State.OFFLINE) { // only when a poll says so (UNKNOWN = not asked yet) - confirm("${g.pc.name} is offline", "Wake it, then start ${g.app.appName} once it's online.", "Wake it") { wake(g.pc) } + confirm("${g.pc.name} is offline", "Wake it, then start ${g.app.appName} once it's online.", "Wake it", yesPicked = true) { wake(g.pc) } return } - Recents.touch(this, g.key) - start(g.pc, g.app) + start(g.pc, g.app) { Recents.touch(this, g.key) } } g.ps != null -> { Recents.touch(this, g.key); playPs(g.ps) } g.xb != null -> { Recents.touch(this, g.key); playXbox(g.xb) } @@ -1634,7 +1633,7 @@ class HandheldHomeActivity : Activity() { val t = when { g.pc != null && g.app != null -> { if (!online(g.pc)) { - confirm("${g.pc.name} is offline", "Wake it, then send ${g.app.appName} to ${tv.name} once it's online.", "Wake it") { wake(g.pc) } + confirm("${g.pc.name} is offline", "Wake it, then send ${g.app.appName} to ${tv.name} once it's online.", "Wake it", yesPicked = true) { wake(g.pc) } return } MoveToTv.Target("pc", g.app.appName, g.pc.uuid, g.pc.name, g.app.appId) @@ -1659,16 +1658,19 @@ class HandheldHomeActivity : Activity() { Opt("⚙", Sw.PC, "Controller settings") { settingsGroup = "pads"; go(Page.SETTINGS) }), listOf("Close" to {})) } - private fun start(pc: ComputerDetails, app: NvApp) { + /** Starts [app], asking first when another game runs there. [started] runs once it really starts (not on Cancel). */ + private fun start(pc: ComputerDetails, app: NvApp, started: () -> Unit = {}) { val b = binder ?: return toast(getString(R.string.error_manager_not_running)) val other = runningApp(pc) if (other != null && other.appId != app.appId) { confirm("Quit ${other.appName}?", "${pc.name} is running ${other.appName}. Quit it and start ${app.appName}?", "Quit and start") { + started() FeelSounds.play(this, FeelSounds.Cue.LAUNCH) ServerHelper.doQuit(this, pc, other, b) { runOnUiThread { ServerHelper.doStart(this, app, pc, b) } } } return } + started() FeelSounds.play(this, FeelSounds.Cue.LAUNCH) ServerHelper.doStart(this, app, pc, b) } @@ -1950,13 +1952,15 @@ class HandheldHomeActivity : Activity() { } /** A dialog's buttons along its bottom: rounded buttons side by side; the last is where focus starts. */ - private fun buttons(card: LinearLayout, list: List Unit>>, primary: Boolean = true, keepOpenLast: Boolean = false) { + /** A row of buttons; with [primary], the one at [primaryAt] (default the last) is the one A and the first focus pick. */ + private fun buttons(card: LinearLayout, list: List Unit>>, primary: Boolean = true, keepOpenLast: Boolean = false, + primaryAt: Int = list.size - 1) { val row = sw.row() list.forEachIndexed { i, (label, fn) -> val keep = keepOpenLast && i == list.size - 1 row.addView(sw.text(label, 30, sw.ring, 800).apply { gravity = Gravity.CENTER - tag = if (primary && i == list.size - 1) "primary" else "btn:$i" + tag = if (primary && i == primaryAt) "primary" else "btn:$i" setTag(R.id.hh_pill, true) background = sw.round(sw.bg, 48) sw.focusable(this) @@ -1972,7 +1976,7 @@ class HandheldHomeActivity : Activity() { card.addView(row, sw.lp(-1, 96).apply { leftMargin = sw.px(40); rightMargin = sw.px(40); topMargin = sw.px(28); bottomMargin = sw.px(40) }) } - private fun dialog(title: String, body: String?, opts: List, btns: List Unit>>) { + private fun dialog(title: String, body: String?, opts: List, btns: List Unit>>, primaryAt: Int = btns.size - 1) { val card = card() card.addView(sw.text(title, 40, sw.ink, 800, 2), sw.lp(-1, -2).apply { leftMargin = sw.px(56); rightMargin = sw.px(56); topMargin = sw.px(48); bottomMargin = sw.px(10) }) if (body != null) card.addView(sw.text(body, 26, sw.sub, 600, 8), sw.lp(-1, -2).apply { leftMargin = sw.px(56); rightMargin = sw.px(56); bottomMargin = sw.px(26) }) @@ -1984,12 +1988,16 @@ class HandheldHomeActivity : Activity() { val fit = ((sw.designHeight - 620) / 132f).toInt().coerceIn(3, 8) if (opts.size > fit) card.addView(ColScroll(this, sw.px(30)).apply { isVerticalScrollBarEnabled = false; addView(list) }, sw.lp(-1, fit * 132 - 66)) else card.addView(list, sw.lp(-1, -2)) - buttons(card, btns, primary = firstOn < 0) + buttons(card, btns, primary = firstOn < 0, primaryAt = primaryAt) showOverlay("dialog", card) } - private fun confirm(title: String, body: String, yes: String, onYes: () -> Unit) = - dialog(title, body, emptyList(), listOf("Cancel" to {}, yes to onYes)) + /** + * A yes/Cancel question. Cancel is picked (A presses it) unless [yesPicked]: a habitual A must not quit a game, + * unpair or remove anything (it quit Ryujinx on 2026-10-21). Only a harmless yes, like Wake it, is picked. + */ + private fun confirm(title: String, body: String, yes: String, yesPicked: Boolean = false, onYes: () -> Unit) = + dialog(title, body, emptyList(), listOf("Cancel" to {}, yes to onYes), primaryAt = if (yesPicked) 1 else 0) /** A one-line entry; [onSave] returns an error to show, or null when the value is good. */ private fun entry(title: String, body: String, hint: String, v: String, numbers: Boolean, onSave: (String) -> String?) = @@ -2047,6 +2055,7 @@ class HandheldHomeActivity : Activity() { overlay.isFocusable = false; card.isFocusable = false main.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS (overlay.findViewWithTag("primary") ?: firstFocusable(overlay))?.requestFocus() + buildFoot() // the hints say what A and B do in the dialog, not on the page under it } private fun hideOverlay(cue: Boolean = true) { @@ -2085,7 +2094,9 @@ class HandheldHomeActivity : Activity() { "Y" -> KeyEvent.KEYCODE_BUTTON_Y; "L R" -> KeyEvent.KEYCODE_BUTTON_R1; else -> return } // A starts what's selected; after a tap nothing has focus, so use what the page starts on - if (code == KeyEvent.KEYCODE_BUTTON_A && (currentFocus == null || currentFocus?.isInTouchMode == true)) { primaryView?.performClick(); return } + if (code == KeyEvent.KEYCODE_BUTTON_A && (currentFocus == null || currentFocus?.isInTouchMode == true)) { + (if (overlayKind != null) overlay.findViewWithTag("primary") else primaryView)?.performClick(); return + } dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, code)); dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, code)) } diff --git a/app/src/main/java/com/limelight/home/BatteryCap.kt b/app/src/main/java/com/limelight/home/BatteryCap.kt index 64885615d5..13861973a9 100644 --- a/app/src/main/java/com/limelight/home/BatteryCap.kt +++ b/app/src/main/java/com/limelight/home/BatteryCap.kt @@ -31,6 +31,12 @@ object BatteryCap { Log.i("MoonCast", "on battery: stream ${config.width}x${config.height} capped to ${w}x$cap") config.width = w config.height = cap + // Bitrate Auto (0) was worked out for the size before the cap (80 Mbps for 4K): work it out for the capped size + val kbps = android.preference.PreferenceManager.getDefaultSharedPreferences(context).getInt("seekbar_bitrate_kbps", 0) + if (kbps == 0) { + config.bitrate = PreferenceConfiguration.getDefaultBitrate("${w}x$cap", config.fps.toString()) + Log.i("MoonCast", "on battery: Auto bitrate ${config.bitrate / 1000} Mbps") + } return true } } diff --git a/app/src/tv/java/com/limelight/home/HomeActivity.kt b/app/src/tv/java/com/limelight/home/HomeActivity.kt index 433b2419c8..4d7c1a533b 100644 --- a/app/src/tv/java/com/limelight/home/HomeActivity.kt +++ b/app/src/tv/java/com/limelight/home/HomeActivity.kt @@ -1342,7 +1342,7 @@ class HomeActivity : Activity(), PhoneLink.Listener { val other = runningApp(pc) if (other != null && other.appId != app.appId) { confirm("Quit ${other.appName}?", "${pc.name} is running ${other.appName}. Quit it and start ${app.appName}?", - "Quit and start") { + "Quit and start", danger = true) { FeelSounds.play(this, FeelSounds.Cue.LAUNCH) ServerHelper.doQuit(this, pc, other, b) { runOnUiThread { ServerHelper.doStart(this, app, pc, b) } } } @@ -1354,7 +1354,7 @@ class HomeActivity : Activity(), PhoneLink.Listener { private fun quit(pc: ComputerDetails, app: NvApp) { val b = binder ?: return - confirm("Quit ${app.appName}?", "The game closes on ${pc.name}. Anything you haven't saved is lost.", "Quit game") { + confirm("Quit ${app.appName}?", "The game closes on ${pc.name}. Anything you haven't saved is lost.", "Quit game", danger = true) { ServerHelper.doQuit(this, pc, app, b) { runOnUiThread { b.invalidateStateForComputer(pc.uuid) } } } } @@ -1879,15 +1879,16 @@ class HomeActivity : Activity(), PhoneLink.Listener { val card = dialogCard() card.addView(tv.text(title, 40, tv.p.moon, tv.display(700), 2)) card.addView(tv.text(body, 22, tv.p.dust, tv.ui(500), 4), tv.lp(-1, -2).apply { topMargin = tv.px(12); bottomMargin = tv.px(28) }) + // danger (quit, unpair, remove): Cancel is picked, so a habitual OK on the remote doesn't do it card.addView(tv.row().apply { - addView(tv.pill(yes, "A", !danger) { + addView(tv.pill(yes, if (danger) null else "A", !danger) { // one sound per action: what the answer starts (a launch) speaks for it, else the dialog's close val n = FeelSounds.serial hideOverlay(cue = false); onYes() if (n == FeelSounds.serial) FeelSounds.play(this@HomeActivity, FeelSounds.Cue.CLOSE) }.apply { - tag = "primary"; if (danger) (getChildAt(childCount - 1) as TextView).setTextColor(Tv.DANGER) }) - addView(tv.pill("Cancel", "B", false) { hideOverlay() }) + tag = if (danger) "yes" else "primary"; if (danger) (getChildAt(childCount - 1) as TextView).setTextColor(Tv.DANGER) }) + addView(tv.pill("Cancel", "B", false) { hideOverlay() }.apply { if (danger) tag = "primary" }) }) showOverlay("confirm", FrameLayout(this).apply { addView(card, tv.flp(900, -2, Gravity.CENTER)) }) } From 34df4c9e08e4e4dc6e12c1903276a8727d5180b0 Mon Sep 17 00:00:00 2001 From: MoonCast Date: Thu, 22 Oct 2026 03:22:15 +0000 Subject: [PATCH 2/3] docs(changelog): test244 Auto bitrate for 720p60 is 10 Mbps Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 843db81d46..4ddc1f8566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - **Quit prompts pick Cancel.** "Quit X and start Y?", "Quit game?", Unpair and Remove now have Cancel selected, on the handheld and the TV, so pressing A (or OK on a remote) by habit doesn't do them. On 2026-10-21 an A on the pre-selected "Quit and start" quit Ryujinx. Wake it stays selected, since it's harmless. - Handheld: while a dialog is open the hints say "B Cancel, A OK" instead of the page's "A Start", and a tapped A hint presses the dialog's selected button, not the game behind it. - Handheld: a PC game moves to the front of Recent only once it really starts, not when the prompt opens, so Cancel no longer reshuffles the tiles. -- **On battery with bitrate Auto:** the bitrate was still the one for the uncapped size (80 Mbps for 4K on a 720p stream). It's now worked out for the capped size (about 15 Mbps for 720p60). +- **On battery with bitrate Auto:** the bitrate was still the one for the uncapped size (80 Mbps for 4K on a 720p stream). It's now worked out for the capped size (10 Mbps for 720p60, Moonlight's usual Auto). ## 1.0-test243 (2026-10-22) - Touch screen (Quick menu, PC), found by Saleh on test242: From 6504f3fb276a7a375d29e47de17eed69b3e6194c Mon Sep 17 00:00:00 2001 From: MoonCast Date: Thu, 22 Oct 2026 03:53:58 +0000 Subject: [PATCH 3/3] remove: On battery, stream at (#65), little saving for the complexity (test245) Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 ++ .../handheld/HandheldHomeActivity.kt | 2 - app/src/main/java/com/limelight/Game.java | 9 +--- .../java/com/limelight/Ps5StreamActivity.kt | 9 ---- .../java/com/limelight/home/BatteryCap.kt | 42 ------------------- 5 files changed, 4 insertions(+), 61 deletions(-) delete mode 100644 app/src/main/java/com/limelight/home/BatteryCap.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ddc1f8566..fa4de1c719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 1.0-test245 (2026-10-22) +- **"On battery, stream at" is removed** (Settings, Handheld, and `home/BatteryCap.kt`, added for #65 in test237). It saved little: the screen uses most of the battery and doesn't change, and Native resolution already avoids streaming more pixels than the screen shows. With it goes test244's Auto-bitrate fix. A saved setting is simply ignored. + ## 1.0-test244 (2026-10-22) - **Quit prompts pick Cancel.** "Quit X and start Y?", "Quit game?", Unpair and Remove now have Cancel selected, on the handheld and the TV, so pressing A (or OK on a remote) by habit doesn't do them. On 2026-10-21 an A on the pre-selected "Quit and start" quit Ryujinx. Wake it stays selected, since it's harmless. - Handheld: while a dialog is open the hints say "B Cancel, A OK" instead of the page's "A Start", and a tapped A hint presses the dialog's selected button, not the game behind it. diff --git a/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt b/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt index 922fe82261..fbdfc95138 100644 --- a/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt +++ b/app/src/handheld/java/com/limelight/handheld/HandheldHomeActivity.kt @@ -1205,8 +1205,6 @@ class HandheldHomeActivity : Activity() { // PC games: what a finger on the picture does when a game starts (the Quick menu changes it for that game) choice(list, stream, com.limelight.Game.TOUCH_DEFAULT_PREF, "Touch screen", "In PC games. Mouse is a trackpad, Touch clicks where you tap. The Quick menu changes it while you play", listOf("Off" to "off", "Mouse" to "mouse", "Touch" to "touch"), "off") - choice(list, prefs, com.limelight.home.BatteryCap.PREF, "On battery, stream at", "Unplugged, PC and PS5 streams go no higher than this. Plugged in, the Picture settings apply", - listOf("Same" to "same", "1080p" to "1080", "720p" to "720", "540p" to "540"), "same") appToggle(list, "hh_dim_on_tv", "Dim the screen on a TV", "While this ${deviceShort()} is the controller for a TV", true) toggle(list, "checkbox_ultra_low_latency", "Ultra low latency", "Experimental. This device: ${chipName()}", false) } diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 3a8c1e7f44..5ce5bc2e5b 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -223,10 +223,6 @@ protected void onCreate(Bundle savedInstanceState) { // Read the stream preferences prefConfig = PreferenceConfiguration.readPreferences(this); - // #65: on battery, Settings, Handheld, "On battery, stream at" caps the size. The fold checks compare the - // screen with the size before the cap, so a capped stream isn't taken for a wrong-size one. - uncappedSize = prefConfig.width + "x" + prefConfig.height; - com.limelight.home.BatteryCap.apply(this, prefConfig); trace(foldLabel(getResources().getConfiguration()) + ": stream " + prefConfig.width + "x" + prefConfig.height + ", Native " + PreferenceConfiguration.nativeWholeScreen(this)); tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0); @@ -3030,12 +3026,9 @@ private void reconnectHere(String why) { /** With Native on, the size this screen streams at now differs from this stream's. */ private boolean sizeChanged() { return prefConfig != null && PreferenceConfiguration.nativeWholeScreen(this) - && !PreferenceConfiguration.nativeResolution(this).equals(uncappedSize != null ? uncappedSize : prefConfig.width + "x" + prefConfig.height); + && !PreferenceConfiguration.nativeResolution(this).equals(prefConfig.width + "x" + prefConfig.height); } - /** The stream's size before the battery cap (#65). */ - private String uncappedSize; - @Override public void mouseMove(int deltaX, int deltaY) { conn.sendMouseMove((short) deltaX, (short) deltaY); diff --git a/app/src/main/java/com/limelight/Ps5StreamActivity.kt b/app/src/main/java/com/limelight/Ps5StreamActivity.kt index f65771129a..a3de616ed7 100644 --- a/app/src/main/java/com/limelight/Ps5StreamActivity.kt +++ b/app/src/main/java/com/limelight/Ps5StreamActivity.kt @@ -151,15 +151,6 @@ class Ps5StreamActivity : Activity(), SurfaceHolder.Callback, com.limelight.home away && awayQuality == "1080" -> VideoResolutionPreset.RES_1080P weak || (!away && prefs.getString("ps5_resolution", "1080") == "720") -> VideoResolutionPreset.RES_720P else -> VideoResolutionPreset.RES_1080P - }.let { chosen -> - // #65: on battery, Settings, Handheld, "On battery, stream at" caps it - val cap = com.limelight.home.BatteryCap.height(this) - val h = when (chosen) { VideoResolutionPreset.RES_540P -> 540; VideoResolutionPreset.RES_720P -> 720; else -> 1080 } - when { - cap in 1 until h && cap <= 540 -> VideoResolutionPreset.RES_540P - cap in 1 until h -> VideoResolutionPreset.RES_720P - else -> chosen - }.also { if (it != chosen) Log.i(TAG, "on battery: $chosen capped to $it") } } val h264 = !ps5 || (if (away) prefs.getString("away_codec", "h265") else prefs.getString("ps5_codec", "h265")) == "h264" // Frame rate: the PS5 streams at 30 or 60 fps only; any other rate broke the picture (#39). A Custom value diff --git a/app/src/main/java/com/limelight/home/BatteryCap.kt b/app/src/main/java/com/limelight/home/BatteryCap.kt deleted file mode 100644 index 13861973a9..0000000000 --- a/app/src/main/java/com/limelight/home/BatteryCap.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.limelight.home - -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.os.BatteryManager -import android.util.Log -import com.limelight.preferences.PreferenceConfiguration - -/** - * Settings, Handheld, "On battery, stream at" (#65): while the device isn't plugged in, streams are capped at that - * height. Plugged in, the Picture settings apply. Only the handheld app sets it; elsewhere it stays "same". - */ -object BatteryCap { - const val PREF = "hh_battery_res" - - /** The height to cap a stream at now, or 0: no cap (the setting is Same, or the device is plugged in). */ - @JvmStatic - fun height(context: Context): Int { - val cap = context.getSharedPreferences("mc_tv", Context.MODE_PRIVATE).getString(PREF, "same")?.toIntOrNull() ?: return 0 - val status = try { context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) } catch (e: RuntimeException) { null } ?: return 0 - return if (status.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) == 0) cap else 0 - } - - /** Caps a PC stream's size, keeping its shape (width a multiple of 8). True if it was capped. */ - @JvmStatic - fun apply(context: Context, config: PreferenceConfiguration): Boolean { - val cap = height(context) - if (cap <= 0 || config.height <= cap) return false - val w = (Math.round(config.width.toDouble() * cap / config.height / 8.0) * 8).toInt() - Log.i("MoonCast", "on battery: stream ${config.width}x${config.height} capped to ${w}x$cap") - config.width = w - config.height = cap - // Bitrate Auto (0) was worked out for the size before the cap (80 Mbps for 4K): work it out for the capped size - val kbps = android.preference.PreferenceManager.getDefaultSharedPreferences(context).getInt("seekbar_bitrate_kbps", 0) - if (kbps == 0) { - config.bitrate = PreferenceConfiguration.getDefaultBitrate("${w}x$cap", config.fps.toString()) - Log.i("MoonCast", "on battery: Auto bitrate ${config.bitrate / 1000} Mbps") - } - return true - } -}