`MediaStore.MediaColumns.DATA` is deprecated, what column should I use as an alternative - java

I want to load all the pictures from the media provider to my app by using MediaStore API, but this column MediaStore.MediaColumns.DATA is deprecated. So, what can I use as an alternative?
I want to update the following code to get rid of the deprecated MediaStore.MediaColumns.DATA column:
fun ContentResolver.loadImagesPaths(): List<String> {
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val images = mutableListOf<String>()
val projection = arrayOf(MediaStore.MediaColumns.DATA)
query(uri, projection, null, null, null)?.use { cursor ->
val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
while (cursor.moveToNext()) {
images += cursor.getString(dataColumn)
}
}
return images
}
Edit:
Updated code:
fun ContentResolver.loadImagesUris(): List<Uri> {
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val images = mutableListOf<Uri>()
val projection = arrayOf(MediaStore.Images.Media._ID)
query(uri, projection, null, null, null)?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
images += ContentUris.withAppendedId(uri, cursor.getLong(idColumn))
}
}
return images
}
Check out this link for further details on how to access media files from shared storage: https://developer.android.com/training/data-storage/shared/media

I was able to replace MediaStore.MediaColumns.Data with its own file ID (incredibly, files have IDs) and correctly constructing its URI, like this:
fun getAllShownImagesPath(activity: Activity): MutableList<Uri> {
val uriExternal: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor?
val columnIndexID: Int
val listOfAllImages: MutableList<Uri> = mutableListOf()
val projection = arrayOf(MediaStore.Images.Media._ID)
var imageId: Long
cursor = activity.contentResolver.query(uriExternal, projection, null, null, null)
if (cursor != null) {
columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
imageId = cursor.getLong(columnIndexID)
val uriImage = Uri.withAppendedPath(uriExternal, "" + imageId)
listOfAllImages.add(uriImage)
}
cursor.close()
}
return listOfAllImages
}
and then with Uri you build it in your Views!

I managed to come up with the following solution, its kind of an addition to the previous answer
but there I still couldn't load images with the obtained Uri.
Documentation suggested to use openFileDescriptor() which I did and then decoded images' bitmaps from it:
override fun loadImagesFromStorage(): List<AdapterImage> {
val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor?
val columnIndexId: Int
val listOfAllImages = mutableListOf<AdapterImage>()
val projection = arrayOf(MediaStore.Images.Media._ID)
cursor = context.contentResolver
.query( uri, projection, null, null, null)
if ( cursor != null ){
columnIndexId = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()){
val contentUri = ContentUris.withAppendedId(uri, cursor.getLong(columnIndexId))
//here I open FileDescriptor and then decode it into Bitmap
var image: Bitmap
context.contentResolver.openFileDescriptor(contentUri, "r").use { pfd ->
if( pfd != null ){
image = BitmapFactory.decodeFileDescriptor(pfd.fileDescriptor)
listOfAllImages.add(AdapterImage(image))
}
}
}
cursor.close()
}
return listOfAllImages
}
P.S. My method will return a list of AdapterImage objects that I use later in app but you can put anything you need there at this point

I finally solved the problem by creating this class
class FileHelper {
val mediaType = "multipart/form-data".toMediaTypeOrNull()
fun getPartBodyFromUri(context: Context, uri: Uri): MultipartBody.Part {
val realPath = getPathFromURI(context, uri)
val fileImage = createFile(realPath)
val requestBody = createRequestBody(fileImage)
return createPart(fileImage, requestBody)
}
private fun createFile(realPath: String): File {
return File(realPath)
}
private fun createRequestBody(file: File): RequestBody {
return file.asRequestBody(mediaType)
}
private fun createPart(file: File, requestBody: RequestBody): MultipartBody.Part {
return MultipartBody.Part.createFormData("imageFile", file.name, requestBody)
}
private fun getPathFromURI(context: Context, uri: Uri): String {
var realPath = String()
uri.path?.let { path ->
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (path.contains("/document/image:")) { // files selected from "Documents"
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else { // files selected from all other sources, especially on Samsung devices
databaseUri = uri
selection = null
selectionArgs = null
}
try {
val column = "_data"
val projection = arrayOf(column)
val cursor = context.contentResolver.query(
databaseUri,
projection,
selection,
selectionArgs,
null
)
cursor?.let {
if (it.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)
}
cursor.close()
}
} catch (e: Exception) {
println(e)
}
}
return realPath
}
}
Media.DATA it's deprecate and "MediaStore.Images.Media._ID" to get the correct column, not working so I create column I need
val column = "_data"
val projection = arrayOf(column)
then I use getColumnIndexOrThrow() method to get correct index
val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)

In Java
FileInputStream input = null;
FileOutputStream output = null;
try {
String filePath = new File(getCacheDir(), "tmp").getAbsolutePath();
android.os.ParcelFileDescriptor pfd = getContentResolver ().openFileDescriptor(
sharedFileUri, "r");
if (pfd != null) {
FileDescriptor fd = pfd . getFileDescriptor ();
input = new FileInputStream (fd);
output = new FileOutputStream (filePath);
int read;
byte[] bytes = new byte[4096];
while ((read = input.read(bytes)) != -1) {
output.write(bytes, 0, read);
}
File sharedFile = new File(filePath);
String finalPath = sharedFile.getPath();
}
}catch(Exception ex) {
} finally {
try {
input.close();
output.close();
} catch (Exception ignored) {
}
}

Loading images from internal store.Reading all folders which has images and videos using MediaStore class.
And returning result as ArrayList.
private fun getAllShownImagesPath(activity: Activity): ArrayList<Albums> {
val uri: Uri
val cursor: Cursor
var cursorBucket: Cursor
val column_index_data: Int
val column_index_folder_name: Int
val listOfAllImages = ArrayList<String>()
var absolutePathOfImage: String? = null
var albumsList = ArrayList<Albums>()
var album: Albums? = null
val BUCKET_GROUP_BY = "1) GROUP BY 1,(2"
val BUCKET_ORDER_BY = "MAX(datetaken) DESC"
uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.ImageColumns.BUCKET_ID,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.DATA)
cursor = activity.contentResolver.query(uri, projection, BUCKET_GROUP_BY, null, BUCKET_ORDER_BY)
if (cursor != null) {
column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
column_index_folder_name = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
while (cursor.moveToNext()) {
absolutePathOfImage = cursor.getString(column_index_data)
Log.d("title_apps", "bucket name:" + cursor.getString(column_index_data))
val selectionArgs = arrayOf("%" + cursor.getString(column_index_folder_name) + "%")
val selection = MediaStore.Images.Media.DATA + " like ? "
val projectionOnlyBucket = arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
cursorBucket = activity.contentResolver.query(uri, projectionOnlyBucket, selection, selectionArgs, null)
Log.d("title_apps", "bucket size:" + cursorBucket.count)
if (absolutePathOfImage != "" && absolutePathOfImage != null) {
listOfAllImages.add(absolutePathOfImage)
albumsList.add(Albums(cursor.getString(column_index_folder_name), absolutePathOfImage, cursorBucket.count, false))
}
}
}
return getListOfVideoFolders(albumsList)
}
// This function is resposible to read all videos from all folders.
private fun getListOfVideoFolders(albumsList: ArrayList<Albums>): ArrayList<Albums> {
var cursor: Cursor
var cursorBucket: Cursor
var uri: Uri
val BUCKET_GROUP_BY = "1) GROUP BY 1,(2"
val BUCKET_ORDER_BY = "MAX(datetaken) DESC"
val column_index_album_name: Int
val column_index_album_video: Int
uri = android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI
val projection1 = arrayOf(MediaStore.Video.VideoColumns.BUCKET_ID,
MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME,
MediaStore.Video.VideoColumns.DATE_TAKEN,
MediaStore.Video.VideoColumns.DATA)
cursor = this.contentResolver.query(uri, projection1, BUCKET_GROUP_BY, null, BUCKET_ORDER_BY)
if (cursor != null) {
column_index_album_name = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME)
column_index_album_video = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)
while (cursor.moveToNext()) {
Log.d("title_apps", "bucket video:" + cursor.getString(column_index_album_name))
Log.d("title_apps", "bucket video:" + cursor.getString(column_index_album_video))
val selectionArgs = arrayOf("%" + cursor.getString(column_index_album_name) + "%")
val selection = MediaStore.Video.Media.DATA + " like ? "
val projectionOnlyBucket = arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Video.Media.BUCKET_DISPLAY_NAME)
cursorBucket = this.contentResolver.query(uri, projectionOnlyBucket, selection, selectionArgs, null)
Log.d("title_apps", "bucket size:" + cursorBucket.count)
albumsList.add(Albums(cursor.getString(column_index_album_name), cursor.getString(column_index_album_video), cursorBucket.count, true))
}
}
return albumsList
}

you can use "IMediaColumns" instead of "MediaColumns".

Related

How to solve 'Cannot retrieve length of file, path (OS Error: No such file or directory, errno = 2) ' in flutter

I am building a simple music player app in which I want to fetch all songs available on the users device. I am doing this with my custom method in java
private static List<Map<String, String>> getAllSongs(Context context) {
List<Map<String, String>> songs = new ArrayList<>();
// Set up query to get all audio files
String[] projection = new String[] {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ALBUM_ID
};
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
// Execute query
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
sortOrder
);
// Extract metadata from query result
if (cursor != null && cursor.moveToFirst()) {
int idColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
int titleColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int artistColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
int albumColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
int durationColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
int pathColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
int albumIdColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
do {
Map<String, String> song = new HashMap<>();
song.put("id", cursor.getString(idColumnIndex));
song.put("title", cursor.getString(titleColumnIndex));
song.put("artist", cursor.getString(artistColumnIndex));
song.put("album", cursor.getString(albumColumnIndex));
song.put("duration", cursor.getString(durationColumnIndex));
song.put("path", cursor.getString(pathColumnIndex));
long albumId = cursor.getLong(albumIdColumnIndex);
Uri albumArtUri = Uri.withAppendedPath(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, Long.toString(albumId));
song.put("albumArt", albumArtUri.toString());
songs.add(song);
} while (cursor.moveToNext());
cursor.close();
}
return songs;
}
This is then handled in flutter by ->
class Song {
String id;
String title;
String artist;
String album;
String path;
String albumArt;
Song(
{required this.id,
required this.title,
required this.artist,
required this.album,
required this.path,
required this.albumArt});
}
class MusicService {
static const MethodChannel _channel = const MethodChannel('com.mybea.ah');
static Future<List<Song>> getAllSongs() async {
List<Song> songs = [];
try {
final List<dynamic> result = await _channel.invokeMethod('getAllSongs');
if (result.isNotEmpty) {
for (int i = 0; i < result.length; i++) {
songs.add(Song(
id: result[i]['id'],
title: result[i]['title'],
artist: result[i]['artist'],
album: result[i]['album'],
path: result[i]['path'],
albumArt: result[i]['albumArt'],
));
}
}
} on PlatformException catch (e) {
print("Failed to get all songs: '${e.message}'.");
}
return songs;
}
}
When I fetch the songs from the method all is fetched properly but when I try to display the artwork I get the following error->
════════ Exception caught by image resource service
════════════════════════════ Cannot retrieve length of file, path =
'content://media/external/audio/albums/89' (OS Error: No such file or
directory, errno = 2)
This is the code where I try to use the method ->
Future<void> _loadSongs() async {
if (await Permission.storage.request().isGranted) {
List<Song> songs = await MusicService.getAllSongs();
setState(() {
_songs = songs;
} else {
return;
}
}
_songs.length == 0
? Center(
child: Text("No Songs Found"),
)
: ListView.builder(
itemCount: _songs.length,
itemBuilder: (context, index) {
Song song = _songs[index];
return ListTile(
onTap: () {
debugPrint(song.path);
},
leading: CircleAvatar(
backgroundImage: FileImage(File(song.albumArt)),
),
title: Text(song.title),
subtitle: Text(song.artist),
trailing: Icon(Icons.play_arrow),
);
},
),
I tried displaying the image by Image.file() and Image.network() but nothing seemed to work and gave the same error.
Please Help

Setting Alarm sound programmatically doesn't work but Ringtone and Notification does? RingtoneManager

I want the user the be able to choose between setting a sound as Alarm, Notification and Ringtone.
Debugging device is Samsung Galaxy S10+.
Not sure why it's not working and also not sure how it is suppose to work if every Alarm can have a different sound, what should change ?
Setting it as Ringtone and Notification works totally fine, just when I choose RingtoneManager.TYPE_ALARM nothing changes
private fun changeSystemAudio(context: Context, type: Int, file: File) {
val values = ContentValues()
values.put(MediaStore.MediaColumns.DATA, file.absolutePath)
values.put(MediaStore.MediaColumns.TITLE, file.name)
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3")
values.put(MediaStore.Audio.Media.ARTIST, false)
values.put(MediaStore.Audio.Media.IS_RINGTONE, true)
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true)
values.put(MediaStore.Audio.Media.IS_ALARM, true)
values.put(MediaStore.Audio.Media.IS_MUSIC, false)
values.put(MediaStore.Audio.Media.IS_PODCAST, false)
val baseUri = MediaStore.Audio.Media.getContentUriForPath(file.absolutePath)
var toneUri: Uri? = baseUri?.let {
getUriForExistingTone(
context,
it,
file.absolutePath
)
}
if (toneUri == null) {
toneUri = context.contentResolver.insert(baseUri!!, values)
}
RingtoneManager.setActualDefaultRingtoneUri(context, type, toneUri)
}
#SuppressLint("Range")
private fun getUriForExistingTone(context: Context, uri: Uri, filePath: String): Uri? {
var cursor: Cursor? = null
try {
cursor = context.contentResolver
.query(
uri, arrayOf(MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DATA),
MediaStore.MediaColumns.DATA + " = ?", arrayOf(filePath),
null, null
)
if (cursor != null && cursor.count != 0) {
cursor.moveToFirst()
val mediaPos = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID))
return Uri.parse("$uri/$mediaPos")
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}
return null
}
Call:
changeSystemAudio(context, RingtoneManager.TYPE_ALARM, file)

How to fetch all pdf file from all directories in my Android app

I want to know how to fetch all PDF files from internal storage. Files can be in any directory, like some in DCIM folders or some in Downloads folder, and so on and so forth.
Note: I am using Android Studio (language: Java).
i have search almost all the ans but it was not working in Android 11. so i have a short solution for picking up all file for example image, video, pdf, doc, audio etc. there was a github library which was recently created
Click [here] https://github.com/HBiSoft/PickiT
and if you want to do all this without dependency
Code Below
do it in orderwise
var mimeTypes = arrayOf(
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // .doc & .docx
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation", // .ppt & .pptx
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // .xls & .xlsx
"application/pdf"
)
findViewById<Button>(R.id.btnclick).setOnClickListener {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
// mimeTypes = mimeTypes
}
startActivityForResult(intent, 100)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.e(">>>>>>", "check")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getFile(this,intentToDocumentFiles(data)[0])
}
}
private fun intentToDocumentFiles(intent: Intent?): List<DocumentFile> {
val uris = intent?.clipData?.run {
val list = mutableListOf<Uri>()
for (i in 0 until itemCount) {
list.add(getItemAt(i).uri)
}
list.takeIf { it.isNotEmpty() }
} ?: listOf(intent?.data ?: return emptyList())
return uris.mapNotNull { uri ->
if (uri.isDownloadsDocument && Build.VERSION.SDK_INT < 28 && uri.path?.startsWith("/document/raw:") == true) {
val fullPath = uri.path.orEmpty().substringAfterLast("/document/raw:")
DocumentFile.fromFile(File(fullPath))
} else {
fromSingleUri(uri)
}
}.filter { it.isFile }
}
#RequiresApi(Build.VERSION_CODES.R)
fun getFile(context: Context, document: DocumentFile): File? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return null
}
try {
val volumeList: List<StorageVolume> = context
.getSystemService(StorageManager::class.java)
.getStorageVolumes()
if (volumeList == null || volumeList.isEmpty()) {
return null
}
// There must be a better way to get the document segment
val documentId = DocumentsContract.getDocumentId(document.uri)
val documentSegment = documentId.substring(documentId.lastIndexOf(':') + 1)
for (volume in volumeList) {
val volumePath: String
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
val class_StorageVolume = Class.forName("android.os.storage.StorageVolume")
val method_getPath: Method = class_StorageVolume.getDeclaredMethod("getPath")
volumePath=method_getPath.invoke(volume).toString()
} else {
// API 30
volumePath=volume.directory!!.path
}
val storageFile = File(volumePath + File.separator + documentSegment)
// Should improve with other checks, because there is the
// remote possibility that a copy could exist in a different
// volume (SD-card) under a matching path structure and even
// same file name, (maybe a user's backup in the SD-card).
// Checking for the volume Uuid could be an option but
// as per the documentation the Uuid can be empty.
val isTarget = (storageFile.exists()
&& storageFile.lastModified() == document.lastModified()
&& storageFile.length() == document.length())
if (isTarget) {
Log.e(">>>>>>>",storageFile.absolutePath)
return storageFile
}
}
} catch (e: Exception) {
e.printStackTrace()
}
Log.e(">>>>>>>","null")
return null
}
You can use MediaStore to fetch all PDF Files ,this is an example how to get all your PDF files :
protected ArrayList<String> getPdfList() {
ArrayList<String> pdfList = new ArrayList<>();
Uri collection;
final String[] projection = new String[]{
MediaStore.Files.FileColumns.DISPLAY_NAME,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.MIME_TYPE,
};
final String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";
final String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ?";
final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
final String[] selectionArgs = new String[]{mimeType};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
}else{
collection = MediaStore.Files.getContentUri("external");
}
try (Cursor cursor = getContentResolver().query(collection, projection, selection, selectionArgs, sortOrder)) {
assert cursor != null;
if (cursor.moveToFirst()) {
int columnData = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
int columnName = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
do {
pdfList.add((cursor.getString(columnData)));
Log.d(TAG, "getPdf: " + cursor.getString(columnData));
//you can get your pdf files
} while (cursor.moveToNext());
}
}
return pdfList;
}
This is improvised answer of #Shay Kin.
As we know in latest android versions we have many restrictions to access files in external storage.
MediaStore api and Storage Access Framework apis provides access to shared files. This is explained clearly in this video.
Coming to the answer, in Shay Kin's answer we can able to fetch all pdf files which are there in the shared files but ignores downloads.
Permissions required
READ_EXTERNAL_STORAGE
if api is Q plus you also need MANAGE_EXTERNAL_STORAGE
please find the below code to fetch all pdf files.
protected List<String> getPdfList() {
List<String> pdfList = new ArrayList<>();
final String[] projection = new String[]{
MediaStore.Files.FileColumns.DISPLAY_NAME,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.MIME_TYPE,
};
final String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";
final String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ?";
final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
final String[] selectionArgs = new String[]{mimeType};
Uri collection = MediaStore.Files.getContentUri("external");
pdfList.addAll(getPdfList(collection, projection, selection, selectionArgs, sortOrder));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
collection = MediaStore.Downloads.getContentUri("external");
pdfList.addAll(getPdfList(collection,projection, selection, selectionArgs, sortOrder));
}
return pdfList;
}
private List<String> getPdfList(Uri collection, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
List<String> pdfList = new ArrayList<>();
try (Cursor cursor = getContentResolver().query(collection, projection, selection, selectionArgs, sortOrder)) {
assert cursor != null;
if (cursor.moveToFirst()) {
int columnData = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
do {
pdfList.add((cursor.getString(columnData)));
Log.d(TAG, "getPdf: " + cursor.getString(columnData));
//you can get your pdf files
} while (cursor.moveToNext());
}
}
return pdfList;
}
Hope this works.

Having issue with file path

I am successfully able to select file programmatically. But, when I am getting uri from that file
content://com.android.providers.downloads.documents/document/3356
content://com.android.providers.downloads.documents/document/3331
Unfortunately, wherever the file is my uri is always locating at downloads.documents
I think it doesn't fact. Cause, everyone get the uri by data.getData(). So, I think the uri is correct.
Last year, I was working with Audio, Video, File and Image uploading to server. I was trying that source code to get path.
String mediaPath, mediaPath1;
String[] mediaColumns = {MediaStore.Video.Media._ID};
// Get the file from data
String path = data.getStringExtra(mediaPath);
File file = new File(path);
Uri selectedFile = Uri.fromFile(new File(file.getAbsolutePath()));
String[] filePathColumn = {MediaStore.Files.FileColumns.MEDIA_TYPE};
Cursor cursor = getContentResolver().query(selectedFile, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath = cursor.getString(columnIndex);
txt.setText(path);
// Set the Image in ImageView for Previewing the Media
cursor.close();
Unfortunately,That is returning null pointerexception. After researching little bit, I found another source code(PathUtils)
public class PathUtils {
public static String getPath(final Context context, final Uri uri) {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {// ExternalStorageProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String storageDefinition;
if("primary".equalsIgnoreCase(type)){
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else {
if(Environment.isExternalStorageRemovable()){
storageDefinition = "EXTERNAL_STORAGE";
} else{
storageDefinition = "SECONDARY_STORAGE";
}
return System.getenv(storageDefinition) + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {// DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {// MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general)
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {// File
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}
I am not getting any error. But, Path is always locating at Downloads file. I don't know why. After looking at uri I noticed my uri is always returning downloads.documents. I am not sure is it the issue.
There is lot of question similar to this question in stackoverflow. To tell everyone none worked for me. So, I will request to not flag it.
PATH: /storage/emulated/0/Download/The Road to Reality ( PDFDrive ).pdf
PATH: /storage/emulated/0/Download/The order of time ( PDFDrive ).pdf
PATH: /storage/emulated/0/Download/pdf_495.pdf
First pdf file is in documents file. Second pdf file is in Download third pdf file is in /storage/emulated/0/
I am parsing pdf texts. Here is my code
try {
String parsedText="";
StringBuilder builder = new StringBuilder();
//Here you can see I need path to load the pdf file
PdfReader reader = new PdfReader(PathUtils.getPathFromUri(getApplicationContext(),PathHolder));
int n = reader.getNumberOfPages();
for (int i = 10; i <n ; i++) {
parsedText = parsedText+ PdfTextExtractor.getTextFromPage(reader, i).trim()+"\n";
Log.d("for_loop", String.valueOf(i));
Log.d("PARSED_TEXT",parsedText+" ");
}
builder.append(parsedText);
reader.close();
runOnUiThread(() -> {
txt.setText(builder.toString());
});
// System.out.println("TEXT FROM PDF : "+builder.toString());
} catch (Exception e) {
System.out.println(e);
}
As you can see I need path to load the pdf file. But, I have already told you I am having issue with path. So, if I wanna do something with uri than how can i do that cause, path required.
I tried another way to get the path also.
Uri PathHolder = data.getData();
Cursor cursor = null;
try {
cursor = this.getContentResolver().query(PathHolder, new String[]{MediaStore.Files.FileColumns.DATA}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString()+"/" + fileName;
Log.d("PATH",path);
if (!TextUtils.isEmpty(path)) {
}else{
Toast.makeText(this, "null return", Toast.LENGTH_SHORT).show();
}
}
}catch (Exception e){
e.printStackTrace();
Log.d("EXCEPTION_ERROR",e.toString());
} finally {
if (cursor != null)
cursor.close();
}
Unfortunately, It's not working also.
Like we do for audio, images or, videos.
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Audio.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath = cursor.getString(columnIndex);
str1.setText(mediaPath);
// Set the Image in ImageView for Previewing the Media
imgView.setImageBitmap(BitmapFactory.decodeFile(mediaPath));
cursor.close();
Edited :
Uri uri = data.getData();
try{
InputStream in = getContentResolver().openInputStream(uri);
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
total.append(line).append('\n');
}
String content = total.toString();
Log.d("CONTENT",content);
}catch (Exception e){
e.printStackTrace();
}
The problem I am facing here is.
As you can see the catch is returning no such file or directory found. I am not sure what I am doing wrong here. Cause, I took the source code from somewhere else and it is first time I am working with InputStream. And, I think the problem is on I am unable to get the file by uri.
Catch exception is returning
no such file or directory
Edited :
Uri uri = data.getData();
File file=new File(uri.toString());
InputStream inputStream = getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=inputStream.read(buf))>0){
out.write(buf,0,len);
}
out.close();
inputStream.close();
Starting from Android 10 using Scoped Storage is required. You cannot get absolute path of the file and work with file APIs with external Storage. MediaStore.Audio.Media.DATA that is used to take absolute path is depracated. But with uri returned you can copy that file using inputStream to your app-specific directory and do what you want with that file. For more information please refer to this article.
For reading pdf as I said you can copy that file to your app-specific directory or use that uri like this sample.
Copying file from uri in kotlin:
val uri: Uri = data?.data ?: return
val ins = context?.contentResolver?.openInputStream(uri)
val file = File(context?.filesDir, "image.jpg")
val fileOutputStream = FileOutputStream(file)
ins?.copyTo(fileOutputStream)
ins?.close()
fileOutputStream.close()
val absolutePath = file.absolutePath
Log.d("AAA", absolutePath)
If you use java there is no copyTo function so use this function then you can use the file in Files directory in app-specific storage
private void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}}
Copied file in app-specific directory
This is log:
D/AAA: /data/user/0/com.example.pickerapp/files/image.jpg

How to get paths of folders that has image or video

I want to create an android gallery app .
How to scan and get paths of folders that includes photos or videos .
I used this code and worked . but when i compare it with Quickpic Gallery in play store , i see the count of folders in my app is less than Quickpic folders
Do you see any problem in this code ?
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = ba.context.getContentResolver().query(uri, null, null,
null, MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME);
if (cursor != null) {
cursor.moveToFirst();
int data = cursor
.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
int displayName = cursor
.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME);
imageFolders = new HashMap<>();
do {
String imageAddress = cursor.getString(data);
String imageName = cursor.getString(displayName);
String folderAddress = imageAddress.substring(0,
imageAddress.lastIndexOf(imageName) - 1);
if (!imageFolders.containsKey(folderAddress)) {
imageFolders.put(folderAddress, imageAddress);
}
} while (cursor.moveToNext());
for (String str : imageFolders.keySet()) {
ba.raiseEventFromDifferentThread(
null,
null,
0,
"result",
true,
new Object[] { String.format("%s", str),
String.format("%s", imageFolders.get(str)) });
}
}
this way you can find all video and image parents.
ArrayList<String> allFolder;
HashMap<String, ArrayList<String>> listImageByFolder;
ArrayList<String> allVideoFolder;
HashMap<String, ArrayList<String>> listVideoByFolder;
find all images folder path
private void getImageFolderList() {
String[] projection = new String[] { MediaStore.Images.Media.DATA,
MediaStore.Images.Media._ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN };
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
final String orderBy = MediaStore.Images.Media.DATE_TAKEN;
Cursor cur = getContentResolver().query(images, projection, // Which
// columns
// to return
null, // Which rows to return (all rows)
null, // Selection arguments (none)
orderBy + " DESC" // Ordering
);
ArrayList<String> imagePath;
if (cur.moveToFirst()) {
String bucket, date;
int bucketColumn = cur.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
int dateColumn = cur.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
do {
bucket = cur.getString(bucketColumn);
date = cur.getString(dateColumn);
if (!allFolder.contains(bucket)) {
allFolder.add(bucket);
}
imagePath = listImageByFolder.get(bucket);
if (imagePath == null) {
imagePath = new ArrayList<String>();
}
imagePath.add(cur.getString(cur
.getColumnIndex(MediaStore.Images.Media.DATA)));
listImageByFolder.put(bucket, imagePath);
} while (cur.moveToNext());
}
}
find all videos folder path
private void getVideoFolderList() {
String[] projection = new String[] { MediaStore.Video.Media.DATA,
MediaStore.Video.Media._ID,
MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
MediaStore.Video.Media.DATE_TAKEN };
Uri images = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
final String orderBy = MediaStore.Video.Media.DATE_TAKEN;
Cursor cur = getContentResolver().query(images, projection, // Which
// columns
// to return
null, // Which rows to return (all rows)
null, // Selection arguments (none)
orderBy + " DESC" // Ordering
);
ArrayList<String> imagePath;
if (cur.moveToFirst()) {
String bucket, date;
int bucketColumn = cur.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME);
int dateColumn = cur.getColumnIndex(MediaStore.Video.Media.DATE_TAKEN);
do {
bucket = cur.getString(bucketColumn);
date = cur.getString(dateColumn);
if (!allVideoFolder.contains(bucket)) {
allVideoFolder.add(bucket);
}
imagePath = listVideoByFolder.get(bucket);
if (imagePath == null) {
imagePath = new ArrayList<String>();
}
imagePath.add(cur.getString(cur
.getColumnIndex(MediaStore.Images.Media.DATA)));
listVideoByFolder.put(bucket, imagePath);
} while (cur.moveToNext());
}
}
i can see you are trying to get the folder names of all folders containing video files the answer given by #prakash ubhadiya is good an works but for the problem that if the are many of such folders with same name the function will keep only one and ignore the rest, below i have modified his fuction to return not only the folder names but also the folder absolute path in case you will want to use this to get all the video files in that specific folder, i have created a class called floderFacer the holds the folder name and the folder adsolute path, done this way no folders with same names will be ignored below is the class
public class folderFacer {
private String path;
private String folderName;
public folderFacer(){
}
public folderFacer(String path, String folderName) {
this.path = path;
this.folderName = folderName;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getFolderName() {
return folderName;
}
public void setFolderName(String folderName) {
this.folderName = folderName;
}
}
now below is the modified fuction that will return the folder names and paths in a folderFacer object all in an ArrayList<folderFacer>
private ArrayList<folderFacer> getVideoPaths(){
ArrayList<folderFacer> videoFolders = new ArrayList<>();
ArrayList<String> videoPaths = new ArrayList<>();
Uri allVideosuri = android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA ,MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.BUCKET_DISPLAY_NAME,MediaStore.Video.Media.BUCKET_ID};
Cursor cursor = getContentResolver().query(allVideosuri, projection, null, null, null);
try {
cursor.moveToFirst();
do{
folderFacer folds = new folderFacer();
String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME));
String folder = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME));
String datapath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
String folderpaths = datapath.replace(name,"");
if (!videoPaths.contains(folderpaths)) {
videoPaths.add(folderpaths);
folds.setPath(folderpaths);
folds.setFolderName(folder);
videoFolders.add(folds);
}
}while(cursor.moveToNext());
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
for(int i = 0;i < videoFolders.size();i++){
Log.d("video folders",videoFolders.get(i).getFolderName()+" and path = "+videoFolders.get(i).getPath());
}
return videoFolders;
}
hope this helps

Categories

Resources