android: mark manual mic as microphone foreground service · openclaw/openclaw@8ab36e4
joshavant
·
2026-06-18
·
via Recent Commits to openclaw:main
File tree
main/java/ai/openclaw/app
test/java/ai/openclaw/app
| Original file line number | Diff line number | Diff line change |
|---|
@@ -223,10 +223,11 @@ class NodeForegroundService : Service() {
|
223 | 223 | |
224 | 224 | internal fun foregroundServiceTypesForVoiceMode(mode: VoiceCaptureMode): Int { |
225 | 225 | val base = ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE |
226 | | -return if (mode == VoiceCaptureMode.TalkMode) { |
227 | | - base or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE |
228 | | - } else { |
229 | | - base |
| 226 | +return when (mode) { |
| 227 | +VoiceCaptureMode.Off -> base |
| 228 | +VoiceCaptureMode.ManualMic, |
| 229 | +VoiceCaptureMode.TalkMode, |
| 230 | +-> base or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE |
230 | 231 | } |
231 | 232 | } |
232 | 233 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1396,8 +1396,9 @@ class NodeRuntime(
|
1396 | 1396 | mode: VoiceCaptureMode, |
1397 | 1397 | persistManualMic: Boolean = true, |
1398 | 1398 | ) { |
1399 | | -if (mode == VoiceCaptureMode.TalkMode && !hasRecordAudioPermission()) { |
| 1399 | +if (mode.requiresMicrophonePermission && !hasRecordAudioPermission()) { |
1400 | 1400 | _voiceCaptureMode.value = VoiceCaptureMode.Off |
| 1401 | + prefs.setVoiceMicEnabled(false) |
1401 | 1402 | externalAudioCaptureActive.value = false |
1402 | 1403 | return |
1403 | 1404 | } |
@@ -1468,6 +1469,9 @@ class NodeRuntime(
|
1468 | 1469 | } |
1469 | 1470 | } |
1470 | 1471 | |
| 1472 | +private val VoiceCaptureMode.requiresMicrophonePermission: Boolean |
| 1473 | + get() = this == VoiceCaptureMode.ManualMic || this == VoiceCaptureMode.TalkMode |
| 1474 | + |
1471 | 1475 | fun refreshGatewayConnection() { |
1472 | 1476 | val endpoint = connectedEndpoint |
1473 | 1477 | if (endpoint == null) { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -376,6 +376,25 @@ class GatewayBootstrapAuthTest {
|
376 | 376 | assertNull(authStore.loadToken(deviceId, "operator")) |
377 | 377 | } |
378 | 378 | |
| 379 | + @Test |
| 380 | +fun restoredManualMicWithoutRecordAudioClearsStalePreference() { |
| 381 | +val app = RuntimeEnvironment.getApplication() |
| 382 | + shadowOf(app).denyPermissions(Manifest.permission.RECORD_AUDIO) |
| 383 | +val securePrefs = |
| 384 | + app.getSharedPreferences( |
| 385 | +"openclaw.node.secure.test.${UUID.randomUUID()}", |
| 386 | + android.content.Context.MODE_PRIVATE, |
| 387 | + ) |
| 388 | +val prefs = SecurePrefs(app, securePrefsOverride = securePrefs) |
| 389 | + prefs.setVoiceMicEnabled(true) |
| 390 | + |
| 391 | +val runtime = NodeRuntime(app, prefs) |
| 392 | + |
| 393 | + assertEquals(VoiceCaptureMode.Off, runtime.voiceCaptureMode.value) |
| 394 | + assertFalse(prefs.voiceMicEnabled.value) |
| 395 | + assertFalse(readField<MutableStateFlow<Boolean>>(runtime, "externalAudioCaptureActive").value) |
| 396 | + } |
| 397 | + |
379 | 398 | @Test |
380 | 399 | fun talkPttStart_cleansPreparedCaptureWhenBeginFails() = |
381 | 400 | runBlocking { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -32,13 +32,13 @@ class NodeForegroundServiceTest {
|
32 | 32 | } |
33 | 33 | |
34 | 34 | @Test |
35 | | -fun foregroundServiceTypesForVoiceMode_addsMicrophoneOnlyForTalkMode() { |
| 35 | +fun foregroundServiceTypesForVoiceMode_addsMicrophoneForActiveCaptureModes() { |
36 | 36 | assertEquals( |
37 | 37 | ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, |
38 | 38 | foregroundServiceTypesForVoiceMode(VoiceCaptureMode.Off), |
39 | 39 | ) |
40 | 40 | assertEquals( |
41 | | -ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, |
| 41 | +ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE, |
42 | 42 | foregroundServiceTypesForVoiceMode(VoiceCaptureMode.ManualMic), |
43 | 43 | ) |
44 | 44 | assertEquals( |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。