Skip to content

Commit

Permalink
Merge pull request #186 from ooni/battery-optimizations
Browse files Browse the repository at this point in the history
Request to ignore battery optimizations
  • Loading branch information
sdsantos authored Oct 16, 2024
2 parents cc6f903 + ecb6a2b commit 42f71ef
Show file tree
Hide file tree
Showing 13 changed files with 268 additions and 74 deletions.
1 change: 0 additions & 1 deletion composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ kotlin {
// This makes instrumented tests depend on commonTest and androidUnitTest sources
sourceSetTree.set(KotlinSourceSetTree.test)
}
instrumentedTestVariant { }
}

iosX64()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class OnboardingTest {
clickOnText("True")

wait { onNodeWithText("Automated testing").isDisplayed() }
clickOnTag("Yes-AutoTest")
clickOnTag("No-AutoTest")

wait { onNodeWithText("Crash Reporting").isDisplayed() }
clickOnTag("Yes-CrashReporting")
Expand All @@ -63,7 +63,7 @@ class OnboardingTest {
}

assertEquals(
true,
false,
preferences.getValueByKey(SettingsKey.AUTOMATED_TESTING_ENABLED).first(),
)
assertEquals(true, preferences.getValueByKey(SettingsKey.SEND_CRASH).first())
Expand Down
1 change: 1 addition & 0 deletions composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<application
android:name=".AndroidApplication"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.net.Uri
import android.os.BatteryManager
import android.os.Build
import android.os.LocaleList
import android.os.PowerManager
import androidx.core.content.FileProvider
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.SharedPreferencesMigration
Expand All @@ -25,6 +26,7 @@ import okio.Path.Companion.toPath
import org.ooni.engine.AndroidNetworkTypeFinder
import org.ooni.engine.AndroidOonimkallBridge
import org.ooni.probe.background.AppWorkerManager
import org.ooni.probe.config.AndroidBatteryOptimization
import org.ooni.probe.data.models.FileSharing
import org.ooni.probe.di.Dependencies
import org.ooni.probe.shared.Platform
Expand Down Expand Up @@ -53,9 +55,12 @@ class AndroidApplication : Application() {
configureDescriptorAutoUpdate = appWorkerManager::configureDescriptorAutoUpdate,
fetchDescriptorUpdate = appWorkerManager::fetchDescriptorUpdate,
shareFile = ::shareFile,
batteryOptimization = batteryOptimization,
)
}

private val mainActivityLifecycleCallbacks = MainActivityLifecycleCallbacks()

override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
Expand All @@ -65,6 +70,7 @@ class AndroidApplication : Application() {
LocaleList.forLanguageTags(getString(R.string.supported_languages)),
)
}
registerActivityLifecycleCallbacks(mainActivityLifecycleCallbacks)
}

private val platformInfo by lazy {
Expand Down Expand Up @@ -194,4 +200,14 @@ class AndroidApplication : Application() {
false
}
}

private val batteryOptimization by lazy {
AndroidBatteryOptimization(
powerManager = getSystemService(PowerManager::class.java),
packageName = packageName,
requestCall = { callback ->
mainActivityLifecycleCallbacks.activity?.requestIgnoreBatteryOptimization(callback)
},
)
}
}
29 changes: 29 additions & 0 deletions composeApp/src/androidMain/kotlin/org/ooni/probe/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package org.ooni.probe

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContract
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
Expand Down Expand Up @@ -60,4 +65,28 @@ class MainActivity : ComponentActivity() {
}
}
}

// Battery Optimization

private var ignoreBatteryOptimizationCallback: (() -> Unit)? = null

private val ignoreBatteryOptimizationContract =
registerForActivityResult(object : ActivityResultContract<Unit, Unit>() {
@SuppressLint("BatteryLife")
override fun createIntent(
context: Context,
input: Unit,
) = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.setData(Uri.parse("package:$packageName"))

override fun parseResult(
resultCode: Int,
intent: Intent?,
) {}
}) { ignoreBatteryOptimizationCallback?.invoke() }

fun requestIgnoreBatteryOptimization(callback: () -> Unit) {
ignoreBatteryOptimizationCallback = callback
ignoreBatteryOptimizationContract.launch(Unit)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.ooni.probe

import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Bundle

class MainActivityLifecycleCallbacks : ActivityLifecycleCallbacks {
var activity: MainActivity? = null
private set

override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?,
) {
this.activity = activity as? MainActivity
}

override fun onActivityStarted(activity: Activity) {}

override fun onActivityResumed(activity: Activity) {}

override fun onActivityPaused(activity: Activity) {}

override fun onActivityStopped(activity: Activity) {}

override fun onActivitySaveInstanceState(
activity: Activity,
outState: Bundle,
) {}

override fun onActivityDestroyed(activity: Activity) {
this.activity = null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.ooni.probe.config

import android.os.PowerManager

class AndroidBatteryOptimization(
private val powerManager: PowerManager,
private val packageName: String,
private val requestCall: (() -> Unit) -> Unit,
) : BatteryOptimization {
override val isSupported = true

override val isIgnoring: Boolean
get() = powerManager.isIgnoringBatteryOptimizations(packageName)

override fun requestIgnore(onResponse: (Boolean) -> Unit) {
requestCall {
onResponse(isIgnoring)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@
<string name="Modal_CustomURL_Title_NotSaved">Are you sure?</string>
<string name="Modal_CustomURL_NotSaved">Your URLs will not be saved when you leave this screen. Are you sure you want to leave this screen?</string>

<string name="Modal_Autorun_BatteryOptimization">OONI Probe cannot run automatically without battery optimization. Do you want to try again?</string>

<!-- New Strings -->
<string name="back">Back</string>
<string name="refresh">refresh</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.ooni.probe.config

interface BatteryOptimization {
val isSupported: Boolean get() = false

val isIgnoring: Boolean
get() = throw IllegalStateException("Battery Optimization not supported")

fun requestIgnore(onResponse: (Boolean) -> Unit) {
throw IllegalStateException("Battery Optimization not supported")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.ooni.engine.NetworkTypeFinder
import org.ooni.engine.OonimkallBridge
import org.ooni.engine.TaskEventMapper
import org.ooni.probe.Database
import org.ooni.probe.config.BatteryOptimization
import org.ooni.probe.data.disk.DeleteFiles
import org.ooni.probe.data.disk.DeleteFilesOkio
import org.ooni.probe.data.disk.ReadFile
Expand Down Expand Up @@ -111,6 +112,7 @@ class Dependencies(
val fetchDescriptorUpdate: suspend (List<InstalledTestDescriptorModel>?) -> Unit,
val localeDirection: (() -> LayoutDirection)? = null,
private val shareFile: (FileSharing) -> Boolean,
private val batteryOptimization: BatteryOptimization,
) {
// Common

Expand Down Expand Up @@ -426,6 +428,7 @@ class Dependencies(
platformInfo = platformInfo,
preferenceRepository = preferenceRepository,
launchUrl = { launchUrl(it, null) },
batteryOptimization = batteryOptimization,
)

fun proxyViewModel(onBack: () -> Unit) = ProxyViewModel(onBack, preferenceRepository)
Expand Down
Loading

0 comments on commit 42f71ef

Please sign in to comment.