Register photo creation receiver for internal storage for auto upload

This commit is contained in:
Julian Raufelder 2021-02-15 16:49:56 +01:00
parent a42919911d
commit 7dca46864d
No known key found for this signature in database
GPG Key ID: 17EE71F6634E381D

View File

@ -7,12 +7,13 @@ import android.app.job.JobScheduler
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import android.database.Cursor
import android.database.MergeCursor
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.provider.MediaStore
import android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
import android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI
import androidx.annotation.RequiresApi
import org.cryptomator.domain.exception.FatalBackendException
import org.cryptomator.presentation.R
@ -21,72 +22,69 @@ import org.cryptomator.presentation.util.ResourceHelper
import org.cryptomator.util.file.MimeTypeMap_Factory
import org.cryptomator.util.file.MimeTypes
import timber.log.Timber
import java.lang.String.format
import java.util.*
@RequiresApi(api = Build.VERSION_CODES.N)
class PhotoContentJob : JobService() {
private val mHandler = Handler()
private val mWorker: Runnable = Runnable {
private val handler = Handler()
private val worker: Runnable = Runnable {
scheduleJob(applicationContext)
jobFinished(mRunningParams, false)
jobFinished(runningParams, false)
}
private lateinit var mRunningParams: JobParameters
private lateinit var runningParams: JobParameters
override fun onStartJob(params: JobParameters): Boolean {
Timber.tag("PhotoContentJob").i("Job started!")
val fileUtil = FileUtil(baseContext, MimeTypes(MimeTypeMap_Factory.newInstance()))
mRunningParams = params
if (params.triggeredContentAuthorities != null) {
runningParams = params
params.triggeredContentAuthorities?.let {
if (params.triggeredContentUris != null) {
val ids = getIds(params)
if (ids != null && ids.size > 0) {
if (ids != null && ids.isNotEmpty()) {
val selection = buildSelection(ids)
var cursor: Cursor? = null
try {
cursor = contentResolver.query(EXTERNAL_CONTENT_URI, PROJECTION, selection, null, null)
cursor?.let {
while (cursor.moveToNext()) {
val dir = cursor.getString(PROJECTION_DATA)
try {
fileUtil.addImageToAutoUploads(dir)
Timber.tag("PhotoContentJob").i("Added file to UploadList")
Timber.tag("PhotoContentJob").d(format("Added file to UploadList %s", dir))
} catch (e: FatalBackendException) {
Timber.tag("PhotoContentJob").e(e, "Failed to add image to auto upload list")
contentResolver.query(EXTERNAL_CONTENT_URI, PROJECTION, selection, null, null).use { externalCursor ->
contentResolver.query(INTERNAL_CONTENT_URI, PROJECTION, selection, null, null).use { internalCursor ->
MergeCursor(arrayOf(externalCursor, internalCursor)).use { cursor ->
while (cursor.moveToNext()) {
try {
val dir = cursor.getString(PROJECTION_DATA)
fileUtil.addImageToAutoUploads(dir)
Timber.tag("PhotoContentJob").i("Added file to UploadList")
Timber.tag("PhotoContentJob").d(String.format("Added file to UploadList %s", dir))
} catch (e: FatalBackendException) {
Timber.tag("PhotoContentJob").e(e, "Failed to add image to auto upload list")
} catch (e: SecurityException) {
Timber.tag("PhotoContentJob").e(e, "No access to storage")
}
}
}
} ?: Timber.tag("PhotoContentJob").e("Error: no access to media!")
} catch (e: SecurityException) {
Timber.tag("PhotoContentJob").e("Error: no access to media!")
} finally {
cursor?.close()
}
}
} else {
Timber.tag("PhotoContentJob").d("ids are null or 0: %s", ids)
}
} else {
Timber.tag("PhotoContentJob").w("Photos rescan needed!")
return true
}
} else {
Timber.tag("PhotoContentJob").w("No photos content")
}
} ?: Timber.tag("PhotoContentJob").w("No photos content")
mHandler.post(mWorker)
handler.post(worker)
return false
}
private fun getIds(params: JobParameters): ArrayList<String>? {
private fun getIds(params: JobParameters): Set<String>? {
return params.triggeredContentUris
?.map { it.pathSegments }
?.filter { it != null && it.size == EXTERNAL_PATH_SEGMENTS.size + 1 }
?.mapTo(ArrayList()) { it[it.size - 1] }
?.filter { it != null && (it.size == EXTERNAL_CONTENT_URI.pathSegments.size + 1 || it.size == INTERNAL_CONTENT_URI.pathSegments.size + 1) }
?.mapTo(HashSet()) { it[it.size - 1] }
}
private fun buildSelection(ids: ArrayList<String>): String {
private fun buildSelection(ids: Set<String>): String {
val selection = StringBuilder()
ids.indices.forEach { i ->
if (selection.isNotEmpty()) {
@ -94,7 +92,7 @@ class PhotoContentJob : JobService() {
}
selection.append(MediaStore.Images.ImageColumns._ID)
selection.append("='")
selection.append(ids[i])
selection.append(ids.elementAt(i))
selection.append("'")
}
return selection.toString()
@ -102,7 +100,7 @@ class PhotoContentJob : JobService() {
override fun onStopJob(params: JobParameters): Boolean {
Timber.tag("PhotoContentJob").i("onStopJob called, must stop, reschedule later")
mHandler.removeCallbacks(mWorker)
handler.removeCallbacks(worker)
return true
}
@ -114,7 +112,6 @@ class PhotoContentJob : JobService() {
companion object {
private val MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/")
internal val EXTERNAL_PATH_SEGMENTS = EXTERNAL_CONTENT_URI.pathSegments
internal val PROJECTION = arrayOf(MediaStore.Images.ImageColumns._ID, MediaStore.Images.ImageColumns.DATA)
internal const val PROJECTION_DATA = 1
@ -125,6 +122,7 @@ class PhotoContentJob : JobService() {
init {
val builder = JobInfo.Builder(PHOTOS_CONTENT_JOB, ComponentName(ResourceHelper.getString(R.string.app_id), PhotoContentJob::class.java.name))
builder.addTriggerContentUri(JobInfo.TriggerContentUri(EXTERNAL_CONTENT_URI, FLAG_NOTIFY_FOR_DESCENDANTS))
builder.addTriggerContentUri(JobInfo.TriggerContentUri(INTERNAL_CONTENT_URI, FLAG_NOTIFY_FOR_DESCENDANTS))
builder.addTriggerContentUri(JobInfo.TriggerContentUri(MEDIA_URI, FLAG_NOTIFY_FOR_DESCENDANTS))
jobInfo = builder.build()
}