Since the changes related to the authorizations of access to the shared storage, it does not seem any more possible to search all the documents of the type pdf by this approach (with requestLegacyExternalStorage = "false"):
ContentResolver cr = context.getContentResolver();
Uri uri = MediaStore.Files.getContentUri("external");
String[] projection = null;
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_NONE;
String[] selectionArgs = null;
String sortOrder = null;
Cursor allNonMediaFiles = cr.query(uri, projection, selection, selectionArgs, sortOrder);
Check this link : Media data restrictions
The only solution I see is to scan in a recurcive way all the tree of the shared storage with SAF, which seems to me very expensive in resources and ridiculous.
Does anyone have another idea?
The basic idea of scoped storage is exactly to avoid this kind of behavior, you can't know if there are or not some files somewhere in the user phone. You can just ask for permission to access to the storage tree and scan everything as you said. Even in this case the user could select a folder different from the root so your app will be limited to that folder. The idea could be perform a scan and then update your database keeping in sync using a job (job service) scheduled on the modification of tree URI and descendants.
if your project targeted to Sdk level 29 you should add to your AndroidManifest.xml the flag android:requestLegacyExternalStorage="true" under your <application> tag.
public List<String> queryFilesFromDevice(Uri uri, String[] projection, String selection, final Context context) {
final List<String> tempList = new ArrayList<>();
Cursor c = context.getContentResolver().query(uri, projection,
selection,
null,
null);
if (c != null) {
while (c.moveToNext()) {
String path = c.getString(0);
long size = c.getLong(1);
// your code logic should be here
}
c.close();
}
tempList.add(path);
return tempList;
}
you need to call the function like this:
String pdfExt = "_data LIKE '%.pdf'";
Uri ducumentsUri = MediaStore.Files.getContentUri("external");
String[] docsProjection ={MediaStore.Files.FileColumns.DATA,MediaStore.Images.Media.SIZE,MediaStore.Files.FileColumns.MIME_TYPE,};
queryFilesFromDevice(ducumentsUri, docsProjection, pdfExt, this);
Related
I want to fetch file data from specific folder using MediaStore Query but returned cursor result is always null.
I have tried using MediaStore query
File file = new File(Environment.getExternalStorageDirectory() + "/myplayer/");
if (file.isDirectory())
{
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.Media._ID
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.DATA,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.SIZE, MediaStore.Video.Media.ALBUM
};
String selection = MediaStore.Video.Media.DATA + " like?";
String[] selectionArgs = new String[]{Environment.getExternalStorageDirectory() + "/myplayer/"};
Cursor cursor = ctx.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if ((cursor != null))
{
Log.d("trace cursor", "not null");
Log.d("trace count", "" + cursor.getCount());
}
}
According to following code, the count of cursor is always 0, but there are some video files in myplayer directory.
The problem is in the selection arguments. Append the ‘%’ character at the end, so it is as “myplayer/%”:
new String[]{Environment.getExternalStorageDirectory() + "/myplayer/%"};
This means to select anything that starts with the prefixed path, and has any string after “myplayer/”, which in this case are the file names.
Said that, consider that both the DATA field, and Environment.getExternalStorageDirectory() have been deprecated in Android Q (API 29). Hence, they will not work as expected in such version, and you should already try to find alternatives if you want your code to work in future Android versions, for example to use the BUCKET_DISPLAY_NAME instead.
so I'm pretty new to Android development. I'm trying to have the user select a song from their SD card or internal storage using a file manager and upload the file to a server. Right now, I'm just trying to access the name of the file that the user selected so that I can use it to access the contents of the file later and upload those contents.
I've looked at other posts concerning this and most of them tell you to query the content resolver and then use the cursor to grab the display name, but that does not always return the display name (this is mentioned in Google's guide to the SAF). It has not been returning the full file name, just part of it (the title of the song).
Here's my code that starts the intent:
Intent chooseIntent = new Intent(Intent.ACTION_GET_CONTENT);
chooseIntent.addCategory(Intent.CATEGORY_OPENABLE);
chooseIntent.setType("audio/*");
startActivityForResult(chooseIntent, SELECT_SONG_FILE_REQUEST_CODE);
How I'm getting the display name now:
String fileName = null;
if (uri.getScheme().equals("content")) {
try (Cursor cursor = getContentResolver().query(uri, null, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
fileName = cursor.getString(
cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
Log.i(TAG, "Filename: " + fileName);
cursor.close();
}
}
}
How can I get the full file name rather than just the display name?
You also can use TITLE in Cursor as URI parameter to get the full name of file
use below code it
Cursor cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,MediaStore.Audio.Media.TITLE, null, null, null);
Or You can use DATA to get Path of the file
Cursor cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,MediaStore.Audio.Media.DATA, null, null, null);
All You have to do is let the user choose the music and after selecting with the use of DATA you have full path of song and with TITLE you have full name of file .
Next just upload it.
There are several things that you can do to improve the performance of the query
You are getting all the columns which can be painfully slow.
You can write code like the one below and then check what field you want to use. You will get all the data for all the audio files installed in the device. You can walk through this code in the debugger to see the data that you need.
{
Uri objUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
ContentResolver cr = context.getContentResolver();
String[] entityColumns = {MediaStore.Audio.AudioColumns.DATA,
MediaStore.Audio.AudioColumns.DISPLAY_NAME,
MediaStore.Audio.AudioColumns.TITLE};
cursor = cr.query(
objUri,
entityColumns,
null,
null,
null);
if (cursor != null && cursor.moveToFirst()) {
do {
String filePath = cursor.getString(cursor.getColumnIndex(entityCoumns[0]));
String fileName = cursor.getString(cursor.getColumnIndex(entityColumns[1]));
String fileTitle =
cursor.getString(cursor.getColumnIndex(entityColumns[2]));
} while (cursor.moveToNext());
cursor.close();
}
}
This question already has answers here:
get the last picture taken by user
(3 answers)
Closed 9 years ago.
My intention is not to take a picture and then save it to sd card , get the link and all. The image is already taked with the original camera app in the android.
All i need it how can i get that image path with respect to sd card like
emulated/0/sdcard/DCIM/100ANDRO/image.jpg
how do i get that format of the recently taken image.
I've accomplished it like this:
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID + " DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
imageCursor.moveToFirst();
do {
String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
if (fullPath.contains("DCIM")) {
//--last image from camera --
return;
}
}
while (imageCursor.moveToNext());
Use this to get path of file from URI:
Uri selectedImageUri = data.getData();
selectedImagePath = getRealPathFromURI(selectedImageUri);
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
Cursor provides random read-write access to the result set returned by a database query.
getContentResolver () returns a ContentResolver instance for your application's package.
When you want to access data in a content provider, you use the ContentResolver object in your application's Context to communicate with the provider as a client. The ContentResolver object communicates with the provider object, an instance of a class that implements ContentProvider. The provider object receives data requests from clients, performs the requested action, and returns the results.
The Content Resolver includes the CRUD (create, read, update, delete) methods corresponding to the abstract methods (insert, delete, query, update) in the Content Provider class. The Content Resolver does not know the implementation of the Content Providers it is interacting with (nor does it need to know); each method is passed an URI that specifies the Content Provider to interact with.
MediaStore: The Media provider contains meta data for all available media on both internal and external storage devices. MediaStore.images contains meta data for all available images.
In the class MediaStore.Files class, its mentioned that,
Media provider table containing an index of all files in the media storage, including non-media files.
I'm interested in querying for non-media files like PDF.
I'm using CursorLoader to query the database. The second parameter for the constructor requires an Uri argument which is easy to get for the media types Audio, Images and Video as each of them have a EXTERNAL_CONTENT_URI and INTERNAL_CONTENT_URI constant defined for them.
For MediaStore.Files there is no such defined constant. I tried using the getContentUri() method but couldn't figure out the argument value for volumeName. I tried giving "/mnt/sdcard" and also the volume name that appears when I connect the device to my system but in vain.
I saw a similar question on Google Groups but that is not resolved.
EDIT: I also tried using Uri.fromFile(new File("/mnt/sdcard/")) and Uri.parse(new File("/mnt/sdcard").toString()) but that didn't work out either.
It is "external" or "internal" although internal (system files) is probably not useful here.
ContentResolver cr = context.getContentResolver();
Uri uri = MediaStore.Files.getContentUri("external");
// every column, although that is huge waste, you probably need
// BaseColumns.DATA (the path) only.
String[] projection = null;
// exclude media files, they would be here also.
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_NONE;
String[] selectionArgs = null; // there is no ? in selection so null here
String sortOrder = null; // unordered
Cursor allNonMediaFiles = cr.query(uri, projection, selection, selectionArgs, sortOrder);
If you want .pdf only you could check the mimetype
// only pdf
String selectionMimeType = MediaStore.Files.FileColumns.MIME_TYPE + "=?";
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
String[] selectionArgsPdf = new String[]{ mimeType };
Cursor allPdfFiles = cr.query(uri, projection, selectionMimeType, selectionArgsPdf, sortOrder);
i am traversing in the phone's memory with the following code.
ContentResolver contentResolver = getContentResolver();
String[] columns = {
MediaColumns._ID,
MediaColumns.TITLE,
AudioColumns.DURATION,
};
final String where = MediaStore.Audio.Media.IS_MUSIC + "=1";
Cursor cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,columns, where, null, null);
while(cursor.moveToNext()) {
String urp = cursor.getString(cursor.getColumnIndex(MediaColumns._ID));
String title = cursor.getString(cursor.getColumnIndex(MediaColumns.TITLE));
Long duration = cursor.getLong(cursor.getColumnIndex(AudioColumns.DURATION));
}
so now my question is, how to get the uri of the cursor items traveresed, like
for first while run i have stored id,title,duration etc metadata and i would also like to
store that tracks URI, also i would like to convert that URI from content// scheme to file scheme.
Any help will be greatful
thankyou
String.valueOf(cur.getColumnIndex(android.provider.MediaStore.MediaColumns.DATA)));
http://android-er.blogspot.fr/2011/04/convert-uri-to-real-path-format.html