diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt index 4fd8f882a..6183482d6 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt @@ -1,6 +1,5 @@ package io.nekohasekai.sagernet.ui -import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri @@ -10,8 +9,6 @@ import android.os.PowerManager import android.provider.Settings import android.view.View import android.widget.Toast -import androidx.activity.result.component1 -import androidx.activity.result.component2 import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.ViewCompat import androidx.recyclerview.widget.RecyclerView @@ -51,12 +48,13 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) { val requestIgnoreBatteryOptimizations = registerForActivityResult( ActivityResultContracts.StartActivityForResult() - ) { (resultCode, _) -> - if (resultCode == Activity.RESULT_OK) { - parentFragmentManager.beginTransaction() - .replace(R.id.about_fragment_holder, AboutContent()) - .commitAllowingStateLoss() - } + ) { + // The battery-optimization request/settings screen returns RESULT_CANCELED even + // when the user actually granted the exemption, so don't gate on the result code + // — just rebuild the list so the item's on/off subtext reflects the new state. + // Guard with isAdded: the fragment may be detached while the settings screen was + // open, and refreshMaterialAboutList() would otherwise touch a null adapter. + if (isAdded) refreshMaterialAboutList() } override fun getMaterialAboutList(activityContext: Context): MaterialAboutList { @@ -131,22 +129,32 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) { .apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val pm = app.getSystemService(Context.POWER_SERVICE) as PowerManager - if (!pm.isIgnoringBatteryOptimizations(app.packageName)) { - addItem( - MaterialAboutActionItem.Builder() - .icon(R.drawable.ic_baseline_running_with_errors_24) - .text(R.string.ignore_battery_optimizations) - .subText(R.string.ignore_battery_optimizations_sum) - .setOnClickAction { - requestIgnoreBatteryOptimizations.launch( - Intent( - Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - "package:${app.packageName}".toUri() - ) + val ignoring = pm.isIgnoringBatteryOptimizations(app.packageName) + addItem( + MaterialAboutActionItem.Builder() + .icon(R.drawable.ic_baseline_running_with_errors_24) + .text(R.string.ignore_battery_optimizations) + .subText( + if (ignoring) R.string.battery_optimization_enabled + else R.string.battery_optimization_disabled + ) + .setOnClickAction { + // The ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS + // dialog only appears while the app is still + // optimized; once exempt it is a no-op. So when + // already exempt, send the user to the battery + // settings screen where they can toggle it back off. + val intent = if (ignoring) { + Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) + } else { + Intent( + Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, + "package:${app.packageName}".toUri() ) } - .build()) - } + requestIgnoreBatteryOptimizations.launch(intent) + } + .build()) } } .build()) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7be22d054..1069dd9c8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -309,6 +309,8 @@ I love money Ignore battery optimizations Remove some restrictions + Enabled — the app can run unrestricted in the background + Disabled — tap to allow background activity Plugin Configure…