diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DeleteTask.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DeleteTask.java index 4f83f4bd0a..8926e489ea 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DeleteTask.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DeleteTask.java @@ -114,7 +114,7 @@ protected final AsyncTaskResult doInBackground( // delete file from media database if (!file.isSmb() && !file.isSftp()) - MediaConnectionUtils.scanFile( + MediaConnectionUtils.scanFiles( applicationContext, files.toArray(new HybridFile[files.size()])); // delete file entry from encrypted database diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/MoveFilesTask.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/MoveFilesTask.kt index 9d9a3b6566..909a1cc59d 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/MoveFilesTask.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/MoveFilesTask.kt @@ -106,8 +106,8 @@ class MoveFilesTask( for (hybridFileParcelables in files) { sourcesFiles.addAll(hybridFileParcelables) } - MediaConnectionUtils.scanFile(applicationContext, sourcesFiles.toTypedArray()) - MediaConnectionUtils.scanFile(applicationContext, targetFiles.toTypedArray()) + MediaConnectionUtils.scanFiles(applicationContext, sourcesFiles.toTypedArray()) + MediaConnectionUtils.scanFiles(applicationContext, targetFiles.toTypedArray()) } // updating encrypted db entry if any encrypted file was moved diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java b/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java index 398cb8ff64..1f0dc4f05c 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java @@ -468,7 +468,7 @@ void copyRoot(HybridFileParcelable sourceFile, HybridFile targetFile, boolean mo e); failedFOps.add(sourceFile); } - MediaConnectionUtils.scanFile(c, new HybridFile[] {targetFile}); + MediaConnectionUtils.scanFiles(c, new HybridFile[] {targetFile}); } private void copyFiles( diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java b/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java index 37b01b01df..02c45cea90 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java @@ -1581,7 +1581,7 @@ public void restoreFromBin(Context context) { if (!source.renameTo(dest)) { return false; } - MediaConnectionUtils.scanFile(context, new HybridFile[] {this}); + MediaConnectionUtils.scanFiles(context, new HybridFile[] {this}); return true; }); } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java b/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java index 5336fd6bc0..b699283b2d 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java @@ -40,6 +40,7 @@ import android.provider.MediaStore; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; /** @@ -164,6 +165,41 @@ public static OutputStream getOutputStream(Context context, String str) { } } + public static Uri getUriForMusicMediaFrom(@NonNull String path, @NonNull Context context) { + Uri retval = getUriForMusicMediaInternal(path, context); + return retval; + } + + private static Uri getUriForMusicMediaInternal(@NonNull String path, @NonNull Context context) { + String[] projection = {MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DATA}; + + String selection = MediaStore.Audio.Media.DATA + "=?"; + String[] selectionArgs = new String[] {path}; + + try (Cursor cursor = + context + .getContentResolver() + .query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + projection, + selection, + selectionArgs, + null)) { + if (cursor != null && cursor.moveToFirst()) { + int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)); + return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + .buildUpon() + .appendPath(String.valueOf(id)) + .build(); + } else { + return null; + } + } catch (Exception e) { + Log.e(TAG, "Error querying MediaStore", e); + return null; + } + } + /** Returns an OutputStream to write to the file. The file will be truncated immediately. */ private static int getTemporaryAlbumId(final Context context) { final File temporaryTrack; diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java b/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java index 02d46eb5ec..0bd1cad98f 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java @@ -717,7 +717,7 @@ protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); if (newFile != null && oldFile != null) { HybridFile[] hybridFiles = {newFile, oldFile}; - MediaConnectionUtils.scanFile(context, hybridFiles); + MediaConnectionUtils.scanFiles(context, hybridFiles); } } }.executeOnExecutor(executor); diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/files/GenericCopyUtil.java b/app/src/main/java/com/amaze/filemanager/filesystem/files/GenericCopyUtil.java index 75dc8ab34f..680aebb289 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/files/GenericCopyUtil.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/files/GenericCopyUtil.java @@ -269,7 +269,7 @@ private void startCopy( // If target file is copied onto the device and copy was successful, trigger media store // rescan if (mTargetFile != null) { - MediaConnectionUtils.scanFile(mContext, new HybridFile[] {mTargetFile}); + MediaConnectionUtils.scanFiles(mContext, new HybridFile[] {mTargetFile}); } } } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/files/MediaConnectionUtils.kt b/app/src/main/java/com/amaze/filemanager/filesystem/files/MediaConnectionUtils.kt index e51370578c..7764965265 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/files/MediaConnectionUtils.kt +++ b/app/src/main/java/com/amaze/filemanager/filesystem/files/MediaConnectionUtils.kt @@ -36,13 +36,14 @@ object MediaConnectionUtils { * @param hybridFiles files to be scanned */ @JvmStatic - fun scanFile( + fun scanFiles( context: Context, hybridFiles: Array, ) { - val paths = arrayOfNulls(hybridFiles.size) - - for (i in hybridFiles.indices) paths[i] = hybridFiles[i].path + val paths: Array = + hybridFiles.map { + it.path + }.toTypedArray() MediaScannerConnection.scanFile( context, @@ -52,4 +53,31 @@ object MediaConnectionUtils { LOG.info("MediaConnectionUtils#scanFile finished scanning path$path") } } + + /** + * Invokes MediaScannerConnection#scanFile for the given file. + * + * @param context the context + * @param path the file path to be scanned + * @param mimeType the mime type of the file. Optional. + * + */ + @JvmStatic + fun scanFileByFileSystemPathAndMimeType( + context: Context, + path: String, + mimeType: String? = null, + callback: MediaScannerConnection.OnScanCompletedListener? = null, + ) { + MediaScannerConnection.scanFile( + context, + arrayOf(path), + mimeType?.let { + arrayOf(it) + }, + ) { scannedPath: String, uri: Uri? -> + LOG.info("Finished scanning path $scannedPath") + callback?.onScanCompleted(path, uri) + } + } } diff --git a/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivityViewModel.kt b/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivityViewModel.kt index e9c8c83246..c165f88636 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivityViewModel.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivityViewModel.kt @@ -40,7 +40,7 @@ import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.SearchResu import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.searchParametersFromBoolean import com.amaze.filemanager.fileoperations.filesystem.OpenMode import com.amaze.filemanager.filesystem.HybridFile -import com.amaze.filemanager.filesystem.files.MediaConnectionUtils.scanFile +import com.amaze.filemanager.filesystem.files.MediaConnectionUtils.scanFiles import com.amaze.filemanager.ui.fragments.preferencefragments.PreferencesConstants.PREFERENCE_REGEX import com.amaze.filemanager.ui.fragments.preferencefragments.PreferencesConstants.PREFERENCE_REGEX_MATCHES import com.amaze.filemanager.ui.fragments.preferencefragments.PreferencesConstants.PREFERENCE_SHOW_HIDDENFILES @@ -235,7 +235,7 @@ class MainActivityViewModel(val applicationContext: Application) : OpenMode.TRASH_BIN, originalFilePath, ) - scanFile(applicationContext, arrayOf(hybridFile)) + scanFiles(applicationContext, arrayOf(hybridFile)) val intent = Intent(MainActivity.KEY_INTENT_LOAD_LIST) hybridFile.getParent(applicationContext)?.let { intent.putExtra(MainActivity.KEY_INTENT_LOAD_LIST_FILE, it) @@ -291,7 +291,7 @@ class MainActivityViewModel(val applicationContext: Application) : OpenMode.TRASH_BIN, source, ) - scanFile(applicationContext, arrayOf(hybridFile)) + scanFiles(applicationContext, arrayOf(hybridFile)) val intent = Intent(MainActivity.KEY_INTENT_LOAD_LIST) hybridFile.getParent(applicationContext)?.let { intent.putExtra(MainActivity.KEY_INTENT_LOAD_LIST_FILE, it) diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java b/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java index 772abf6739..57cc35f64c 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java @@ -58,6 +58,7 @@ import com.amaze.filemanager.filesystem.FileProperties; import com.amaze.filemanager.filesystem.HybridFile; import com.amaze.filemanager.filesystem.HybridFileParcelable; +import com.amaze.filemanager.filesystem.MediaStoreHack; import com.amaze.filemanager.filesystem.SafRootHolder; import com.amaze.filemanager.filesystem.files.CryptUtil; import com.amaze.filemanager.filesystem.files.EncryptDecryptUtils; @@ -136,6 +137,7 @@ import jcifs.smb.SmbFile; import kotlin.collections.ArraysKt; import kotlin.collections.CollectionsKt; +import kotlin.text.StringsKt; public class MainFragment extends Fragment implements BottomBarButtonPath, @@ -574,10 +576,26 @@ public void returnIntentResults(HybridFileParcelable[] baseFiles) { HybridFileParcelable resultBaseFile = result.getKey(); if (requireMainActivity().mRingtonePickerIntent) { - intent.setDataAndType( - resultUri, - MimeTypes.getMimeType(resultBaseFile.getPath(), resultBaseFile.isDirectory())); - intent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, resultUri); + // Query MediaStore to get the proper content URI for the selected audio file + Uri mediaFileUri = + MediaStoreHack.getUriForMusicMediaFrom(resultBaseFile.getPath(), requireContext()); + if (mediaFileUri != null) { + String filename = resultBaseFile.getName(); + Uri properUri = + mediaFileUri + .buildUpon() + .appendQueryParameter("canonical", "1") + .appendQueryParameter("title", StringsKt.substringBeforeLast(filename, ".", "")) + .build(); + // Set the proper content URI as result + intent.setDataAndType(properUri, "audio/*"); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, properUri); + } else { + Toast.makeText(requireContext(), R.string.error_mediastore_query_uri, Toast.LENGTH_LONG) + .show(); + requireMainActivity().finish(); + return; + } } else { LOG.debug("pickup file"); intent.setDataAndType(resultUri, MimeTypes.getExtension(resultBaseFile.getPath())); @@ -1353,7 +1371,7 @@ public void hide(String path) { LOG.warn("failure when hiding file", e); } } - MediaConnectionUtils.scanFile( + MediaConnectionUtils.scanFiles( requireMainActivity(), new HybridFile[] {new HybridFile(OpenMode.FILE, path)}); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7d3f97ae2a..05a108fefc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -848,5 +848,6 @@ You only need to do this once, until the next time you select a new location for Maximum data (in MBs) trash bin can store Cleanup interval Trigger auto-cleanup interval (hours) + Error querying MediaStore for content URI of select media file. Refresh the MediaStore and try again.