Skip to content

Commit b22a5e2

Browse files
committed
Add battery optimization prompt
To prompt users to disable battery optimization for better network I/O performance when running FTP server. Fixes #4603
1 parent 502d11a commit b22a5e2

10 files changed

Lines changed: 385 additions & 3 deletions

File tree

app/src/main/java/com/amaze/filemanager/asynchronous/services/ftp/FtpTileService.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package com.amaze.filemanager.asynchronous.services.ftp
2222
import android.content.Intent
2323
import android.graphics.drawable.Icon
2424
import android.os.Build
25+
import android.os.PowerManager
2526
import android.service.quicksettings.Tile
2627
import android.service.quicksettings.TileService
2728
import android.widget.Toast
@@ -76,6 +77,14 @@ class FtpTileService : TileService() {
7677
if (isConnectedToWifi(applicationContext) ||
7778
isConnectedToLocalNetwork(applicationContext)
7879
) {
80+
val pm = getSystemService(POWER_SERVICE) as PowerManager
81+
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
82+
Toast.makeText(
83+
applicationContext,
84+
R.string.ftp_battery_optimization_tile_warning,
85+
Toast.LENGTH_LONG,
86+
).show()
87+
}
7988
val i = Intent(FtpPreferences.ACTION_START_FTPSERVER).setPackage(packageName)
8089
i.putExtra(FtpPreferences.TAG_STARTED_BY_TILE, true)
8190
applicationContext.sendBroadcast(i)

app/src/main/java/com/amaze/filemanager/ui/fragments/FtpServerFragment.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ import android.os.Build.VERSION_CODES.LOLLIPOP
3434
import android.os.Build.VERSION_CODES.M
3535
import android.os.Build.VERSION_CODES.O
3636
import android.os.Bundle
37+
import android.os.PowerManager
3738
import android.os.Process
3839
import android.provider.DocumentsContract
3940
import android.provider.DocumentsContract.EXTRA_INITIAL_URI
4041
import android.provider.Settings
42+
import android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
4143
import android.text.InputType
4244
import android.text.Spanned
4345
import android.view.KeyEvent
@@ -122,6 +124,7 @@ class FtpServerFragment : Fragment(R.layout.fragment_ftp) {
122124
private var spannedStatusSecure: Spanned? = null
123125
private var spannedStatusNotRunning: Spanned? = null
124126
private var snackbar: Snackbar? = null
127+
private var pendingBatteryOptimizationResult = false
125128

126129
private var _binding: FragmentFtpBinding? = null
127130
private val binding get() = _binding!!
@@ -457,6 +460,53 @@ class FtpServerFragment : Fragment(R.layout.fragment_ftp) {
457460
}
458461
}
459462

463+
/**
464+
* On API 23+, checks whether the app is exempt from battery optimizations before starting
465+
* the FTP server. If already exempt, or if the user has previously dismissed the prompt,
466+
* [callback] is invoked directly. Otherwise a [MaterialDialog] is shown with options to
467+
* open battery optimization settings, skip, or suppress future prompts.
468+
*/
469+
private fun checkBatteryOptimizationIfNecessary(callback: () -> Unit) {
470+
if (SDK_INT < M) {
471+
callback()
472+
return
473+
}
474+
val pm = requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
475+
val alreadyAsked =
476+
FtpPreferences.getPreferences(requireContext())
477+
.getBoolean(FtpPreferences.KEY_PREFERENCE_BATTERY_OPTIMIZATION_ASKED, false)
478+
if (pm.isIgnoringBatteryOptimizations(requireContext().packageName) || alreadyAsked) {
479+
callback()
480+
return
481+
}
482+
MaterialDialog.Builder(requireContext())
483+
.title(R.string.ftp_battery_optimization_title)
484+
.content(R.string.ftp_battery_optimization_message)
485+
.positiveText(R.string.ftp_battery_optimization_action_settings)
486+
.negativeText(R.string.ftp_battery_optimization_action_skip)
487+
.neutralText(R.string.ftp_battery_optimization_action_dont_ask)
488+
.onPositive { dialog, _ ->
489+
pendingBatteryOptimizationResult = true
490+
startActivity(
491+
Intent(ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS),
492+
)
493+
dialog.dismiss()
494+
}
495+
.onNegative { dialog, _ ->
496+
dialog.dismiss()
497+
callback()
498+
}
499+
.onNeutral { dialog, _ ->
500+
FtpPreferences.getPreferences(requireContext()).edit {
501+
putBoolean(FtpPreferences.KEY_PREFERENCE_BATTERY_OPTIMIZATION_ASKED, true)
502+
}
503+
dialog.dismiss()
504+
callback()
505+
}
506+
.build()
507+
.show()
508+
}
509+
460510
/** Check URI access. Prompt user to DocumentsUI if necessary */
461511
private fun checkUriAccessIfNecessary(callback: () -> Unit) {
462512
val directoryUri: String =
@@ -534,8 +584,10 @@ class FtpServerFragment : Fragment(R.layout.fragment_ftp) {
534584

535585
/** Sends a broadcast to start ftp server */
536586
private fun startServer() {
537-
checkUriAccessIfNecessary {
538-
doStartServer()
587+
checkBatteryOptimizationIfNecessary {
588+
checkUriAccessIfNecessary {
589+
doStartServer()
590+
}
539591
}
540592
}
541593

@@ -562,6 +614,17 @@ class FtpServerFragment : Fragment(R.layout.fragment_ftp) {
562614
wifiFilter,
563615
ContextCompat.RECEIVER_NOT_EXPORTED,
564616
)
617+
if (pendingBatteryOptimizationResult) {
618+
pendingBatteryOptimizationResult = false
619+
if (SDK_INT >= M) {
620+
val pm = requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
621+
if (pm.isIgnoringBatteryOptimizations(requireContext().packageName) &&
622+
(isConnectedToWifi(requireContext()) || isConnectedToLocalNetwork(requireContext()))
623+
) {
624+
checkUriAccessIfNecessary { doStartServer() }
625+
}
626+
}
627+
}
565628
updateStatus()
566629
}
567630

app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/BehaviorPrefsFragment.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@
2020

2121
package com.amaze.filemanager.ui.fragments.preferencefragments
2222

23+
import android.content.Intent
24+
import android.os.Build.VERSION.SDK_INT
25+
import android.os.Build.VERSION_CODES.M
2326
import android.os.Bundle
2427
import android.os.Environment
28+
import android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
2529
import android.text.InputType
2630
import androidx.preference.Preference
2731
import androidx.preference.PreferenceManager
32+
import androidx.preference.TwoStatePreference
2833
import com.afollestad.materialdialogs.MaterialDialog
2934
import com.afollestad.materialdialogs.folderselector.FolderChooserDialog
3035
import com.amaze.filemanager.R
@@ -91,6 +96,26 @@ class BehaviorPrefsFragment : BasePrefsFragment(), FolderChooserDialog.FolderCal
9196
trashBinCleanupInterval()
9297
true
9398
}
99+
100+
val batteryOptPref =
101+
findPreference<TwoStatePreference>(
102+
PreferencesConstants.PREFERENCE_FTP_BATTERY_OPTIMIZATION_ASKED,
103+
)
104+
if (SDK_INT < M) {
105+
batteryOptPref?.isVisible = false
106+
} else {
107+
batteryOptPref?.onPreferenceChangeListener =
108+
Preference.OnPreferenceChangeListener { _, newValue ->
109+
// When user unchecks the toggle (re-enabling the prompt), deep-link to
110+
// battery optimization settings so they can act on it right away.
111+
if (newValue == false) {
112+
startActivity(
113+
Intent(ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS),
114+
)
115+
}
116+
true
117+
}
118+
}
94119
}
95120

96121
override fun onFolderSelection(

app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/PreferencesConstants.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ object PreferencesConstants {
8686
const val PREFERENCE_REGEX = "regex"
8787
const val PREFERENCE_REGEX_MATCHES = "matches"
8888

89+
// ftp preferences (shared key with FtpPreferences in ftpserver module)
90+
const val PREFERENCE_FTP_BATTERY_OPTIMIZATION_ASKED = "ftp_battery_optimization_asked"
91+
8992
// security_prefs.xml
9093
const val PREFERENCE_CRYPT_FINGERPRINT = "crypt_fingerprint"
9194
const val PREFERENCE_CRYPT_MASTER_PASSWORD = "crypt_password"

app/src/main/res/values/strings.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,15 @@ You only need to do this once, until the next time you select a new location for
761761
<string name="ftp_server_reset_notify">FTP server shared path had been reset to internal storage</string>
762762
<string name="ftp_server_root_unavailable">You are choosing a path which requires root access. Please enable root explorer in settings if your device is rooted.</string>
763763
<string name="ftp_server_root_filesystem_warning">You are choosing a path which requires root access, which enables read/write operations in the whole filesystem on your device, and it is dangerous - careless mistakes could brick your device!\n\nAre you sure?</string>
764+
<string name="ftp_battery_optimization_title">Battery Optimization</string>
765+
<string name="ftp_battery_optimization_message">Amaze FTP Server runs as a long-lived background service. Battery optimization may cause the OS to stop it unexpectedly or slow transfer speeds.\n\nFor best reliability, consider disabling battery optimization.</string>
766+
<string name="ftp_battery_optimization_action_settings">Open Settings</string>
767+
<string name="ftp_battery_optimization_action_skip">Skip</string>
768+
<string name="ftp_battery_optimization_action_dont_ask">Don\'t ask again</string>
769+
<string name="ftp_battery_optimization_tile_warning">Battery optimization is enabled — FTP server may be stopped by the OS</string>
770+
<string name="ftp_battery_optimization_pref_title">Disable battery optimization prompt</string>
771+
<string name="ftp_battery_optimization_pref_summary">Skip battery optimization reminder when starting the FTP server</string>
772+
<string name="ftp_server_preferences">FTP Server</string>
764773
<string name="compressed_explorer_fragment_error_open_uri">Error opening URI \"%s\" for reading.</string>
765774
<string name="error_empty_archive">\"%s\" is an empty archive.</string>
766775
<string name="error_bad_archive_without_info">\"%s\" is a corrupted archive.</string>

app/src/main/res/xml/behavior_prefs.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,11 @@
105105
app:summary="@string/root_mode_summary"
106106
app:title="@string/root_mode" />
107107
</PreferenceCategory>
108+
<PreferenceCategory app:title="@string/ftp_server_preferences">
109+
<com.amaze.filemanager.ui.views.preference.CheckBox
110+
app:defaultValue="false"
111+
app:key="ftp_battery_optimization_asked"
112+
app:summary="@string/ftp_battery_optimization_pref_summary"
113+
app:title="@string/ftp_battery_optimization_pref_title" />
114+
</PreferenceCategory>
108115
</PreferenceScreen>

0 commit comments

Comments
 (0)