revert redundant changes

This commit is contained in:
Peter Ombodi 2025-09-19 09:14:08 +03:00
parent 113470c87a
commit 9964ad50c2
4 changed files with 46 additions and 86 deletions

View file

@ -24,7 +24,6 @@ import java.security.MessageDigest
import java.io.FileInputStream import java.io.FileInputStream
import kotlinx.coroutines.* import kotlinx.coroutines.*
import androidx.core.net.toUri import androidx.core.net.toUri
import java.io.InputStream
/** /**
* Android plugin for Dart `BackgroundService` and file trash operations * Android plugin for Dart `BackgroundService` and file trash operations
@ -156,11 +155,10 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
"restoreFromTrash" -> { "restoreFromTrash" -> {
val fileName = call.argument<String>("fileName") val fileName = call.argument<String>("fileName")
val type = call.argument<Int>("type") val type = call.argument<Int>("type")
val checksum = call.argument<String>("checksum")
val mediaId = call.argument<String>("mediaId") val mediaId = call.argument<String>("mediaId")
if (fileName != null && type != null && checksum != null) { if (fileName != null && type != null) {
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) && hasManageMediaPermission()) { if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) && hasManageMediaPermission()) {
restoreFromTrash(fileName, type, checksum, result) restoreFromTrash(fileName, type, result)
} else { } else {
result.error("PERMISSION_DENIED", "Media permission required", null) result.error("PERMISSION_DENIED", "Media permission required", null)
} }
@ -222,14 +220,14 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
} }
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
private fun restoreFromTrash(name: String, type: Int, checksum: String, result: Result) { private fun restoreFromTrash(name: String, type: Int, result: Result) {
val uri = getTrashedFileUri(name, type, checksum) val uri = getTrashedFileUri(name, type)
if (uri == null) { if (uri == null) {
Log.e(TAG, "TrashError, Asset Uri cannot be found obtained") Log.e("TrashError", "Asset Uri cannot be found obtained")
result.error("TrashError", "Asset Uri cannot be found obtained", null) result.error("TrashError", "Asset Uri cannot be found obtained", null)
return return
} }
Log.i(TAG, "trying to restore from trash FILE_URI - $uri") Log.e("FILE_URI", uri.toString())
uri.let { toggleTrash(listOf(it), false, result) } uri.let { toggleTrash(listOf(it), false, result) }
} }
@ -265,6 +263,7 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
result.error("TrashError", "Activity or ContentResolver not available", null) result.error("TrashError", "Activity or ContentResolver not available", null)
return return
} }
try { try {
val pendingIntent = MediaStore.createTrashRequest(contentResolver, contentUris, isTrashed) val pendingIntent = MediaStore.createTrashRequest(contentResolver, contentUris, isTrashed)
pendingResult = result // Store for onActivityResult pendingResult = result // Store for onActivityResult
@ -274,62 +273,39 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
null, 0, 0, 0 null, 0, 0, 0
) )
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "TrashError, Error creating or starting trash request", e) Log.e("TrashError", "Error creating or starting trash request", e)
result.error("TrashError", "Error creating or starting trash request", null) result.error("TrashError", "Error creating or starting trash request", null)
} }
} }
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
private fun getTrashedFileUri(fileName: String, type: Int, checksum: String): Uri? { private fun getTrashedFileUri(fileName: String, type: Int): Uri? {
val contentResolver = context?.contentResolver ?: return null val contentResolver = context?.contentResolver ?: return null
val queryUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val queryUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
val projection = arrayOf( val projection = arrayOf(MediaStore.Files.FileColumns._ID)
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.DISPLAY_NAME
)
val dotIndex = fileName.lastIndexOf('.')
val baseName = if (dotIndex != -1) fileName.substring(0, dotIndex) else fileName
val extension = if (dotIndex != -1) fileName.substring(dotIndex) else ""
val nameLike = "%${baseName}%${extension}"
val queryArgs = Bundle().apply { val queryArgs = Bundle().apply {
putString(ContentResolver.QUERY_ARG_SQL_SELECTION, "${MediaStore.Files.FileColumns.DISPLAY_NAME} LIKE ?") putString(
putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, arrayOf(nameLike)) ContentResolver.QUERY_ARG_SQL_SELECTION,
"${MediaStore.Files.FileColumns.DISPLAY_NAME} = ?"
)
putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, arrayOf(fileName))
putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY) putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY)
} }
val expectedBytes = try {
android.util.Base64.decode(checksum, android.util.Base64.DEFAULT)
} catch (e: Exception) {
Log.e(TAG, "getTrashedFileUri, invalid Base64 checksum: $checksum, Exception: $e")
return null
}
contentResolver.query(queryUri, projection, queryArgs, null)?.use { cursor -> contentResolver.query(queryUri, projection, queryArgs, null)?.use { cursor ->
val idxId = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID) if (cursor.moveToFirst()) {
val idxName = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME) val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID))
// same order as AssetType from dart
while (cursor.moveToNext()) { val contentUri = when (type) {
val id = cursor.getLong(idxId) 1 -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val dn = cursor.getString(idxName) 2 -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
3 -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val candidateUri = ContentUris.withAppendedId(queryUri, id) else -> queryUri
}
val sha1Bytes = try {
contentResolver.openInputStream(candidateUri)?.use { ins -> sha1OfStream(ins) }
} catch (e: Exception) {
Log.e(TAG, "getTrashedFileUri, hash failed for $dn: ${e.message}")
null
} ?: continue
if (sha1Bytes.contentEquals(expectedBytes)) {
val contentUri = contentUriForType(type)
return ContentUris.withAppendedId(contentUri, id) return ContentUris.withAppendedId(contentUri, id)
} }
} }
}
Log.w(TAG, "getTrashedFileUri, not found by checksum, nameLike=$nameLike, checksum: $checksum")
return null return null
} }
@ -396,18 +372,6 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
toggleTrash(uris, false, result) toggleTrash(uris, false, result)
} }
private fun sha1OfStream(ins: InputStream): ByteArray {
val buf = ByteArray(BUFFER_SIZE)
val md = MessageDigest.getInstance("SHA-1")
var len: Int
while (true) {
len = ins.read(buf)
if (len <= 0) break
md.update(buf, 0, len)
}
return md.digest()
}
@RequiresApi(Build.VERSION_CODES.Q) @RequiresApi(Build.VERSION_CODES.Q)
private fun contentUriForType(type: Int): Uri = private fun contentUriForType(type: Int): Uri =
when (type) { when (type) {

View file

@ -14,8 +14,8 @@ class LocalFilesManagerRepository {
return await _service.moveToTrash(mediaUrls); return await _service.moveToTrash(mediaUrls);
} }
Future<bool> restoreFromTrash(String fileName, int type, String checksum) async { Future<bool> restoreFromTrash(String fileName, int type) async {
return await _service.restoreFromTrash(fileName, type, checksum); return await _service.restoreFromTrash(fileName, type);
} }
Future<bool> restoreFromTrashById(String mediaId, int type) async { Future<bool> restoreFromTrashById(String mediaId, int type) async {

View file

@ -18,13 +18,9 @@ class LocalFilesManagerService {
} }
} }
Future<bool> restoreFromTrash(String fileName, int type, String checksum) async { Future<bool> restoreFromTrash(String fileName, int type) async {
try { try {
return await _channel.invokeMethod('restoreFromTrash', { return await _channel.invokeMethod('restoreFromTrash', {'fileName': fileName, 'type': type});
'fileName': fileName,
'type': type,
'checksum': checksum,
});
} catch (e, s) { } catch (e, s) {
_logger.warning('Error restore file from trash', e, s); _logger.warning('Error restore file from trash', e, s);
return false; return false;

View file

@ -691,7 +691,7 @@ class SyncService {
} }
trashMediaUrls.add(mediaUrl); trashMediaUrls.add(mediaUrl);
} else { } else {
await _localFilesManager.restoreFromTrash(asset.fileName, asset.type.index, asset.checksum); await _localFilesManager.restoreFromTrash(asset.fileName, asset.type.index);
} }
} }