feat: power manager wake locks

This commit is contained in:
Miuzarte
2026-04-11 20:19:47 +08:00
parent 69e1976e5b
commit 2639da4b2c
5 changed files with 52 additions and 26 deletions

View File

@@ -34,6 +34,9 @@
}, },
{ {
"path": "../socialite" "path": "../socialite"
},
{
"path": "../termux-app"
} }
], ],
} }

View File

@@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<application <application

View File

@@ -8,6 +8,7 @@ import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import io.github.miuzarte.scrcpyforandroid.pages.MainScreen import io.github.miuzarte.scrcpyforandroid.pages.MainScreen
import io.github.miuzarte.scrcpyforandroid.services.AppRuntime import io.github.miuzarte.scrcpyforandroid.services.AppRuntime
import io.github.miuzarte.scrcpyforandroid.services.AppWakeLocks
import io.github.miuzarte.scrcpyforandroid.storage.PreferenceMigration import io.github.miuzarte.scrcpyforandroid.storage.PreferenceMigration
import io.github.miuzarte.scrcpyforandroid.storage.Storage import io.github.miuzarte.scrcpyforandroid.storage.Storage
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@@ -17,9 +18,9 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// initialize settings singleton
Storage.init(applicationContext) Storage.init(applicationContext)
AppRuntime.init(applicationContext) AppRuntime.init(applicationContext)
AppWakeLocks.init(applicationContext)
val migration = PreferenceMigration(applicationContext) val migration = PreferenceMigration(applicationContext)
runBlocking { runBlocking {

View File

@@ -1,9 +1,7 @@
package io.github.miuzarte.scrcpyforandroid.pages package io.github.miuzarte.scrcpyforandroid.pages
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.util.Log import android.util.Log
import android.view.WindowManager
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -38,6 +36,7 @@ import io.github.miuzarte.scrcpyforandroid.models.DeviceShortcuts
import io.github.miuzarte.scrcpyforandroid.nativecore.NativeAdbService import io.github.miuzarte.scrcpyforandroid.nativecore.NativeAdbService
import io.github.miuzarte.scrcpyforandroid.scaffolds.LazyColumn import io.github.miuzarte.scrcpyforandroid.scaffolds.LazyColumn
import io.github.miuzarte.scrcpyforandroid.scrcpy.Scrcpy import io.github.miuzarte.scrcpyforandroid.scrcpy.Scrcpy
import io.github.miuzarte.scrcpyforandroid.services.AppWakeLocks
import io.github.miuzarte.scrcpyforandroid.services.EventLogger import io.github.miuzarte.scrcpyforandroid.services.EventLogger
import io.github.miuzarte.scrcpyforandroid.services.EventLogger.logEvent import io.github.miuzarte.scrcpyforandroid.services.EventLogger.logEvent
import io.github.miuzarte.scrcpyforandroid.services.LocalSnackbarController import io.github.miuzarte.scrcpyforandroid.services.LocalSnackbarController
@@ -150,9 +149,9 @@ fun DeviceTabPage(
scrcpy: Scrcpy, scrcpy: Scrcpy,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val taskScope = remember { CoroutineScope(Dispatchers.IO + SupervisorJob()) } val taskScope = remember { CoroutineScope(Dispatchers.IO + SupervisorJob()) }
val activity = remember(context) { context as? Activity }
val haptics = LocalAppHaptics.current val haptics = LocalAppHaptics.current
val navigator = LocalRootNavigator.current val navigator = LocalRootNavigator.current
@@ -207,20 +206,9 @@ fun DeviceTabPage(
// read only // read only
val soBundleShared by scrcpyOptions.bundleState.collectAsState() val soBundleShared by scrcpyOptions.bundleState.collectAsState()
fun setKeepScreenOn(enabled: Boolean) { DisposableEffect(Unit) {
val window = activity?.window ?: return
window.decorView.post {
if (enabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
}
DisposableEffect(activity) {
onDispose { onDispose {
setKeepScreenOn(false) AppWakeLocks.release()
} }
} }
@@ -306,8 +294,8 @@ fun DeviceTabPage(
) { ) {
// Also stops scrcpy. // Also stops scrcpy.
runCatching { scrcpy.stop() } runCatching { scrcpy.stop() }
setKeepScreenOn(false)
runCatching { NativeAdbService.disconnect() } runCatching { NativeAdbService.disconnect() }
AppWakeLocks.release()
adbConnected = false adbConnected = false
currentTargetHost = "" currentTargetHost = ""
currentTargetPort = Defaults.ADB_PORT currentTargetPort = Defaults.ADB_PORT
@@ -533,14 +521,12 @@ fun DeviceTabPage(
val options = scrcpyOptions.toClientOptions(soBundleShared).fix() val options = scrcpyOptions.toClientOptions(soBundleShared).fix()
val session = scrcpy.start(options) val session = scrcpy.start(options)
pendingScrollToPreview = true pendingScrollToPreview = true
if (openFullscreen) { if (openFullscreen) withContext(Dispatchers.Main) {
withContext(Dispatchers.Main) { context.startActivity(StreamActivity.createIntent(context))
context.startActivity(StreamActivity.createIntent(context))
}
}
if (options.disableScreensaver) {
setKeepScreenOn(true)
} }
if (options.disableScreensaver)
AppWakeLocks.acquire()
statusLine = "scrcpy 运行中" statusLine = "scrcpy 运行中"
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
val videoDetail = val videoDetail =
@@ -934,7 +920,7 @@ fun DeviceTabPage(
onStop = { onStop = {
runBusy("停止 scrcpy") { runBusy("停止 scrcpy") {
scrcpy.stop() scrcpy.stop()
setKeepScreenOn(false) AppWakeLocks.release()
statusLine = "${currentTarget!!.host}:${currentTarget.port}" statusLine = "${currentTarget!!.host}:${currentTarget.port}"
logEvent("scrcpy 已停止") logEvent("scrcpy 已停止")
snackbar.show("scrcpy 已停止") snackbar.show("scrcpy 已停止")

View File

@@ -0,0 +1,35 @@
package io.github.miuzarte.scrcpyforandroid.services
import android.annotation.SuppressLint
import android.content.Context
import android.os.PowerManager
object AppWakeLocks {
private lateinit var appContext: Context
private lateinit var powerManager: PowerManager
fun init(context: Context) {
appContext = context.applicationContext
powerManager = appContext.getSystemService(Context.POWER_SERVICE) as PowerManager
}
private var wakeLock: PowerManager.WakeLock? = null
@SuppressLint("WakelockTimeout")
fun acquire() {
if (wakeLock != null) return
wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"${appContext.packageName}:scrcpy-wakelock",
).apply {
setReferenceCounted(false)
acquire()
}
}
fun release() {
wakeLock?.runCatching { release() }
wakeLock = null
}
}