feat: optional --list-app call when connected

This commit is contained in:
Miuzarte
2026-04-13 13:53:32 +08:00
parent d8c66e528f
commit 2ddbbcf8b9
8 changed files with 70 additions and 34 deletions

View File

@@ -30,7 +30,6 @@
## 已知问题 ## 已知问题
- 在息屏状态下 `--list-apps` 会阻塞较长时间,可能会暂时导致设备无法断开连接,之后加开关禁用连接时拉取应用列表 (同时最近任务中会只显示包名)
- 因为没有设备用于(也懒得)测试,应用可能无法正常运行在安卓版本较低的设备上,特别是画中画功能,非常取决于国产 ROM 的实现 - 因为没有设备用于(也懒得)测试,应用可能无法正常运行在安卓版本较低的设备上,特别是画中画功能,非常取决于国产 ROM 的实现
- 关闭画中画后不会停止 scrcpy 串流,仍然需要回到应用中点击停止 - 关闭画中画后不会停止 scrcpy 串流,仍然需要回到应用中点击停止
- 虚拟按键的截图实现方式为发送 - 虚拟按键的截图实现方式为发送

View File

@@ -40,8 +40,8 @@ android {
applicationId = "io.github.miuzarte.scrcpyforandroid" applicationId = "io.github.miuzarte.scrcpyforandroid"
minSdk = 26 minSdk = 26
targetSdk = 36 targetSdk = 36
versionCode = 9 versionCode = 10
versionName = "0.1.3" versionName = "0.1.4"
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View File

@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Android
import androidx.compose.material.icons.rounded.MoreVert import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material.icons.rounded.Refresh import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -100,11 +101,9 @@ import top.yukonga.miuix.kmp.basic.TopAppBar
import top.yukonga.miuix.kmp.icon.MiuixIcons import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.basic.Check import top.yukonga.miuix.kmp.icon.basic.Check
import top.yukonga.miuix.kmp.icon.extended.Store import top.yukonga.miuix.kmp.icon.extended.Store
import top.yukonga.miuix.kmp.icon.extended.Tune
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
import top.yukonga.miuix.kmp.overlay.OverlayListPopup import top.yukonga.miuix.kmp.overlay.OverlayListPopup
import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.theme.MiuixTheme
import androidx.compose.foundation.lazy.LazyColumn as FoundationLazyColumn
private const val ADB_CONNECT_TIMEOUT_MS = 12_000L private const val ADB_CONNECT_TIMEOUT_MS = 12_000L
private const val ADB_KEEPALIVE_INTERVAL_MS = 3_000L private const val ADB_KEEPALIVE_INTERVAL_MS = 3_000L
@@ -616,7 +615,7 @@ fun DeviceTabPage(
val apps = scrcpy.listings.getApps(forceRefresh = false) val apps = scrcpy.listings.getApps(forceRefresh = false)
val matches = apps.filter { val matches = apps.filter {
it.label.startsWith(searchName, ignoreCase = true) it.label?.startsWith(searchName, ignoreCase = true) == true
} }
require(matches.isNotEmpty()) { require(matches.isNotEmpty()) {
@@ -624,7 +623,9 @@ fun DeviceTabPage(
} }
require(matches.size == 1) { require(matches.size == 1) {
"按应用名匹配到多个应用: " + "按应用名匹配到多个应用: " +
matches.take(5).joinToString { "${it.label} (${it.packageName})" } matches.take(5).joinToString {
"${it.label ?: it.packageName} (${it.packageName})"
}
} }
return StartAppRequest( return StartAppRequest(
@@ -773,11 +774,13 @@ fun DeviceTabPage(
"sdk=${info.sdkInt}" "sdk=${info.sdkInt}"
) )
snackbar.show("ADB 已连接") snackbar.show("ADB 已连接")
scope.launch(Dispatchers.IO) { if (asBundle.adbAutoLoadAppListOnConnect) {
runCatching { scope.launch(Dispatchers.IO) {
scrcpy.listings.getApps(forceRefresh = true) runCatching {
}.onFailure { error -> scrcpy.listings.getApps(forceRefresh = true)
logEvent("获取应用列表失败: ${error.message}", Log.WARN, error) }.onFailure { error ->
logEvent("获取应用列表失败: ${error.message}", Log.WARN, error)
}
} }
} }
@@ -1265,7 +1268,7 @@ private fun RecentTasksBottomSheet(
} }
else -> { else -> {
FoundationLazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(max = 420.dp), .heightIn(max = 420.dp),
@@ -1274,15 +1277,19 @@ private fun RecentTasksBottomSheet(
val task = tasks[index] val task = tasks[index]
val app = scrcpy.listings.findCachedApp(task.packageName) val app = scrcpy.listings.findCachedApp(task.packageName)
val entry = SpinnerEntry( val entry = SpinnerEntry(
icon = { modifier -> icon = app?.system?.let { system ->
Icon( { modifier ->
imageVector = if (app?.system == true) MiuixIcons.Tune else MiuixIcons.Store, Icon(
contentDescription = task.packageName, imageVector =
modifier = modifier, if (system) Icons.Rounded.Android // MiuixIcons.Tune
) else MiuixIcons.Store,
contentDescription = task.packageName,
modifier = modifier,
)
}
}, },
title = app?.label?.takeIf { it.isNotBlank() } ?: task.packageName, title = app?.label?.takeIf { it.isNotBlank() } ?: task.packageName,
summary = task.packageName, summary = app?.let { task.packageName },
) )
RecentTaskSheetItem( RecentTaskSheetItem(
entry = entry, entry = entry,

View File

@@ -15,6 +15,7 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Android
import androidx.compose.material.icons.rounded.DeleteOutline import androidx.compose.material.icons.rounded.DeleteOutline
import androidx.compose.material.icons.rounded.Edit import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.MoreVert import androidx.compose.material.icons.rounded.MoreVert
@@ -648,16 +649,18 @@ internal fun ScrcpyAllOptionsPage(
apps.forEach { app -> apps.forEach { app ->
add( add(
SpinnerEntry( SpinnerEntry(
icon = { icon = app.system?.let { system ->
Icon( {
imageVector = Icon(
if (app.system) MiuixIcons.Tune imageVector =
else MiuixIcons.Store, if (system) Icons.Rounded.Android // MiuixIcons.Tune
contentDescription = app.label, else MiuixIcons.Store,
modifier = Modifier.padding(end = UiSpacing.ContentVertical), contentDescription = app.label ?: app.packageName,
) modifier = Modifier.padding(end = UiSpacing.ContentVertical),
)
}
}, },
title = app.label, title = app.label?.takeIf { it.isNotBlank() } ?: app.packageName,
summary = app.packageName, summary = app.packageName,
) )
) )

View File

@@ -430,6 +430,19 @@ fun SettingsPage(
) )
}, },
) )
SwitchPreference(
title = "连接后自动获取应用列表",
summary = "ADB 连接成功后立刻执行 --list-apps用于补全最近任务列表应用名",
checked = asBundle.adbAutoLoadAppListOnConnect,
onCheckedChange = {
asBundle = asBundle.copy(
adbAutoLoadAppListOnConnect = it
)
if (it) snackbar.show(
"--list-apps 操作可能非常耗时(特别是在息屏状态下),启用后可能导致连接设备后阻塞过久!"
)
},
)
} }
} }

View File

@@ -15,15 +15,16 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
import top.yukonga.miuix.kmp.basic.ScrollBehavior import top.yukonga.miuix.kmp.basic.ScrollBehavior
import top.yukonga.miuix.kmp.utils.overScrollVertical import top.yukonga.miuix.kmp.utils.overScrollVertical
@Composable @Composable
fun LazyColumn( fun LazyColumn(
contentPadding: PaddingValues,
scrollBehavior: ScrollBehavior,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
scrollBehavior: ScrollBehavior? = null,
state: LazyListState = rememberLazyListState(), state: LazyListState = rememberLazyListState(),
itemSpacing: Dp = UiSpacing.PageItem, itemSpacing: Dp = UiSpacing.PageItem,
horizontalPadding: Dp = UiSpacing.PageHorizontal, horizontalPadding: Dp = UiSpacing.PageHorizontal,
@@ -43,7 +44,11 @@ fun LazyColumn(
} else Modifier } else Modifier
) )
.overScrollVertical() .overScrollVertical()
.nestedScroll(scrollBehavior.nestedScrollConnection) .then(
if (scrollBehavior != null)
Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
else Modifier
)
.padding(contentPadding), .padding(contentPadding),
state = state, state = state,
contentPadding = PaddingValues(horizontal = horizontalPadding, vertical = verticalPadding), contentPadding = PaddingValues(horizontal = horizontalPadding, vertical = verticalPadding),

View File

@@ -670,8 +670,8 @@ class Scrcpy(
) )
data class AppInfo( data class AppInfo(
val system: Boolean, val system: Boolean?,
val label: String, val label: String?,
val packageName: String, val packageName: String,
) )

View File

@@ -78,10 +78,15 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
booleanPreferencesKey("adb_auto_reconnect_paired_device"), booleanPreferencesKey("adb_auto_reconnect_paired_device"),
true true
) )
// 没必要加开关, 保持启用
val ADB_MDNS_LAN_DISCOVERY = Pair( val ADB_MDNS_LAN_DISCOVERY = Pair(
booleanPreferencesKey("adb_mdns_lan_discovery"), booleanPreferencesKey("adb_mdns_lan_discovery"),
true true
) )
val ADB_AUTO_LOAD_APP_LIST_ON_CONNECT = Pair(
booleanPreferencesKey("adb_auto_load_app_list_on_connect"),
false
)
val LAST_UPDATE_CHECK_AT = Pair( val LAST_UPDATE_CHECK_AT = Pair(
longPreferencesKey("last_update_check_at"), longPreferencesKey("last_update_check_at"),
0L 0L
@@ -112,6 +117,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
val adbPairingAutoDiscoverOnDialogOpen by setting(ADB_PAIRING_AUTO_DISCOVER_ON_DIALOG_OPEN) val adbPairingAutoDiscoverOnDialogOpen by setting(ADB_PAIRING_AUTO_DISCOVER_ON_DIALOG_OPEN)
val adbAutoReconnectPairedDevice by setting(ADB_AUTO_RECONNECT_PAIRED_DEVICE) val adbAutoReconnectPairedDevice by setting(ADB_AUTO_RECONNECT_PAIRED_DEVICE)
val adbMdnsLanDiscovery by setting(ADB_MDNS_LAN_DISCOVERY) val adbMdnsLanDiscovery by setting(ADB_MDNS_LAN_DISCOVERY)
val adbAutoLoadAppListOnConnect by setting(ADB_AUTO_LOAD_APP_LIST_ON_CONNECT)
val lastUpdateCheckAt by setting(LAST_UPDATE_CHECK_AT) val lastUpdateCheckAt by setting(LAST_UPDATE_CHECK_AT)
@Parcelize @Parcelize
@@ -133,6 +139,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
val adbPairingAutoDiscoverOnDialogOpen: Boolean, val adbPairingAutoDiscoverOnDialogOpen: Boolean,
val adbAutoReconnectPairedDevice: Boolean, val adbAutoReconnectPairedDevice: Boolean,
val adbMdnsLanDiscovery: Boolean, val adbMdnsLanDiscovery: Boolean,
val adbAutoLoadAppListOnConnect: Boolean,
val lastUpdateCheckAt: Long, val lastUpdateCheckAt: Long,
) : Parcelable { ) : Parcelable {
} }
@@ -155,6 +162,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
bundleField(ADB_PAIRING_AUTO_DISCOVER_ON_DIALOG_OPEN) { bundle: Bundle -> bundle.adbPairingAutoDiscoverOnDialogOpen }, bundleField(ADB_PAIRING_AUTO_DISCOVER_ON_DIALOG_OPEN) { bundle: Bundle -> bundle.adbPairingAutoDiscoverOnDialogOpen },
bundleField(ADB_AUTO_RECONNECT_PAIRED_DEVICE) { bundle: Bundle -> bundle.adbAutoReconnectPairedDevice }, bundleField(ADB_AUTO_RECONNECT_PAIRED_DEVICE) { bundle: Bundle -> bundle.adbAutoReconnectPairedDevice },
bundleField(ADB_MDNS_LAN_DISCOVERY) { bundle: Bundle -> bundle.adbMdnsLanDiscovery }, bundleField(ADB_MDNS_LAN_DISCOVERY) { bundle: Bundle -> bundle.adbMdnsLanDiscovery },
bundleField(ADB_AUTO_LOAD_APP_LIST_ON_CONNECT) { bundle: Bundle -> bundle.adbAutoLoadAppListOnConnect },
bundleField(LAST_UPDATE_CHECK_AT) { bundle: Bundle -> bundle.lastUpdateCheckAt }, bundleField(LAST_UPDATE_CHECK_AT) { bundle: Bundle -> bundle.lastUpdateCheckAt },
) )
@@ -180,6 +188,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
), ),
adbAutoReconnectPairedDevice = preferences.read(ADB_AUTO_RECONNECT_PAIRED_DEVICE), adbAutoReconnectPairedDevice = preferences.read(ADB_AUTO_RECONNECT_PAIRED_DEVICE),
adbMdnsLanDiscovery = preferences.read(ADB_MDNS_LAN_DISCOVERY), adbMdnsLanDiscovery = preferences.read(ADB_MDNS_LAN_DISCOVERY),
adbAutoLoadAppListOnConnect = preferences.read(ADB_AUTO_LOAD_APP_LIST_ON_CONNECT),
lastUpdateCheckAt = preferences.read(LAST_UPDATE_CHECK_AT), lastUpdateCheckAt = preferences.read(LAST_UPDATE_CHECK_AT),
) )