From 51d91bf9a79be692dab6964ef84c15fd83497b99 Mon Sep 17 00:00:00 2001
From: IndusAryan <125901294+IndusAryan@users.noreply.github.com>
Date: Mon, 25 Mar 2024 05:48:26 +0530
Subject: [PATCH] feat(ui): add ignore battery optimisation dialog for
uniterrupted downloads and notifications (#915)
---
.../ui/result/ResultFragmentPhone.kt | 12 ++-
.../ui/settings/SettingsGeneral.kt | 19 +++-
.../cloudstream3/utils/PowerManagerAPI.kt | 86 +++++++++++++++++++
app/src/main/res/drawable/ic_battery.xml | 12 +++
app/src/main/res/values/strings.xml | 11 +++
app/src/main/res/xml/settings_general.xml | 22 +++--
6 files changed, 152 insertions(+), 10 deletions(-)
create mode 100644 app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt
create mode 100644 app/src/main/res/drawable/ic_battery.xml
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
index 8d0ca37b..fb5160a7 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
@@ -30,7 +30,7 @@ import com.google.android.gms.cast.framework.CastState
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
-import com.lagradost.cloudstream3.CommonActivity
+import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.DubStatus
import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
@@ -61,6 +61,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
+import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.openBatteryOptimizationSettings
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
@@ -442,8 +443,9 @@ open class ResultFragmentPhone : FullScreenPlayer() {
val name = (viewModel.page.value as? Resource.Success)?.value?.title
?: txt(R.string.no_data).asStringNull(context) ?: ""
- CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
+ showToast(txt(message, name), Toast.LENGTH_SHORT)
}
+ context?.let { openBatteryOptimizationSettings(it) }
}
resultFavorite.setOnClickListener {
viewModel.toggleFavoriteStatus(context) { newStatus: Boolean? ->
@@ -457,7 +459,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
val name = (viewModel.page.value as? Resource.Success)?.value?.title
?: txt(R.string.no_data).asStringNull(context) ?: ""
- CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
+ showToast(txt(message, name), Toast.LENGTH_SHORT)
}
}
mediaRouteButton.apply {
@@ -465,7 +467,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
alpha = if (chromecastSupport) 1f else 0.3f
if (!chromecastSupport) {
setOnClickListener {
- CommonActivity.showToast(
+ showToast(
R.string.no_chromecast_support_toast,
Toast.LENGTH_LONG
)
@@ -640,6 +642,8 @@ open class ResultFragmentPhone : FullScreenPlayer() {
),
null
) { click ->
+ context?.let { openBatteryOptimizationSettings(it) }
+
when (click.action) {
DOWNLOAD_ACTION_DOWNLOAD -> {
viewModel.handleAction(
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt
index 6cf00375..c3d84867 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt
@@ -27,11 +27,15 @@ import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.ui.EasterEggMonke
+import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
import com.lagradost.cloudstream3.ui.settings.Globals.beneneCount
+import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
+import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.isAppRestricted
+import com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.showBatteryOptimizationDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
@@ -45,7 +49,6 @@ import com.lagradost.safefile.SafeFile
// Change local language settings in the app.
fun getCurrentLocale(context: Context): String {
- // val dm = res.displayMetrics
val res = context.resources
val conf = res.configuration
@@ -204,6 +207,20 @@ class SettingsGeneral : PreferenceFragmentCompat() {
return@setOnPreferenceClickListener true
}
+ // disable preference on tvs and emulators
+ getPref(R.string.battery_optimisation_key)?.isEnabled = isLayout(PHONE)
+ getPref(R.string.battery_optimisation_key)?.setOnPreferenceClickListener {
+ val ctx = context ?: return@setOnPreferenceClickListener false
+
+ if (isAppRestricted(ctx)) {
+ showBatteryOptimizationDialog(ctx)
+ } else {
+ showToast(R.string.app_unrestricted_toast)
+ }
+
+ true
+ }
+
fun showAdd() {
val providers = synchronized(allProviders) { allProviders.distinctBy { it.javaClass }.sortedBy { it.name } }
activity?.showDialog(
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt
new file mode 100644
index 00000000..27609730
--- /dev/null
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt
@@ -0,0 +1,86 @@
+package com.lagradost.cloudstream3.utils
+
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Bundle
+import android.os.PowerManager
+import android.provider.Settings
+import android.util.Log
+import androidx.appcompat.app.AlertDialog
+import androidx.preference.PreferenceManager
+import com.lagradost.cloudstream3.BuildConfig
+import com.lagradost.cloudstream3.CommonActivity.showToast
+import com.lagradost.cloudstream3.R
+import com.lagradost.cloudstream3.ui.settings.Globals.PHONE
+import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
+
+const val packageName = BuildConfig.APPLICATION_ID
+const val TAG = "PowerManagerAPI"
+
+object BatteryOptimizationChecker {
+
+ fun isAppRestricted(context: Context?): Boolean {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null) {
+ val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
+ return !powerManager.isIgnoringBatteryOptimizations(context.packageName)
+ }
+
+ return false // below Marshmallow, it's always unrestricted when app is in background
+ }
+
+ fun openBatteryOptimizationSettings(context: Context) {
+ if (shouldShowBatteryOptimizationDialog(context)) {
+ showBatteryOptimizationDialog(context)
+ }
+ }
+
+ fun showBatteryOptimizationDialog(context: Context) {
+ val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
+
+ try {
+ context.let {
+ AlertDialog.Builder(it)
+ .setTitle(R.string.battery_dialog_title)
+ .setIcon(R.drawable.ic_battery)
+ .setMessage(R.string.battery_dialog_message)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ intentOpenAppInfo(it)
+ }
+ .setNegativeButton(R.string.cancel) { _, _ ->
+ settingsManager.edit()
+ .putBoolean(context.getString(R.string.battery_optimisation_key), false)
+ .apply()
+ }
+ .show()
+ }
+ } catch (t: Throwable) {
+ Log.e(TAG, "Error showing battery optimization dialog", t)
+ }
+ }
+
+ private fun shouldShowBatteryOptimizationDialog(context: Context): Boolean {
+ val isRestricted = isAppRestricted(context)
+ val isOptimizedNotShown = PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(context.getString(R.string.battery_optimisation_key), true)
+ return isRestricted && isOptimizedNotShown && isLayout(PHONE)
+ }
+
+ private fun intentOpenAppInfo(context: Context) {
+ val intent = Intent()
+ try {
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ .setData(Uri.fromParts("package", packageName, null))
+ context.startActivity(intent, Bundle())
+ } catch (t: Throwable) {
+ Log.e(TAG, "Unable to invoke any intent", t)
+ if (t is ActivityNotFoundException) {
+ showToast("Exception: Activity Not Found")
+ } else {
+ showToast(R.string.app_info_intent_error)
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/ic_battery.xml b/app/src/main/res/drawable/ic_battery.xml
new file mode 100644
index 00000000..24d0a77f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_battery.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d88489a4..378fa16a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -654,6 +654,17 @@
Are you sure you want to exit\?
Yes
No
+ OK
+ Disable Battery optimization
+ To ensure uninterrupted downloads and notifications for subscribed
+ TV shows, CloudStream needs permission to run in background. By pressing "OK", you\'ll be directed to App info.
+ There, scroll to ๐ผ๐ฅ๐ฅ ๐๐๐ฉ๐ฉ๐๐ง๐ฎ ๐ช๐จ๐๐๐ and set battery usage to ๐๐ฃ๐ง๐๐จ๐ฉ๐ง๐๐๐ฉ๐๐. Please note, this permission
+ does not mean CS3 will drain your battery. It will only operate in the background when necessary, such as
+ when receiving notifications or downloading videos from official extensions. If you choose to cancel,
+ you can adjust this setting later in ๐๐๐ฃ๐๐ง๐๐ก ๐๐๐ฉ๐ฉ๐๐ฃ๐๐จ.
+ battery_optimisation
+ App battery usage is already set to unrestricted
+ Unable to open CloudStream\'s App info.
Downloading app updateโฆ
Installing app updateโฆ
Could not install the new version of the app
diff --git a/app/src/main/res/xml/settings_general.xml b/app/src/main/res/xml/settings_general.xml
index c4900bca..cdda6d85 100644
--- a/app/src/main/res/xml/settings_general.xml
+++ b/app/src/main/res/xml/settings_general.xml
@@ -6,10 +6,7 @@
android:title="@string/app_language"
android:icon="@drawable/ic_baseline_language_24" />
-
+
+ android:title="@string/title_downloads">
+
+
+
+
+
+
+
+