mirror of
https://github.com/immich-app/immich.git
synced 2025-06-04 22:24:26 -04:00
chore(mobile): update target SDK version (#11719)
* chore(mobile): update target SDK version * background service * remove print statements * remove extra line * format kotlin * Correct permission
This commit is contained in:
parent
a4506758aa
commit
49610de4b3
@ -46,7 +46,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "app.alextran.immich"
|
applicationId "app.alextran.immich"
|
||||||
minSdkVersion 26
|
minSdkVersion 26
|
||||||
targetSdkVersion 33
|
targetSdkVersion 34
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,38 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.alextran.immich"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.alextran.immich"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_MEDIA" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
|
||||||
|
|
||||||
|
<!-- Foreground service permission -->
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
||||||
|
|
||||||
<application android:label="Immich" android:name=".ImmichApp" android:usesCleartextTraffic="true"
|
<application android:label="Immich" android:name=".ImmichApp" android:usesCleartextTraffic="true"
|
||||||
android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true"
|
android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true"
|
||||||
android:largeHeap="true">
|
android:largeHeap="true">
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
||||||
|
android:directBootAware="false"
|
||||||
|
android:enabled="@bool/enable_system_foreground_service_default"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="dataSync|shortService" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||||
android:value="false" />
|
android:value="false" />
|
||||||
@ -51,23 +80,13 @@
|
|||||||
<provider
|
<provider
|
||||||
android:name="androidx.startup.InitializationProvider"
|
android:name="androidx.startup.InitializationProvider"
|
||||||
android:authorities="${applicationId}.androidx-startup"
|
android:authorities="${applicationId}.androidx-startup"
|
||||||
tools:node="remove"></provider>
|
tools:node="remove" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
|
||||||
android:maxSdkVersion="32" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_MEDIA" />
|
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
@ -7,7 +7,6 @@ import io.flutter.plugin.common.BinaryMessenger
|
|||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.io.File
|
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
@ -21,7 +20,6 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
|
|||||||
|
|
||||||
private var methodChannel: MethodChannel? = null
|
private var methodChannel: MethodChannel? = null
|
||||||
private var context: Context? = null
|
private var context: Context? = null
|
||||||
private val sha1: MessageDigest = MessageDigest.getInstance("SHA-1")
|
|
||||||
|
|
||||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
onAttachedToEngine(binding.applicationContext, binding.binaryMessenger)
|
onAttachedToEngine(binding.applicationContext, binding.binaryMessenger)
|
||||||
@ -50,36 +48,47 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
|
|||||||
ctx.getSharedPreferences(BackupWorker.SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
ctx.getSharedPreferences(BackupWorker.SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
.putBoolean(ContentObserverWorker.SHARED_PREF_SERVICE_ENABLED, true)
|
.putBoolean(ContentObserverWorker.SHARED_PREF_SERVICE_ENABLED, true)
|
||||||
.putLong(BackupWorker.SHARED_PREF_CALLBACK_KEY, args.get(0) as Long)
|
.putLong(BackupWorker.SHARED_PREF_CALLBACK_KEY, args[0] as Long)
|
||||||
.putString(BackupWorker.SHARED_PREF_NOTIFICATION_TITLE, args.get(1) as String)
|
.putString(BackupWorker.SHARED_PREF_NOTIFICATION_TITLE, args[1] as String)
|
||||||
.apply()
|
.apply()
|
||||||
ContentObserverWorker.enable(ctx, immediate = args.get(2) as Boolean)
|
ContentObserverWorker.enable(ctx, immediate = args[2] as Boolean)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
"configure" -> {
|
"configure" -> {
|
||||||
val args = call.arguments<ArrayList<*>>()!!
|
val args = call.arguments<ArrayList<*>>()!!
|
||||||
val requireUnmeteredNetwork = args.get(0) as Boolean
|
val requireUnmeteredNetwork = args[0] as Boolean
|
||||||
val requireCharging = args.get(1) as Boolean
|
val requireCharging = args[1] as Boolean
|
||||||
val triggerUpdateDelay = (args.get(2) as Number).toLong()
|
val triggerUpdateDelay = (args[2] as Number).toLong()
|
||||||
val triggerMaxDelay = (args.get(3) as Number).toLong()
|
val triggerMaxDelay = (args[3] as Number).toLong()
|
||||||
ContentObserverWorker.configureWork(ctx, requireUnmeteredNetwork, requireCharging, triggerUpdateDelay, triggerMaxDelay)
|
ContentObserverWorker.configureWork(
|
||||||
|
ctx,
|
||||||
|
requireUnmeteredNetwork,
|
||||||
|
requireCharging,
|
||||||
|
triggerUpdateDelay,
|
||||||
|
triggerMaxDelay
|
||||||
|
)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
"disable" -> {
|
"disable" -> {
|
||||||
ContentObserverWorker.disable(ctx)
|
ContentObserverWorker.disable(ctx)
|
||||||
BackupWorker.stopWork(ctx)
|
BackupWorker.stopWork(ctx)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
"isEnabled" -> {
|
"isEnabled" -> {
|
||||||
result.success(ContentObserverWorker.isEnabled(ctx))
|
result.success(ContentObserverWorker.isEnabled(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
"isIgnoringBatteryOptimizations" -> {
|
"isIgnoringBatteryOptimizations" -> {
|
||||||
result.success(BackupWorker.isIgnoringBatteryOptimizations(ctx))
|
result.success(BackupWorker.isIgnoringBatteryOptimizations(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
"digestFiles" -> {
|
"digestFiles" -> {
|
||||||
val args = call.arguments<ArrayList<String>>()!!
|
val args = call.arguments<ArrayList<String>>()!!
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
val buf = ByteArray(BUFSIZE)
|
val buf = ByteArray(BUFFER_SIZE)
|
||||||
val digest: MessageDigest = MessageDigest.getInstance("SHA-1")
|
val digest: MessageDigest = MessageDigest.getInstance("SHA-1")
|
||||||
val hashes = arrayOfNulls<ByteArray>(args.size)
|
val hashes = arrayOfNulls<ByteArray>(args.size)
|
||||||
for (i in args.indices) {
|
for (i in args.indices) {
|
||||||
@ -87,14 +96,12 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
|
|||||||
var len = 0
|
var len = 0
|
||||||
try {
|
try {
|
||||||
val file = FileInputStream(path)
|
val file = FileInputStream(path)
|
||||||
try {
|
file.use { assetFile ->
|
||||||
while (true) {
|
while (true) {
|
||||||
len = file.read(buf)
|
len = assetFile.read(buf)
|
||||||
if (len != BUFSIZE) break
|
if (len != BUFFER_SIZE) break
|
||||||
digest.update(buf)
|
digest.update(buf)
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
file.close()
|
|
||||||
}
|
}
|
||||||
digest.update(buf, 0, len)
|
digest.update(buf, 0, len)
|
||||||
hashes[i] = digest.digest()
|
hashes[i] = digest.digest()
|
||||||
@ -106,10 +113,11 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
|
|||||||
result.success(hashes.asList())
|
result.success(hashes.asList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val TAG = "BackgroundServicePlugin"
|
private const val TAG = "BackgroundServicePlugin"
|
||||||
private const val BUFSIZE = 2*1024*1024;
|
private const val BUFFER_SIZE = 2 * 1024 * 1024;
|
||||||
|
@ -4,6 +4,7 @@ import android.app.Notification
|
|||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
@ -40,12 +41,14 @@ import java.util.concurrent.TimeUnit
|
|||||||
* Called by Android WorkManager when all constraints for the work are met,
|
* Called by Android WorkManager when all constraints for the work are met,
|
||||||
* i.e. battery is not low and optionally Wifi and charging are active.
|
* i.e. battery is not low and optionally Wifi and charging are active.
|
||||||
*/
|
*/
|
||||||
class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ctx, params), MethodChannel.MethodCallHandler {
|
class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ctx, params),
|
||||||
|
MethodChannel.MethodCallHandler {
|
||||||
|
|
||||||
private val resolvableFuture = ResolvableFuture.create<Result>()
|
private val resolvableFuture = ResolvableFuture.create<Result>()
|
||||||
private var engine: FlutterEngine? = null
|
private var engine: FlutterEngine? = null
|
||||||
private lateinit var backgroundChannel: MethodChannel
|
private lateinit var backgroundChannel: MethodChannel
|
||||||
private val notificationManager = ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
private val notificationManager =
|
||||||
|
ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
private val isIgnoringBatteryOptimizations = isIgnoringBatteryOptimizations(applicationContext)
|
private val isIgnoringBatteryOptimizations = isIgnoringBatteryOptimizations(applicationContext)
|
||||||
private var timeBackupStarted: Long = 0L
|
private var timeBackupStarted: Long = 0L
|
||||||
private var notificationBuilder: NotificationCompat.Builder? = null
|
private var notificationBuilder: NotificationCompat.Builder? = null
|
||||||
@ -61,10 +64,11 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
if (!flutterLoader.initialized()) {
|
if (!flutterLoader.initialized()) {
|
||||||
flutterLoader.startInitialization(ctx)
|
flutterLoader.startInitialization(ctx)
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
// Create a Notification channel if necessary
|
// Create a Notification channel
|
||||||
createChannel()
|
createChannel()
|
||||||
}
|
|
||||||
|
Log.d(TAG, "isIgnoringBatteryOptimizations $isIgnoringBatteryOptimizations")
|
||||||
if (isIgnoringBatteryOptimizations) {
|
if (isIgnoringBatteryOptimizations) {
|
||||||
// normal background services can only up to 10 minutes
|
// normal background services can only up to 10 minutes
|
||||||
// foreground services are allowed to run indefinitely
|
// foreground services are allowed to run indefinitely
|
||||||
@ -74,6 +78,7 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
.getString(SHARED_PREF_NOTIFICATION_TITLE, NOTIFICATION_DEFAULT_TITLE)!!
|
.getString(SHARED_PREF_NOTIFICATION_TITLE, NOTIFICATION_DEFAULT_TITLE)!!
|
||||||
showInfo(getInfoBuilder(title, indeterminate = true).build())
|
showInfo(getInfoBuilder(title, indeterminate = true).build())
|
||||||
}
|
}
|
||||||
|
|
||||||
engine = FlutterEngine(ctx)
|
engine = FlutterEngine(ctx)
|
||||||
|
|
||||||
flutterLoader.ensureInitializationCompleteAsync(ctx, null, Handler(Looper.getMainLooper())) {
|
flutterLoader.ensureInitializationCompleteAsync(ctx, null, Handler(Looper.getMainLooper())) {
|
||||||
@ -89,8 +94,10 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
*/
|
*/
|
||||||
private fun runDart() {
|
private fun runDart() {
|
||||||
val callbackDispatcherHandle = applicationContext.getSharedPreferences(
|
val callbackDispatcherHandle = applicationContext.getSharedPreferences(
|
||||||
SHARED_PREF_NAME, Context.MODE_PRIVATE).getLong(SHARED_PREF_CALLBACK_KEY, 0L)
|
SHARED_PREF_NAME, Context.MODE_PRIVATE
|
||||||
val callbackInformation = FlutterCallbackInformation.lookupCallbackInformation(callbackDispatcherHandle)
|
).getLong(SHARED_PREF_CALLBACK_KEY, 0L)
|
||||||
|
val callbackInformation =
|
||||||
|
FlutterCallbackInformation.lookupCallbackInformation(callbackDispatcherHandle)
|
||||||
val appBundlePath = flutterLoader.findAppBundlePath()
|
val appBundlePath = flutterLoader.findAppBundlePath()
|
||||||
|
|
||||||
engine?.let { engine ->
|
engine?.let { engine ->
|
||||||
@ -123,11 +130,10 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
|
|
||||||
private fun waitOnSetForegroundAsync() {
|
private fun waitOnSetForegroundAsync() {
|
||||||
val fgFuture = this.fgFuture
|
val fgFuture = this.fgFuture
|
||||||
if (fgFuture != null && !fgFuture.isCancelled() && !fgFuture.isDone()) {
|
if (fgFuture != null && !fgFuture.isCancelled && !fgFuture.isDone) {
|
||||||
try {
|
try {
|
||||||
fgFuture.get(500, TimeUnit.MILLISECONDS)
|
fgFuture.get(500, TimeUnit.MILLISECONDS)
|
||||||
}
|
} catch (e: Exception) {
|
||||||
catch (e: Exception) {
|
|
||||||
// ignored, there is nothing to be done
|
// ignored, there is nothing to be done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,6 +150,7 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
waitOnSetForegroundAsync()
|
waitOnSetForegroundAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
override fun onMethodCall(call: MethodCall, r: MethodChannel.Result) {
|
override fun onMethodCall(call: MethodCall, r: MethodChannel.Result) {
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"initialized" -> {
|
"initialized" -> {
|
||||||
@ -167,26 +174,32 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"updateNotification" -> {
|
"updateNotification" -> {
|
||||||
val args = call.arguments<ArrayList<*>>()!!
|
val args = call.arguments<ArrayList<*>>()!!
|
||||||
val title = args.get(0) as String?
|
val title = args[0] as String?
|
||||||
val content = args.get(1) as String?
|
val content = args[1] as String?
|
||||||
val progress = args.get(2) as Int
|
val progress = args[2] as Int
|
||||||
val max = args.get(3) as Int
|
val max = args[3] as Int
|
||||||
val indeterminate = args.get(4) as Boolean
|
val indeterminate = args[4] as Boolean
|
||||||
val isDetail = args.get(5) as Boolean
|
val isDetail = args[5] as Boolean
|
||||||
val onlyIfFG = args.get(6) as Boolean
|
val onlyIfFG = args[6] as Boolean
|
||||||
if (!onlyIfFG || isIgnoringBatteryOptimizations) {
|
if (!onlyIfFG || isIgnoringBatteryOptimizations) {
|
||||||
showInfo(getInfoBuilder(title, content, isDetail, progress, max, indeterminate).build(), isDetail)
|
showInfo(
|
||||||
|
getInfoBuilder(title, content, isDetail, progress, max, indeterminate).build(),
|
||||||
|
isDetail
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"showError" -> {
|
"showError" -> {
|
||||||
val args = call.arguments<ArrayList<*>>()!!
|
val args = call.arguments<ArrayList<*>>()!!
|
||||||
val title = args.get(0) as String
|
val title = args[0] as String
|
||||||
val content = args.get(1) as String?
|
val content = args[1] as String?
|
||||||
val individualTag = args.get(2) as String?
|
val individualTag = args[2] as String?
|
||||||
showError(title, content, individualTag)
|
showError(title, content, individualTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
"clearErrorNotifications" -> clearErrorNotifications()
|
"clearErrorNotifications" -> clearErrorNotifications()
|
||||||
"hasContentChanged" -> {
|
"hasContentChanged" -> {
|
||||||
val lastChange = applicationContext
|
val lastChange = applicationContext
|
||||||
@ -196,6 +209,7 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
timeBackupStarted = SystemClock.uptimeMillis()
|
timeBackupStarted = SystemClock.uptimeMillis()
|
||||||
r.success(hasContentChanged)
|
r.success(hasContentChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> r.notImplemented()
|
else -> r.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,8 +235,13 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
|
|
||||||
private fun showInfo(notification: Notification, isDetail: Boolean = false) {
|
private fun showInfo(notification: Notification, isDetail: Boolean = false) {
|
||||||
val id = if (isDetail) NOTIFICATION_DETAIL_ID else NOTIFICATION_ID
|
val id = if (isDetail) NOTIFICATION_DETAIL_ID else NOTIFICATION_ID
|
||||||
|
|
||||||
if (isIgnoringBatteryOptimizations && !isDetail) {
|
if (isIgnoringBatteryOptimizations && !isDetail) {
|
||||||
fgFuture = setForegroundAsync(ForegroundInfo(id, notification))
|
fgFuture = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
|
setForegroundAsync(ForegroundInfo(id, notification, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE))
|
||||||
|
} else {
|
||||||
|
setForegroundAsync(ForegroundInfo(id, notification))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
notificationManager.notify(id, notification)
|
notificationManager.notify(id, notification)
|
||||||
}
|
}
|
||||||
@ -257,11 +276,18 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
return builder.setProgress(max, progress, indeterminate)
|
return builder.setProgress(max, progress, indeterminate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
private fun createChannel() {
|
private fun createChannel() {
|
||||||
val foreground = NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW)
|
val foreground = NotificationChannel(
|
||||||
|
NOTIFICATION_CHANNEL_ID,
|
||||||
|
NOTIFICATION_CHANNEL_ID,
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
)
|
||||||
notificationManager.createNotificationChannel(foreground)
|
notificationManager.createNotificationChannel(foreground)
|
||||||
val error = NotificationChannel(NOTIFICATION_CHANNEL_ERROR_ID, NOTIFICATION_CHANNEL_ERROR_ID, NotificationManager.IMPORTANCE_HIGH)
|
val error = NotificationChannel(
|
||||||
|
NOTIFICATION_CHANNEL_ERROR_ID,
|
||||||
|
NOTIFICATION_CHANNEL_ERROR_ID,
|
||||||
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
|
)
|
||||||
notificationManager.createNotificationChannel(error)
|
notificationManager.createNotificationChannel(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,21 +309,26 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
/**
|
/**
|
||||||
* Enqueues the BackupWorker to run once the constraints are met
|
* Enqueues the BackupWorker to run once the constraints are met
|
||||||
*/
|
*/
|
||||||
fun enqueueBackupWorker(context: Context,
|
fun enqueueBackupWorker(
|
||||||
|
context: Context,
|
||||||
requireWifi: Boolean = false,
|
requireWifi: Boolean = false,
|
||||||
requireCharging: Boolean = false,
|
requireCharging: Boolean = false,
|
||||||
delayMilliseconds: Long = 0L) {
|
delayMilliseconds: Long = 0L
|
||||||
|
) {
|
||||||
val workRequest = buildWorkRequest(requireWifi, requireCharging, delayMilliseconds)
|
val workRequest = buildWorkRequest(requireWifi, requireCharging, delayMilliseconds)
|
||||||
WorkManager.getInstance(context).enqueueUniqueWork(TASK_NAME_BACKUP, ExistingWorkPolicy.KEEP, workRequest)
|
WorkManager.getInstance(context)
|
||||||
|
.enqueueUniqueWork(TASK_NAME_BACKUP, ExistingWorkPolicy.KEEP, workRequest)
|
||||||
Log.d(TAG, "enqueueBackupWorker: BackupWorker enqueued")
|
Log.d(TAG, "enqueueBackupWorker: BackupWorker enqueued")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the constraints of an already enqueued BackupWorker
|
* Updates the constraints of an already enqueued BackupWorker
|
||||||
*/
|
*/
|
||||||
fun updateBackupWorker(context: Context,
|
fun updateBackupWorker(
|
||||||
|
context: Context,
|
||||||
requireWifi: Boolean = false,
|
requireWifi: Boolean = false,
|
||||||
requireCharging: Boolean = false) {
|
requireCharging: Boolean = false
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
val wm = WorkManager.getInstance(context)
|
val wm = WorkManager.getInstance(context)
|
||||||
val workInfoFuture = wm.getWorkInfosForUniqueWork(TASK_NAME_BACKUP)
|
val workInfoFuture = wm.getWorkInfosForUniqueWork(TASK_NAME_BACKUP)
|
||||||
@ -314,7 +345,7 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
}
|
}
|
||||||
Log.d(TAG, "updateBackupWorker: BackupWorker not enqueued")
|
Log.d(TAG, "updateBackupWorker: BackupWorker not enqueued")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d(TAG, "updateBackupWorker failed: ${e}")
|
Log.d(TAG, "updateBackupWorker failed: $e")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,17 +361,15 @@ class BackupWorker(ctx: Context, params: WorkerParameters) : ListenableWorker(ct
|
|||||||
* Returns `true` if the app is ignoring battery optimizations
|
* Returns `true` if the app is ignoring battery optimizations
|
||||||
*/
|
*/
|
||||||
fun isIgnoringBatteryOptimizations(ctx: Context): Boolean {
|
fun isIgnoringBatteryOptimizations(ctx: Context): Boolean {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
val powerManager = ctx.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
val pwrm = ctx.getSystemService(Context.POWER_SERVICE) as PowerManager
|
return powerManager.isIgnoringBatteryOptimizations(ctx.packageName)
|
||||||
val name = ctx.packageName
|
|
||||||
return pwrm.isIgnoringBatteryOptimizations(name)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildWorkRequest(requireWifi: Boolean = false,
|
private fun buildWorkRequest(
|
||||||
|
requireWifi: Boolean = false,
|
||||||
requireCharging: Boolean = false,
|
requireCharging: Boolean = false,
|
||||||
delayMilliseconds: Long = 0L): OneTimeWorkRequest {
|
delayMilliseconds: Long = 0L
|
||||||
|
): OneTimeWorkRequest {
|
||||||
val constraints = Constraints.Builder()
|
val constraints = Constraints.Builder()
|
||||||
.setRequiredNetworkType(if (requireWifi) NetworkType.UNMETERED else NetworkType.CONNECTED)
|
.setRequiredNetworkType(if (requireWifi) NetworkType.UNMETERED else NetworkType.CONNECTED)
|
||||||
.setRequiresBatteryNotLow(true)
|
.setRequiresBatteryNotLow(true)
|
||||||
|
@ -26,7 +26,7 @@ class ContentObserverWorker(ctx: Context, params: WorkerParameters) : Worker(ctx
|
|||||||
if (!isEnabled(applicationContext)) {
|
if (!isEnabled(applicationContext)) {
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
if (getTriggeredContentUris().size > 0) {
|
if (triggeredContentUris.size > 0) {
|
||||||
startBackupWorker(applicationContext, delayMilliseconds = 0)
|
startBackupWorker(applicationContext, delayMilliseconds = 0)
|
||||||
}
|
}
|
||||||
enqueueObserverWorker(applicationContext, ExistingWorkPolicy.REPLACE)
|
enqueueObserverWorker(applicationContext, ExistingWorkPolicy.REPLACE)
|
||||||
@ -35,10 +35,10 @@ class ContentObserverWorker(ctx: Context, params: WorkerParameters) : Worker(ctx
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SHARED_PREF_SERVICE_ENABLED = "serviceEnabled"
|
const val SHARED_PREF_SERVICE_ENABLED = "serviceEnabled"
|
||||||
const val SHARED_PREF_REQUIRE_WIFI = "requireWifi"
|
private const val SHARED_PREF_REQUIRE_WIFI = "requireWifi"
|
||||||
const val SHARED_PREF_REQUIRE_CHARGING = "requireCharging"
|
private const val SHARED_PREF_REQUIRE_CHARGING = "requireCharging"
|
||||||
const val SHARED_PREF_TRIGGER_UPDATE_DELAY = "triggerUpdateDelay"
|
private const val SHARED_PREF_TRIGGER_UPDATE_DELAY = "triggerUpdateDelay"
|
||||||
const val SHARED_PREF_TRIGGER_MAX_DELAY = "triggerMaxDelay"
|
private const val SHARED_PREF_TRIGGER_MAX_DELAY = "triggerMaxDelay"
|
||||||
|
|
||||||
private const val TASK_NAME_OBSERVER = "immich/ContentObserver"
|
private const val TASK_NAME_OBSERVER = "immich/ContentObserver"
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ class ContentObserverWorker(ctx: Context, params: WorkerParameters) : Worker(ctx
|
|||||||
WorkManager
|
WorkManager
|
||||||
.getInstance(context)
|
.getInstance(context)
|
||||||
.enqueueUniqueWork(TASK_NAME_OBSERVER, ExistingWorkPolicy.REPLACE, work)
|
.enqueueUniqueWork(TASK_NAME_OBSERVER, ExistingWorkPolicy.REPLACE, work)
|
||||||
.getResult()
|
.result
|
||||||
.get()
|
.get()
|
||||||
Log.d(TAG, "workManagerAppClearedWorkaround")
|
Log.d(TAG, "workManagerAppClearedWorkaround")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user