ListView displaying audio and video from mediastore - android

I'm trying to create a list that shows both audio and video from the mediastore. However, I'm not sure how to create such a query - is it even possible to get information for both audio and video at the same time?
So to query for video and audio I do this:
String[] projV = { MediaStore.Video.Media._ID,
MediaStore.Video.Media.DATA,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.DATE_TAKEN };
Cursor videoCursor = getActivity().managedQuery(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projV, null,
null, null);
String[] projA = { MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.MIME_TYPE,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATE_ADDED };
Cursor audioCursor = getActivity().managedQuery(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projA, null,
null, null);
I looked into using CursorJoiner or MergeCursor, but I'm not sure how to use these or even certain its the right solution.
So my question is; Is there a way to construct a query for the mediaStore that returns a cursor with information for both audio and video or do I need to something more complex such as using CursorJoiner or MergeCursor.
As I mentioned at the start, my goal is to have a list displaying all the audio and video in the mediastore - is this the right approach or am I looking at it from a wrong angle?
Thanks.

It is possible from API-11 by using MediaStore.Files with an appropriate selection clause.
public Loader<Cursor> onCreateLoader(int id, Bundle bundle)
{
final String PROJECTION[] = {FileColumns._ID, FileColumns.DATA, FileColumns.DATE_ADDED};
final String ORDER = FileColumns.DATE_ADDED + " DESC";
final String SELECTION = "(" + FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_VIDEO +") OR (" + FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_IMAGE + ")";
return new CursorLoader(getActivity(), Files.getContentUri("external"), PROJECTION, SELECTION, null, ORDER);
}
Prior to that you can use a MergeCursor if you don't care about sort order. Look at MatrixCursor if you need to manage sort order. Alternatively wrap your cursors in a CursorWrapper that implements order logic.

Related

MediaStore to list from specific path

I am trying to get list of mp3 files from a particular folder.
As of now, I am using contentResolver.query for getting the music from my phone.
Like this:
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
String[] projection = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION
};
ContentResolver contentResolver = context.getContentResolver();
cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,projection, selection,null,null);
I am looking for solution to scan only a particular folder. How do I do this using contentResolver?
Thanks!
Finally figured it out myself. Hope it will help others.
Instead of this:
cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, null);
I used this:
cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection,MediaStore.Audio.Media.DATA + " like ? ",
new String[] {"%MyMusicFolder%"}, null);

Android - searching music using MediaStore using a string

I basically can not accomplish this for over 2 weeks now.
I have posted a numerous amount of code over a few questions yet most of them got ignored so I won't flood this question with more code of my own that won't even be read.
How do I search the MediaStore with "LIKE" attributes using a String?
E.G. I type in Shoot To Thrill, I receive song ID with this code:
if(cursor.moveToFirst()){
while(cursor.moveToNext()){
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String id = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
test.setText(title +" " + artist + " " + id);
}
}
Here is something to begin with:
String[] projection = {
BaseColumns._ID,
MediaStore.Audio.Artists.ARTIST,
MediaStore.Audio.Media.TITLE
}
Cursor cursor = this.managedQuery(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, //uri
projection, //projection
//i dont know what to enter,
//i dont know what to enter,
MediaStore.Audio.Media.TITLE);
It's just normal SQL hiding behind the scenes. Normal LIKE operations should work just fine. You can use MediaStore.Audio.Media.TITLE + " LIKE \"%thrill%\"" just like any other SQL query.
String[] projection = { BaseColumns._ID,
MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Media.TITLE };
String where = MediaStore.Audio.Media.TITLE + " LIKE ?";
String[] params = new String[] { "%life%" };
Cursor q = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection, where, params, MediaStore.Audio.Media.TITLE);
try {
while (q.moveToNext()) {
Log.e("song", q.getString(1) + " " + q.getString(2));
}
} finally {
q.close();
}

How to actually search for a song in a mediastore cursor using a string

I have set up the cursor but I am still struggling with actually searching it. How do I search for the track name? How do I get its ID so I can pass it to mediaplayer? I have tried different things but didn't succeed.
Basically, I want to know how to search the mediastore for a certain string (string songToPlay in this case), get the results, get the ID of the best match and pass it to my mediaplayer service to play it in the background. The only thing I am asking you is how to get the ID though.
This is the code I am using:
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] songToPlay = value.split("play song");
String[] searchWords = songToPlay[1].split(" ");
String [] keywords = null;
StringBuilder where = new StringBuilder();
where.append(MediaStore.Audio.Media.TITLE + " != ''");
String selection = where.toString();
String[] projection = {
BaseColumns._ID,
MediaStore.Audio.Media.MIME_TYPE,
MediaStore.Audio.Artists.ARTIST,
MediaStore.Audio.Albums.ALBUM,
MediaStore.Audio.Media.TITLE
};
for (int i = 0; i < searchWords.length; i++) {
keywords[i] = '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%';
}
Cursor cursor = this.managedQuery(uri, projection, selection, keywords, MediaStore.Audio.Media.TITLE);
if (cursor.moveToFirst()) {
do{
test.setText(cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)));
}while(cursor.moveToNext());
}
I'm very confused and most of this code is from the internet. I have been trying to do this for 2 days now, that's why I'm asking here. I've done hours of trying by myself.
edit: Current code. How am I supposed to find the location - music ID or whatever I need to play that song from the cursor?
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String songToPlay = value.replaceAll("play song", "").trim();
int music_column_index;
String[] projection = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Artists.ARTIST,
MediaStore.Audio.Albums.ALBUM,
MediaStore.Audio.Media.TITLE
};
#SuppressWarnings("deprecation")
Cursor cursor = this.managedQuery(uri,
null,
MediaStore.Audio.Media.TITLE + "=?",
new String[]{songToPlay},
MediaStore.Audio.Media.TITLE + " ASC");
This will search the MediaStore for all songs with title equal to the value of your songToPlay string.
Cursor cursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null,
MediaStore.Audio.Media.TITLE + "=?",
new String[]{songToPlay},
MediaStore.Audio.Media.TITLE + " ASC");
You can then of course query the cursor to get the ID (and any other column) of any results.
while (cursor.moveToNext()) {
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
// Whatever else you need
}
However this will require an exact match, you may like to use the LIKE operator for a more fuzzy match.

Access ordered images and video in same Cursor

I'm using the android.content.CursorLoader class to create two Cursor objects to access media stored on the user of my app's device. I'd like to give the user a grid view of their stored images and video which preserves order from the Android Gallery app.
Currently I'm using one Cursor to access Images and one to access Video. With this approach, all images precede all videos (i.e. they are in two separate groups). Is there a way to access both Images and Video from the same Cursor? If not, is there a better way to access these media on the device?
For reference, here is the code I am using:
For Images:
CursorLoader cursorLoader = new CursorLoader(
mContext,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
IMAGE_PROJECTION,
null,
null,
MediaStore.Images.Media._ID + " desc"
);
mImageCursor = cursorLoader.loadInBackground();
And Video:
CursorLoader cursorLoader = new CursorLoader(
mContext,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
VIDEO_PROJECTION,
null,
null,
MediaStore.Video.Media._ID + " desc"
);
mVideoCursor = cursorLoader.loadInBackground();
After lots of research and playing around with source code, I'm finally a bit more familiar with the Android filesystem. To get a single Cursor which can access information about both Images and Video I used the following:
// Get relevant columns for use later.
String[] projection = {
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MIME_TYPE,
MediaStore.Files.FileColumns.TITLE
};
// Return only video and image metadata.
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE
+ " OR "
+ MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
Uri queryUri = MediaStore.Files.getContentUri("external");
CursorLoader cursorLoader = new CursorLoader(
this,
queryUri,
projection,
selection,
null, // Selection args (none).
MediaStore.Files.FileColumns.DATE_ADDED + " DESC" // Sort order.
);
Cursor cursor = cursorLoader.loadInBackground();

Group By in ContentResolver in Ice Cream Sandwich

I am making a query on the Android Contacts ContentProvider. I need a Group By clause. In Gingerbread and Honeycomb, I do something like this to search phone numbers and emails at the same time:
(The actual WHERE clause is much more complicated as it includes types checks. This is a simplification, but it yields the same result)
String request = Phone.NUMBER + " LIKE ? OR " + Email.DATA + " LIKE ?";
String[] params = new String["%test%", "%test%"];
Cursor cursor = getContentResolver().query(
Data.CONTENT_URI,
new String[] { Data._ID, Data.RAW_CONTACT_ID },
request + ") GROUP BY (" + Data.RAW_CONTACT_ID,
params, "lower(" + Data.DISPLAY_NAME + ") ASC");
The injection of the ')' finishes the WHERE clause and allow the insertion of a GROUP BY clause.
However, in Ice Cream Sandwich, it appears that the ContentProvider detects this and adds the correct number of parenthesis to prevent my injection. Any other way of doing this in a single cursor query?
Edit
Currently, I have removed the GROUP BY, and added a MatrixCursor to limit the impact, but I'd rather have a real cursor:
MatrixCursor result = new MatrixCursor(new String[] { Data._ID, Data.RAW_CONTACT_ID });
Set<Long> seen = new HashSet<Long>();
while (cursor.moveToNext()) {
long raw = cursor.getLong(1);
if (!seen.contains(raw)) {
seen.add(raw);
result.addRow(new Object[] {cursor.getLong(0), raw});
}
}
I recently battled this issue querying the CallLog.Calls DB (where we were not able to modify the ContentProvider). What we ended up going with was building a query that looked like this:
SELECT _id, date, duration, type, normalized_number FROM calls WHERE _id IN (
SELECT _id FROM calls WHERE date < ? GROUP BY normalized_number ORDER BY date DESC LIMIT ?
);
The idea here is that we place any valid sqlite in our subquery, return a list of ids and then query again for all calls with those ids.
The final code looked something like this:
String whereClause = "_id IN (SELECT _id FROM calls WHERE data < ? GROUP BY normalized_number ORDER BY date DESC LIMIT ?)";
Cursor cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI,
new String[] { "_id", "date", "duration", "normalized_number" },
whereClause,
new String[]{ String.valueOf(amount), String.valueOf(dateFrom) },
null
);
...
In the case that you're querying for contacts, it would look something like this:
String whereClause = "_id IN (SELECT _id FROM contacts WHERE " + Phone.NUMBER + " LIKE ? OR " + Email.DATA + " LIKE ? GROUP BY " + Data.RAW_CONTACT_ID + " ORDER BY lower(" + Data.DISPLAY_NAME + ") ASC)";
String[] params = new String["%test%", "%test%"];
Cursor cursor = getContentResolver().query(
Data.CONTENT_URI,
new String[] { Data._ID, Data.RAW_CONTACT_ID },
whereClause,
params,
null
);
There will be some decrease in performance (since we're essentially querying twice for the same results), but it will surely be a lot faster than querying for all calls and doing the GROUP BY work in java world and also allows you to build up the query with additional clauses.
Hope this helps. We used this on Oreo and it fulfilled our needs.
You could create a custom Uri such that when your UriMatcher in your ContentProvider gets it, you can insert your group by clause and then execute the raw sql directly on the database.
first off all excuse my POOR English!
I'm new to Java/Android, started with 4.2.1 and fight with that too almost 2 days, then i start reading some more details about SQLiteQueryBuilder the query part is pretty much that what u are looking for ;)
it have:
public Cursor query (SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder)
the query "function" of the Content Provider only gives you:
query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
here u can trick around, i will post you my code snip:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
/* a String is a Object, so it can be null!*/
String groupBy = null;
String having = null;
switch (sUriMatcher.match(uri)) {
...
...
...
case EPISODES_NEXT:
groupBy = "ShowID";
queryBuilder.setTables(EpisodenTable.TableName);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
Cursor c = queryBuilder.query(db, projection, selection, selectionArgs,
groupBy, having, sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
thats its!
here the code i use to execute:
Cursor showsc = getContext().getContentResolver().query(
WhatsOnTVProvider.CONTENT_EPISODES_NEXT_URI,
EpisodenTable.allColums_inclCount,
String.valueOf(Calendar.getInstance().getTimeInMillis() / 1000)
+ " < date", null, null);

Categories

Resources