MediaStore External Content URI is fetching data from SDCARD - java

I am using MediaStore and Cursor to fetch audio files from a specified folder. What I want is that, it should fetch the list of songs from the phone's internal storage but it is fetching from SDCARD. Although I have tried using INTERNAL_CONTENT_URI but it is not getting anything at all. Kindly have a look, what's wrong in it. Any help will be appreciated.
String AudioFilePath = "%" +"/nexcox/voicerecorder/audio/" +"%";
Uri uri= MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection= MediaStore.Audio.Media.DATA +" LIKE ? ";
Cursor cursor=context.getContentResolver().query(uri,null,selection,
new String[]{AudioFilePath},
null);
if (cursor!=null){
if (cursor.moveToFirst()){
do {
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
String sourceLocation = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
AudioInfo audioInfo=new AudioInfo(name,duration,sourceLocation);
audioInfos.add(audioInfo);
}while (cursor.moveToNext());
}
cursor.close();
audioAdapter=new AudioAdapter(context,audioInfos);
recyclerView.setAdapter(audioAdapter);
}

for example
String fullpath = trackcursor.getString(trackcursor.getColumnIndex(MediaStore.Audio.Media.DATA))
if(fullpath.contains(Environment.getExternalStorageDirectory(){
// you have the internal sdcard
}
In your code:
if (cursor!=null){
if (cursor.moveToFirst()){
do {
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
String sourceLocation = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
if(sourceLocation.contains(Environment.getExternalStorageDirectory(){
// you have the internal sdcard
AudioInfo audioInfo=new AudioInfo(name,duration,sourceLocation);
audioInfos.add(audioInfo);
}
}while (cursor.moveToNext());
}
cursor.close();
audioAdapter=new AudioAdapter(context,audioInfos);
recyclerView.setAdapter(audioAdapter);
}

I use the same approach as your example. Works fine.
public Cursor getMediastoreTrackDetails(Context context, String trackName) {
if(context!=null) {
ContentResolver cr = context.getContentResolver();
final String _id = MediaStore.Audio.Media._ID;
final String path = MediaStore.Audio.Media.DATA;
final String album = MediaStore.Audio.Media.ALBUM;
final String album_id = MediaStore.Audio.Media.ALBUM_ID;
final String[] columns = {_id, path,album, album_id};
final String[] trackname = {"%" + trackName + "%"};
String where = path + " LIKE ?";
return cr.query(uri, columns, where, trackname, null);
}else{
return null;
}
}

Related

android - ContentProvider: problem setting filename for files delivered by using ContentProvider.openFile

I'm facing the following problem while implementing a ContentProvider to deliver images stored in the private data area of an application in an android-project:
The files returned by the implementation below have the complete absolute path to the stored images as filename which look like
_data_data_com.mypackage.imageprovider_app_images_123456789.jpg
where app_images is the name of the directory the images are stored in by the application and 123456789.jpg is the actual filename.
My question now is: How can I make the ContentProvider set only the actual filename (or alternatively a filename I specify) for the delivered images?
It should be possible, since e.g. the built-in providers in android manage to deliver only the actual filename for an image.
The database table has columns for _id, filename and _data, where _data holds the absolute path to the image in the filesystem.
Any hints are very highly appreciated :)
Thanks in advance, snowcrash123
Here are the relevant parts of my current ContentProvider:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(PhotosTable.TABLE_NAME);
switch (URI_MATCHER.match(uri))
{
case PHOTO_DIR:
if (sortOrder == null)
{
sortOrder = PhotosDirectory.DEFAULT_SORT_ORDER;
}
break;
case PHOTO_ID:
queryBuilder.appendWhere(IPhotoColumns.FILENAME + "="
+ uri.getPathSegments().get(1) + " AND ");
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (!mDb.isOpen())
{
assignWritableDb();
}
return queryBuilder.query(mDb, PhotosDirectory.ALL_COLUMNS,
selection, selectionArgs, null, null, sortOrder);
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
{
if (URI_MATCHER.match(uri) != PHOTO_ID)
{
throw new IllegalArgumentException(
"operation only permitted for single file");
}
try
{
return openFileHelper(uri, mode);
}
catch (FileNotFoundException e)
{
return null;
}
}

Fetching exact path of songs and building a URI

I am using Exo Player in order to make an audio player for android. So far i am using this code and fetching the following info from my phone. Data, Name, Artist.
public void getMp3Songs() {
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0";
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
int songId = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
arrayList.add(new Songs(songId, name, url));
} while (cursor.moveToNext());
}
cursor.close();
}
}
The next thing i need is exact path of these tracks.
For that purpose i am using this code.
private void initializePlayer(){
player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this), new DefaultTrackSelector()
, new DefaultLoadControl());
simpleExoPlayerView.setPlayer(player);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow,playbackPosition);
Uri uri = Uri.parse(url);
MediaSource mediaSource = buildMediaSource(uri);
player.prepare(mediaSource, true, false);
}
private MediaSource buildMediaSource(Uri uri) {
return new ExtractorMediaSource(uri,
new DefaultHttpDataSourceFactory("ua"),
new DefaultExtractorsFactory(), null, null);
}
The problem is that when i start the player, nothing happens. Its just a blank player and its not playing anything. I think i am messing with the file paths here. Please help.
Okay so i found the solution if someone is in need he can use it. The problem was not in getting the address or building the Uri. It was in this particular section. new DefaultHttpDataSourceFactory("ua") Change this to this:
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this,
Util.getUserAgent(this, "idk"), new DefaultBandwidthMeter());
Now use this instance while returning MediaSource.

Changing contact's image to a large photo via PHOTO_FILE_ID in Android

This seems to work for small images:
ContentValues values = new ContentValues();
values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, photo);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
if (photoRow >= 0) {
context.getContentResolver().update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data._ID + " = " + photoRow, null);
} else {
context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}
From the docs I realise that for large images I need to set the PHOTO_FILE_ID, so I can replace:
ContactsContract.CommonDataKinds.Photo.PHOTO
with:
ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID
However, then I need to supply a PHOTO_FILE_ID rather than raw data. My question:
How do I save the photo (byte []) and get a PHOTO_FILE_ID?
If there is already a photo available (PHOTO not PHOTO_FILE_ID). Do I need to delete it for the big image to be seen or does the big image take precedence, if not, how do I delete it?
Your own answer will work, but it's not very efficient because the photo needs to be encoded into an SQL query and piped through Android IPC. That also makes it a subject to Android's IPC size limit of 1MB (i.e. if your photo is too large the content provider operation will fail).
The most efficient way to set (create or override) a RawContact's (primary) photo is by using openAssetFileDescriptor and a ContactsContract.RawContacts.DisplayPhoto URI like so (example copied from Android docs):
public void writeDisplayPhoto(long rawContactId, byte[] photo) {
Uri rawContactPhotoUri = Uri.withAppendedPath(
ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
try {
AssetFileDescriptor fd =
getContentResolver().openAssetFileDescriptor(rawContactPhotoUri, "rw");
OutputStream os = fd.createOutputStream();
os.write(photo);
os.close();
fd.close();
} catch (IOException e) {
// Handle error cases.
}
}
The only drawback of this approach is that it always creates/replaces the primary photo of the RawContact. If the RawContact doesn't have a photo yet this will add one.
Unfortunately there is no way to use openAssetFileDescriptor with a PHOTO_FILE_ID, so you can't override a specific photo identified by its ID using this method. However, in real life most contacts probably have at most one photo, so that's not a real limitation.
This will automatically update the Photo.PHOTO column with a thumbnail of the large photo and assign a PHOTO_FILE_ID.
Finally was able to solve it with:
public void changeContactImage(String contactId, byte[] b) {
ArrayList < ContentProviderOperation > ops = new ArrayList < > ();
ops.add(ContentProviderOperation
.newUpdate(
ContactsContract.Data.CONTENT_URI)
.withSelection(
ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?",
new String[] {
contactId,
ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
})
.withValue(ContactsContract.CommonDataKinds.Photo.DATA15, b).build());
// Do something with the phone number...
try {
context.getContentResolver().
applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
Log.d("RemoteException", e.toString());
} catch (OperationApplicationException e) {
Log.d("OperationException", e.toString());
}
}
The PHOTO_FILE_ID is the ID not of a file (confusingly) but of a row in the database which contains your raw photo data. According to the docs I've looked at you can actually avoid using it (from the docs) :
Under PHOTO_FILE_ID
If present, this will be used to populate PHOTO_URI
and Under PHOTO_ID (which is guaranteed populated if PHOTO_FILE_ID exists)
Reference to the row in the data table holding the photo. A photo can be referred to either by ID (this field) or by URI (see PHOTO_THUMBNAIL_URI and PHOTO_URI)
This implies that if you just use PHOTO_URI you will get the same resulting image as if you made the method openDisplayPhoto. It also suggests that the URI methods are better compatible with 3rd part directories so are probably preferable to work with
You can get the contact photo uri without using ContactsContract.CommonDataKinds.Email.PHOTO_URI this way:
Read Full Answer here More
Where! to get Contact URI as you said try this:
import android.provider.ContactsContract.PhoneLookup;
public String fetchContactIdFromPhoneNumber(String phoneNumber) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
Cursor cursor = this.getContentResolver().query(uri,
new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
null, null, null);
String contactId = "";
if (cursor.moveToFirst()) {
do {
contactId = cursor.getString(cursor
.getColumnIndex(PhoneLookup._ID));
} while (cursor.moveToNext());
}
return contactId;
}
To get the conatct id using the phone number use the following code:
import android.provider.ContactsContract.PhoneLookup;
public String fetchContactIdFromPhoneNumber(String phoneNumber) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
Cursor cursor = this.getContentResolver().query(uri,
new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
null, null, null);
String contactId = "";
if (cursor.moveToFirst()) {
do {
contactId = cursor.getString(cursor
.getColumnIndex(PhoneLookup._ID));
} while (cursor.moveToNext());
}
return contactId;
}
and use the contact id obtained to get the contatc photo URI. Use the following code for getting photo URI:
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
public Uri getPhotoUri(long contactId) {
ContentResolver contentResolver = getContentResolver();
try {
Cursor cursor = contentResolver
.query(ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID
+ "="
+ contactId
+ " AND "
+ ContactsContract.Data.MIMETYPE
+ "='"
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
+ "'", null, null);
if (cursor != null) {
if (!cursor.moveToFirst()) {
return null; // no photo
}
} else {
return null; // error in cursor process
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
Uri person = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, contactId);
return Uri.withAppendedPath(person,
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}
Please let me know if this does not answer your question

Populate listview with video files on KitKat

I hope somebody can help me.
I display on my app all the recorded video files located on the sd card through a listView. But this doesn't work with the Api 19 (kitkat).My code is this:
String selection = MediaStore.Video.Media.DATA + " like?";
String[] selectionArgs = new String[]{"%"+ VideoRoute + "%"};
videocursor = activity.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,proj, selection, selectionArgs, MediaStore.Video.Media.DATE_TAKEN + "DESC");
count = videocursor.getCount();
while (videocursor.moveToNext()){
...
Bitmap bmThumbnail = ThumbnailUtils.createVideoThumbnail(video.getUrlMedia(), Thumbnails.MICRO_KIND);
...
}
Does anyone know how to achieve this with Android KitKat?
Thanks in advance.
Before KitKat, public APIs only supported a single primary external storage device, which on some devices can be emulated and backed by internal storage. Primary external storage devices continue to work the way they always have since API level 1; if you request WRITE_EXTERNAL_STORAGE you have full read/write access across that entire device.
For secondary external storage devices in KitKat, there is limited write access to directories belonging to the running app.
Advantages-
1: apps can take advantage of the extra storage space.
2: users have better visibility into and control over how apps are using their storage space. (These package-specific directories are surfaced to apps through Context.getExternalFilesDirs(), etc.)
So your code might be giving zero count of videos found.
I'll post my own answer, in case someone needs help like me with this issue, what worked for me:
//with videoList fill de listView
videoList = getFilesKitkat();
public List<Video> getFilesKitkat(){
int i = 0;
list.clear();//list is global
//App package directory in the sd card to get all the files,
// in my case, there is only mp4 files.
// /storage/extSdCard/Android/data/<package_name>/files...
File targetDirector = new File (videosPath);
File[] files = targetDirector.listFiles();
int totalFiles = files.length;
String[] filesToScan = new String[totalFiles];
//this is to get all the paths in order to pass them to MediaScannerConnection
for (File file : files){
filesToScan[i] = file.getAbsolutePath();
i++;
}
callMediaScanner_kitkat(filesToScan);
return list;
}
public void callMediaScanner_kitkat(final String[] files) {
MediaScannerConnection.scanFile(context, files, null,
new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
// TODO Auto-generated method stub
Log.i("Test", "Scanned " + path);
getVideosList_kitkat(context, uri);
}
});
}
public void getVideosList_kitkat(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Video.Media._ID,
MediaStore.Video.Media.DATA,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.SIZE,
MediaStore.Video.Media.TITLE,
MediaStore.Video.Media.DATE_MODIFIED};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
while (cursor.moveToNext()){
Video video = new Video();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));
String nombre = (cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE))).toLowerCase();
video.setName(nombre + XSalesApplication.getActivityContext().getResources().getString(R.string.video_extension));
video.setId(cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)));
video.setSize(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)));
video.setUrlMedia(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))); video.setlastModified(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_MODIFIED)));
Bitmap bmThumbnail = ThumbnailUtils.createVideoThumbnail(video.getUrlMedia(), Thumbnails.MICRO_KIND);
video.setPhotoBitmap(bmThumbnail);
list.add(video);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}

Get contact display picture with a phone number without a country code?

Is it possible to get a contact's display picture regardless of whether the number exactly matches to that in the address book?
For exmample - if the number saved is 736--------, but the incoming call shows +01736--------, how do I get the display picture using the number with the extension?
Yes you can get the display image of the contact based on the contact number(whichever format it is).
Below method will return the display image of a contact if the contact is stored in the device contacts list and that contact has the image. Pass the contact number with or without country code.
public static Bitmap getDisplayPhoto(Context context, String contactNumber) {
contactNumber = Uri.encode(contactNumber);
int phoneContactID = -1;
Cursor contactLookupCursor = context.getContentResolver().query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, contactNumber),
new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID }, null, null, null);
while (contactLookupCursor.moveToNext()) {
phoneContactID = contactLookupCursor.getInt(contactLookupCursor.getColumnIndexOrThrow(PhoneLookup._ID));
}
contactLookupCursor.close();
Bitmap photo = null;
if (phoneContactID != -1) {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, phoneContactID);
Uri displayPhotoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.DISPLAY_PHOTO);
try {
AssetFileDescriptor fd = context.getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r");
photo = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
} catch (IOException e) {
}
}
return photo;
}

Resources