Skip to content

Commit 55c5b59

Browse files
Merge pull request #16034 from nextcloud/fix/battery-optimization-check
fix: battery optimization check
2 parents 8b0cc89 + c574b2c commit 55c5b59

2 files changed

Lines changed: 75 additions & 41 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
package com.nextcloud.utils
9+
10+
import android.annotation.SuppressLint
11+
import android.content.Context
12+
import android.content.Intent
13+
import android.os.PowerManager
14+
import android.provider.Settings
15+
import androidx.core.net.toUri
16+
import com.owncloud.android.lib.common.utils.Log_OC
17+
18+
object BatteryOptimizationHelper {
19+
20+
private const val TAG = "BatteryOptimizationHelper"
21+
22+
fun isBatteryOptimizationEnabled(context: Context): Boolean {
23+
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
24+
return !pm.isIgnoringBatteryOptimizations(context.packageName)
25+
}
26+
27+
@Suppress("TooGenericExceptionCaught")
28+
@SuppressLint("BatteryLife")
29+
fun openBatteryOptimizationSettings(context: Context) {
30+
try {
31+
val intent = Intent(
32+
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
33+
"package:${context.packageName}".toUri()
34+
)
35+
36+
if (intent.resolveActivity(context.packageManager) != null) {
37+
context.startActivity(intent)
38+
} else {
39+
// Fallback to generic battery optimization settings
40+
context.startActivity(Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS))
41+
}
42+
} catch (e: Exception) {
43+
Log_OC.d(TAG, "open battery optimization settings: ", e)
44+
}
45+
}
46+
}

app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,12 @@ import android.content.Intent
1414
import android.content.pm.PackageManager
1515
import android.os.Bundle
1616
import android.os.Looper
17-
import android.os.PowerManager
18-
import android.provider.Settings
1917
import android.text.TextUtils
2018
import android.view.Menu
2119
import android.view.MenuItem
2220
import android.view.View
2321
import androidx.annotation.VisibleForTesting
2422
import androidx.appcompat.app.AlertDialog
25-
import androidx.core.net.toUri
2623
import androidx.drawerlayout.widget.DrawerLayout
2724
import androidx.lifecycle.Lifecycle
2825
import androidx.lifecycle.lifecycleScope
@@ -36,10 +33,10 @@ import com.nextcloud.client.jobs.MediaFoldersDetectionWork
3633
import com.nextcloud.client.jobs.NotificationWork
3734
import com.nextcloud.client.jobs.upload.FileUploadWorker
3835
import com.nextcloud.client.preferences.SubFolderRule
36+
import com.nextcloud.utils.BatteryOptimizationHelper
3937
import com.nextcloud.utils.extensions.getParcelableArgument
4038
import com.nextcloud.utils.extensions.isDialogFragmentReady
4139
import com.nextcloud.utils.extensions.setVisibleIf
42-
import com.owncloud.android.BuildConfig
4340
import com.owncloud.android.MainApp
4441
import com.owncloud.android.R
4542
import com.owncloud.android.databinding.StoragePermissionWarningBannerBinding
@@ -577,7 +574,7 @@ class SyncedFoldersActivity :
577574
}
578575
if (syncedFolderDisplayItem.isEnabled) {
579576
backgroundJobManager.startAutoUploadImmediately(syncedFolderDisplayItem, overridePowerSaving = false)
580-
showBatteryOptimizationInfo()
577+
showBatteryOptimizationDialogIfNeeded()
581578
}
582579
}
583580

@@ -711,7 +708,7 @@ class SyncedFoldersActivity :
711708
}
712709
dialogFragment = null
713710
if (syncedFolder.isEnabled) {
714-
showBatteryOptimizationInfo()
711+
showBatteryOptimizationDialogIfNeeded()
715712
}
716713
}
717714

@@ -835,44 +832,35 @@ class SyncedFoldersActivity :
835832
}
836833
}
837834

838-
private fun showBatteryOptimizationInfo() {
839-
if (checkIfBatteryOptimizationEnabled()) {
840-
val alertDialogBuilder = MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog)
841-
.setTitle(getString(R.string.battery_optimization_title))
842-
.setMessage(getString(R.string.battery_optimization_message))
843-
.setPositiveButton(getString(R.string.battery_optimization_disable)) { _, _ ->
844-
// show instant upload
845-
@SuppressLint("BatteryLife")
846-
val intent = Intent(
847-
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
848-
("package:" + BuildConfig.APPLICATION_ID).toUri()
849-
)
850-
if (intent.resolveActivity(packageManager) != null) {
851-
startActivity(intent)
852-
}
853-
}
854-
.setNeutralButton(getString(R.string.battery_optimization_close)) { dialog, _ -> dialog.dismiss() }
855-
.setIcon(R.drawable.ic_battery_alert)
856-
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
857-
val alertDialog = alertDialogBuilder.show()
858-
viewThemeUtils.platform.colorTextButtons(
859-
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE),
860-
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)
861-
)
862-
}
835+
private fun showBatteryOptimizationDialogIfNeeded() {
836+
if (!BatteryOptimizationHelper.isBatteryOptimizationEnabled(this)) {
837+
Log_OC.d(TAG, "battery optimization is disabled")
838+
return
863839
}
840+
841+
showBatteryOptimizationDialog()
864842
}
865843

866-
/**
867-
* Check if battery optimization is enabled. If unknown, fallback to true.
868-
*
869-
* @return true if battery optimization is enabled
870-
*/
871-
private fun checkIfBatteryOptimizationEnabled(): Boolean {
872-
val powerManager = getSystemService(POWER_SERVICE) as PowerManager?
873-
return when {
874-
powerManager != null -> !powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
875-
else -> !appInfo.isDebugBuild
844+
private fun showBatteryOptimizationDialog() {
845+
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
846+
Log_OC.w(TAG, "Activity not resumed, skipping battery dialog")
847+
return
876848
}
849+
850+
val dialog = MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog)
851+
.setTitle(R.string.battery_optimization_title)
852+
.setMessage(R.string.battery_optimization_message)
853+
.setPositiveButton(R.string.battery_optimization_disable) { _, _ ->
854+
BatteryOptimizationHelper.openBatteryOptimizationSettings(this)
855+
}
856+
.setNeutralButton(R.string.battery_optimization_close, null)
857+
.setIcon(R.drawable.ic_battery_alert)
858+
859+
val alertDialog = dialog.show()
860+
861+
viewThemeUtils.platform.colorTextButtons(
862+
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE),
863+
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)
864+
)
877865
}
878866
}

0 commit comments

Comments
 (0)