Skip to content

Commit afa4679

Browse files
committed
Desktop battery state support
1 parent 8308313 commit afa4679

File tree

11 files changed

+99
-32
lines changed

11 files changed

+99
-32
lines changed

composeApp/src/androidMain/kotlin/org/ooni/probe/AndroidApplication.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.ooni.engine.AndroidOonimkallBridge
3030
import org.ooni.probe.background.AppWorkerManager
3131
import org.ooni.probe.config.AndroidBatteryOptimization
3232
import org.ooni.probe.config.FlavorConfig
33+
import org.ooni.probe.data.models.BatteryState
3334
import org.ooni.probe.data.models.PlatformAction
3435
import org.ooni.probe.di.Dependencies
3536
import org.ooni.probe.shared.Platform
@@ -50,7 +51,7 @@ class AndroidApplication : Application() {
5051
databaseDriverFactory = ::buildDatabaseDriver,
5152
networkTypeFinder = AndroidNetworkTypeFinder(connectivityManager),
5253
buildDataStore = ::buildDataStore,
53-
isBatteryCharging = ::checkBatteryCharging,
54+
getBatteryState = ::getBatteryState,
5455
startSingleRunInner = appWorkerManager::startSingleRun,
5556
configureAutoRun = appWorkerManager::configureAutoRun,
5657
configureDescriptorAutoUpdate = appWorkerManager::configureDescriptorAutoUpdate,
@@ -106,12 +107,13 @@ class AndroidApplication : Application() {
106107
),
107108
)
108109

109-
private fun checkBatteryCharging(): Boolean {
110+
private fun getBatteryState(): BatteryState {
110111
// From https://developer.android.com/training/monitoring-device-state/battery-monitoring#DetermineChargeState
111112
val batteryStatus = registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
112113
val status = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1
113-
return status == BatteryManager.BATTERY_STATUS_CHARGING ||
114+
val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
114115
status == BatteryManager.BATTERY_STATUS_FULL
116+
return if (isCharging) BatteryState.Charging else BatteryState.NotCharging
115117
}
116118

117119
private fun launchAction(action: PlatformAction): Boolean {

composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import org.ooni.engine.models.TaskOrigin
1717
import org.ooni.engine.models.TaskSettings
1818
import org.ooni.engine.models.resultOf
1919
import org.ooni.probe.config.OrganizationConfig
20+
import org.ooni.probe.data.models.BatteryState
2021
import org.ooni.probe.data.models.InstalledTestDescriptorModel
2122
import org.ooni.probe.data.models.NetTest
2223
import org.ooni.probe.shared.PlatformInfo
@@ -32,7 +33,7 @@ class Engine(
3233
private val cacheDir: String,
3334
private val taskEventMapper: TaskEventMapper,
3435
private val networkTypeFinder: NetworkTypeFinder,
35-
private val isBatteryCharging: suspend () -> Boolean,
36+
private val getBatteryState: () -> BatteryState,
3637
private val platformInfo: PlatformInfo,
3738
private val getEnginePreferences: suspend () -> EnginePreferences,
3839
private val addRunCancelListener: (() -> Unit) -> Unit,
@@ -199,6 +200,15 @@ class Engine(
199200
platformInfo.platform.value +
200201
(if (taskOrigin == TaskOrigin.AutoRun) "-" + "unattended" else "")
201202

203+
private fun isBatteryCharging(): Boolean {
204+
return when (getBatteryState()) {
205+
BatteryState.NotCharging -> false
206+
BatteryState.Charging,
207+
BatteryState.Unknown,
208+
-> true
209+
}
210+
}
211+
202212
private val oonimkallLogger by lazy {
203213
object : OonimkallBridge.Logger {
204214
override fun debug(msg: String?) {
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.ooni.probe.data.models
22

3-
data class BatteryState(
4-
val isCharging: Boolean,
5-
)
3+
enum class BatteryState {
4+
NotCharging,
5+
Charging,
6+
Unknown,
7+
}

composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.ooni.probe.data.disk.ReadFileOkio
2828
import org.ooni.probe.data.disk.WriteFile
2929
import org.ooni.probe.data.disk.WriteFileOkio
3030
import org.ooni.probe.data.models.AutoRunParameters
31+
import org.ooni.probe.data.models.BatteryState
3132
import org.ooni.probe.data.models.InstalledTestDescriptorModel
3233
import org.ooni.probe.data.models.MeasurementModel
3334
import org.ooni.probe.data.models.PlatformAction
@@ -114,7 +115,7 @@ class Dependencies(
114115
private val networkTypeFinder: NetworkTypeFinder,
115116
@VisibleForTesting
116117
val buildDataStore: () -> DataStore<Preferences>,
117-
private val isBatteryCharging: () -> Boolean,
118+
private val getBatteryState: () -> BatteryState,
118119
val startSingleRunInner: (RunSpecification) -> Unit,
119120
private val configureAutoRun: suspend (AutoRunParameters) -> Unit,
120121
val configureDescriptorAutoUpdate: suspend () -> Boolean,
@@ -195,7 +196,7 @@ class Dependencies(
195196
cacheDir = cacheDir,
196197
taskEventMapper = taskEventMapper,
197198
networkTypeFinder = networkTypeFinder,
198-
isBatteryCharging = isBatteryCharging,
199+
getBatteryState = getBatteryState,
199200
platformInfo = platformInfo,
200201
getEnginePreferences = getEnginePreferences::invoke,
201202
addRunCancelListener = runBackgroundStateManager::addCancelListener,
@@ -231,7 +232,8 @@ class Dependencies(
231232
CheckAutoRunConstraints(
232233
getAutoRunSettings = getAutoRunSettings::invoke,
233234
getNetworkType = networkTypeFinder::invoke,
234-
isBatteryCharging = isBatteryCharging::invoke,
235+
getBatteryState = getBatteryState::invoke,
236+
knownBatteryState = platformInfo.knownBatteryState,
235237
resultRepository::countMissingUpload,
236238
)
237239
}
@@ -315,6 +317,7 @@ class Dependencies(
315317
observeStorageUsed = getStorageUsed::observe,
316318
clearStorage = clearStorage::invoke,
317319
supportsCrashReporting = flavorConfig.isCrashReportingEnabled,
320+
knownBatteryState = platformInfo.knownBatteryState,
318321
)
319322
}
320323

composeApp/src/commonMain/kotlin/org/ooni/probe/domain/CheckAutoRunConstraints.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import kotlinx.coroutines.flow.Flow
55
import kotlinx.coroutines.flow.first
66
import org.ooni.engine.models.NetworkType
77
import org.ooni.probe.data.models.AutoRunParameters
8+
import org.ooni.probe.data.models.BatteryState
89

910
class CheckAutoRunConstraints(
1011
private val getAutoRunSettings: suspend () -> Flow<AutoRunParameters>,
1112
private val getNetworkType: () -> NetworkType,
12-
private val isBatteryCharging: () -> Boolean,
13+
private val getBatteryState: () -> BatteryState,
14+
private val knownBatteryState: Boolean,
1315
private val countResultsMissingUpload: () -> Flow<Long>,
1416
) {
1517
suspend operator fun invoke(): Boolean {
@@ -30,7 +32,10 @@ class CheckAutoRunConstraints(
3032
return false
3133
}
3234

33-
if (autoRunParameters.onlyWhileCharging && !isBatteryCharging()) {
35+
if (knownBatteryState &&
36+
autoRunParameters.onlyWhileCharging &&
37+
getBatteryState() == BatteryState.NotCharging
38+
) {
3439
Logger.i("Not starting auto-run because of battery charging constraint")
3540
return false
3641
}

composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetSettings.kt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class GetSettings(
7474
private val clearStorage: suspend (Boolean) -> Unit,
7575
val observeStorageUsed: () -> Flow<Long>,
7676
private val supportsCrashReporting: Boolean,
77+
private val knownBatteryState: Boolean,
7778
) {
7879
operator fun invoke(): Flow<List<SettingsCategoryItem>> {
7980
return combine(
@@ -167,14 +168,19 @@ class GetSettings(
167168
enabled = autoRunEnabled && uploadResultsEnabled,
168169
indentation = 1,
169170
),
170-
SettingsItem(
171-
title = Res.string.Settings_AutomatedTesting_RunAutomatically_ChargingOnly,
172-
key = SettingsKey.AUTOMATED_TESTING_CHARGING,
173-
type = PreferenceItemType.SWITCH,
174-
enabled = autoRunEnabled && uploadResultsEnabled,
175-
indentation = 1,
176-
),
177-
)
171+
) + if (knownBatteryState) {
172+
listOf(
173+
SettingsItem(
174+
title = Res.string.Settings_AutomatedTesting_RunAutomatically_ChargingOnly,
175+
key = SettingsKey.AUTOMATED_TESTING_CHARGING,
176+
type = PreferenceItemType.SWITCH,
177+
enabled = autoRunEnabled && uploadResultsEnabled,
178+
indentation = 1,
179+
),
180+
)
181+
} else {
182+
emptyList()
183+
}
178184
} else {
179185
emptyList()
180186
} + if (hasWebsitesDescriptor) {

composeApp/src/commonMain/kotlin/org/ooni/probe/shared/PlatformInfo.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ data class PlatformInfo(
77
val osVersion: String,
88
val model: String,
99
val needsToRequestNotificationsPermission: Boolean,
10+
val knownBatteryState: Boolean = true,
1011
val sentryDsn: String,
1112
) {
1213
val version get() = "$buildName ($buildNumber)"

composeApp/src/commonTest/kotlin/org/ooni/engine/EngineTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.ooni.engine.models.TaskLogLevel
1111
import org.ooni.engine.models.TaskOrigin
1212
import org.ooni.engine.models.TaskSettings
1313
import org.ooni.engine.models.TestType
14+
import org.ooni.probe.data.models.BatteryState
1415
import org.ooni.probe.data.models.NetTest
1516
import org.ooni.probe.di.Dependencies
1617
import org.ooni.probe.shared.Platform
@@ -71,7 +72,7 @@ class EngineTest {
7172
cacheDir = "",
7273
taskEventMapper = TaskEventMapper(networkTypeFinder, json),
7374
networkTypeFinder = networkTypeFinder,
74-
isBatteryCharging = { true },
75+
getBatteryState = { BatteryState.Charging },
7576
platformInfo = PlatformInfo(
7677
buildName = "1",
7778
buildNumber = "1",

composeApp/src/commonTest/kotlin/org/ooni/probe/domain/CheckAutoRunConstraintsTest.kt

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import kotlinx.coroutines.flow.flowOf
44
import kotlinx.coroutines.test.runTest
55
import org.ooni.engine.models.NetworkType
66
import org.ooni.probe.data.models.AutoRunParameters
7+
import org.ooni.probe.data.models.BatteryState
78
import kotlin.test.Test
89
import kotlin.test.assertEquals
910
import kotlin.test.assertFalse
11+
import kotlin.test.assertTrue
1012

1113
class CheckAutoRunConstraintsTest {
1214
@Test
@@ -28,7 +30,8 @@ class CheckAutoRunConstraintsTest {
2830
)
2931
},
3032
getNetworkType = { NetworkType.Wifi },
31-
isBatteryCharging = { true },
33+
getBatteryState = { BatteryState.Charging },
34+
knownBatteryState = true,
3235
countResultsMissingUpload = { flowOf(count) },
3336
)(),
3437
)
@@ -51,10 +54,44 @@ class CheckAutoRunConstraintsTest {
5154
)
5255
},
5356
getNetworkType = { NetworkType.VPN },
54-
isBatteryCharging = { true },
57+
getBatteryState = { BatteryState.Charging },
58+
knownBatteryState = true,
5559
countResultsMissingUpload = { flowOf(0) },
5660
)
5761

5862
assertFalse(subject())
5963
}
64+
65+
@Test
66+
fun checkCharging() =
67+
runTest {
68+
suspend fun test(
69+
onlyWhileCharging: Boolean,
70+
batteryState: BatteryState,
71+
knownBatteryState: Boolean,
72+
) = CheckAutoRunConstraints(
73+
getAutoRunSettings = {
74+
flowOf(
75+
AutoRunParameters.Enabled(
76+
wifiOnly = false,
77+
onlyWhileCharging = onlyWhileCharging,
78+
),
79+
)
80+
},
81+
getNetworkType = { NetworkType.Wifi },
82+
getBatteryState = { batteryState },
83+
knownBatteryState = knownBatteryState,
84+
countResultsMissingUpload = { flowOf(0) },
85+
)()
86+
87+
assertTrue(
88+
test(onlyWhileCharging = true, BatteryState.Charging, knownBatteryState = true),
89+
)
90+
assertFalse(
91+
test(onlyWhileCharging = true, BatteryState.NotCharging, knownBatteryState = true),
92+
)
93+
assertTrue(
94+
test(onlyWhileCharging = true, BatteryState.Unknown, knownBatteryState = false),
95+
)
96+
}
6097
}

composeApp/src/desktopMain/kotlin/org/ooni/probe/BuildDependencies.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.ooni.probe.config.BatteryOptimization
1313
import org.ooni.probe.config.FlavorConfigInterface
1414
import org.ooni.probe.config.OptionalFeature
1515
import org.ooni.probe.data.models.AutoRunParameters
16+
import org.ooni.probe.data.models.BatteryState
1617
import org.ooni.probe.data.models.InstalledTestDescriptorModel
1718
import org.ooni.probe.data.models.PlatformAction
1819
import org.ooni.probe.data.models.RunSpecification
@@ -32,7 +33,7 @@ val dependencies = Dependencies(
3233
databaseDriverFactory = ::buildDatabaseDriver,
3334
networkTypeFinder = ::networkTypeFinder,
3435
buildDataStore = ::buildDataStore,
35-
isBatteryCharging = ::isBatteryCharging,
36+
getBatteryState = { BatteryState.Unknown },
3637
startSingleRunInner = ::startSingleRun,
3738
configureAutoRun = ::configureAutoRun,
3839
configureDescriptorAutoUpdate = ::configureDescriptorAutoUpdate,
@@ -52,6 +53,7 @@ private fun buildPlatformInfo() =
5253
osVersion = "1.0",
5354
model = "model",
5455
needsToRequestNotificationsPermission = false,
56+
knownBatteryState = false,
5557
sentryDsn = "",
5658
)
5759

@@ -73,11 +75,6 @@ private fun networkTypeFinder() = NetworkType.Wifi
7375
// TODO: Desktop - Confirm appropriate path and configuration
7476
private fun buildDataStore() = PreferenceDataStoreFactory.create { "$BASE_FILES_DIR/probe.preferences_pb".toPath().toFile() }
7577

76-
private fun isBatteryCharging(): Boolean {
77-
// TODO: Desktop - isBatteryCharging
78-
return true
79-
}
80-
8178
private fun startSingleRun(spec: RunSpecification) {
8279
// TODO: Desktop - background running
8380
CoroutineScope(Dispatchers.IO).launch {

0 commit comments

Comments
 (0)