I want to load cover audio art in android for show list of audio from device. For this purpose i used this following Link:
way1
way2
way3
Like following picture:
And my code for Load audio files:
private void loadAudio() {
ContentResolver contentResolver = getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0";
String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
Cursor cursor = contentResolver.query(uri, null, selection, null, sortOrder);
if (cursor != null && cursor.getCount() > 0) {
audioList.clear();
while (cursor.moveToNext()) {
String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
int albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
Cursor cursor1 = contentResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + "=" + albumId, null, null);
Bitmap bitmap = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
try {
bitmap = contentResolver.loadThumbnail(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, new Size(30, 30), null);
} catch (IOException e) {
e.printStackTrace();
}
}
String albumArt = "";
if (cursor1 != null && cursor1.getCount() > 0)
while (cursor1.moveToNext()) {
albumArt = cursor.getString(cursor1.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
}
// Save to audioList
audioList.add(new Audio(data, title, album, artist, albumArt, bitmap));
}
}
cursor.close();
setAdapter();
}
And in MyAdapter about recyclerview:
#Override
public void onBindViewHolder(#NonNull MainHolder holder, int position) {
Audio audio = arrayList.get(position);
holder.txtTitle.setText("Title: " + audio.getTitle());
holder.txtAlbum.setText("Album: " + audio.getAlbum());
holder.txtArtist.setText("Artist: " + audio.getArtist());
File imgFile = new File(audio.getAlbumArt());
Picasso.get().load(imgFile.getAbsolutePath()).into(holder.img);
if (imgFile.exists()) {
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
holder.img.setImageBitmap(myBitmap);
}
}
Help me please.
Solved:
Load audio file:
private void loadAudio() {
ContentResolver contentResolver = getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0";
String sortOrder = MediaStore.Audio.Media.ARTIST + " DESC";
Cursor cursor = contentResolver.query(uri, null, selection, null, sortOrder);
if (cursor != null && cursor.getCount() > 0) {
audioList.clear();
while (cursor.moveToNext()) {
Audio audio = new Audio();
String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
int albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
Bitmap thumbnail = null;
String albumArt = null;
Uri imageUri_t;
Cursor cursor1 = contentResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + "=" + albumId, null, null);
while (cursor1.moveToNext()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Size thumbSize = new Size(100, 100);
try {
int thumbColumn = cursor1.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID);
int _thumpId = cursor1.getInt(thumbColumn);
imageUri_t = ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, _thumpId);
thumbnail = getContentResolver().loadThumbnail(imageUri_t, thumbSize, null);
} catch (IOException e) {
e.printStackTrace();
}
} else {
albumArt = cursor1.getString(cursor1.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
}
}
audio.setData(data);
audio.setTitle(title);
audio.setAlbum(album);
audio.setArtist(artist);
audio.setAlbumId(albumId);
audio.setAlbumArt(albumArt);
audio.setThumbnail(thumbnail);
audioList.add(audio);
}
}
cursor.close();
setAdapter();
}
And a part of MyAdapter:
#Override
public void onBindViewHolder(#NonNull MainHolder holder, int position) {
Audio audio = arrayList.get(position);
holder.txtTitle.setText("Title: " + audio.getTitle());
holder.txtAlbum.setText("Album: " + audio.getAlbum());
holder.txtArtist.setText("Artist: " + audio.getArtist());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (audio.getThumbnail() != null)
holder.img.setImageBitmap(audio.getThumbnail());
} else {
if (audio.getAlbumArt() != null) {
File imgFile = new File(audio.getAlbumArt());
if (imgFile.exists()) {
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
holder.img.setImageBitmap(myBitmap);
}
}
}
}
First query on MediaStore.Audio.Media.ARTIST about fetch audio info from MediaStore.
There is a difference About fetch thumbnail of Audio file in android 10 (Q) and below.
So query for lower than Android 10 is like follow:
String albumArt = cursor1.getString(cursor1.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
You can get album art from ALBUM_ART column in MediaStore.Audio.Albums.
Then for Android 10 like follow this:
Query on MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI where albumId equals _ID column from MediaStore.Audio.Albums.
And load thumbnail from Content Resolver by image uri...
I hope it is useful ;)
I tried lot of snippets. This is what I'm using now. I know that MediaStore.Video.Media.DATA is deprecated.somehow this method is working on android 10 as well but sometimes it throws
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
public static String getvideoPath(Context context, Uri uri) {
try {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
LogMessage.v("Document Id:: "+document_id);
if(document_id!=null){
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Video.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
cursor.close();
return path;
}else
return getPath(context,uri);
} catch (Exception e) {
e.printStackTrace();
return getPath(context,uri);
}
}
private static String getPath(Context context,Uri uri){
try {
String[] proj = { MediaStore.Video.Media.DATA };
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
return document_id;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Get real path of video selected from gallery with below method
#SuppressLint("NewApi")
public String getPath( final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String selection = null;
String[] selectionArgs = null;
// DocumentProvider
if (isKitKat ) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String fullPath = getPathFromExtSD(split);
if (fullPath != "") {
return fullPath;
} else {
return null;
}
}
// DownloadsProvider
if (isDownloadsDocument(uri)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String id;
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
if (!TextUtils.isEmpty(path)) {
return path;
}
}
}
finally {
if (cursor != null)
cursor.close();
}
id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads"
};
for (String contentUriPrefix : contentUriPrefixesToTry) {
try {
final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
//In Android 8 and Android P the id is not a number
return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
}
}
}
}
else {
final String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
}
catch (NumberFormatException e) {
e.printStackTrace();
}
if (contentUri != null) {
return getDataColumn(context, contentUri, null, null);
}
}
}
// MediaProvider
if (isMediaDocument(uri)) {
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;
}
selection = "_id=?";
selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection,
selectionArgs);
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri);
}
if(isWhatsAppFile(uri)){
return getFilePathForWhatsApp(uri);
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri);
}
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
// return getFilePathFromURI(context,uri);
return copyFileToInternalStorage(uri,"userfiles");
// return getRealPathFromURI(context,uri);
}
else
{
return getDataColumn(context, uri, null, null);
}
}
if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
}
else {
if(isWhatsAppFile(uri)){
return getFilePathForWhatsApp(uri);
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = null;
try {
cursor = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
private boolean fileExists(String filePath) {
File file = new File(filePath);
return file.exists();
}
private String getPathFromExtSD(String[] pathData) {
final String type = pathData[0];
final String relativePath = "/" + pathData[1];
String fullPath = "";
// on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
// something like "71F8-2C0A", some kind of unique id per storage
// don't know any API that can get the root path of that storage based on its id.
//
// so no "primary" type, but let the check here for other devices
if ("primary".equalsIgnoreCase(type)) {
fullPath = Environment.getExternalStorageDirectory() + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
}
// Environment.isExternalStorageRemovable() is `true` for external and internal storage
// so we cannot relay on it.
//
// instead, for each possible path, check if file exists
// we'll start with secondary storage as this could be our (physically) removable sd card
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
return fullPath;
}
private String getDriveFilePath(Uri uri) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
/***
* Used for Android Q+
* #param uri
* #param newDirName if you want to create a directory, you can set this variable
* #return
*/
private String copyFileToInternalStorage(Uri uri,String newDirName) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, new String[]{
OpenableColumns.DISPLAY_NAME,OpenableColumns.SIZE
}, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File output;
if(!newDirName.equals("")) {
File dir = new File(context.getFilesDir() + "/" + newDirName);
if (!dir.exists()) {
dir.mkdir();
}
output = new File(context.getFilesDir() + "/" + newDirName + "/" + name);
}
else{
output = new File(context.getFilesDir() + "/" + name);
}
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(output);
int read = 0;
int bufferSize = 1024;
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
inputStream.close();
outputStream.close();
}
catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return output.getPath();
}
private String getFilePathForWhatsApp(Uri uri){
return copyFileToInternalStorage(uri,"whatsapp");
}
private 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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
}
finally {
if (cursor != null)
cursor.close();
}
return null;
}
private boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
public boolean isWhatsAppFile(Uri uri){
return "com.whatsapp.provider.media".equals(uri.getAuthority());
}
private boolean isGoogleDriveUri(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
}
Happy Coding.
The above answer which is given by tushar is abosulity correct, I have converted that code into kotlin, might be it helps someone.
import android.annotation.SuppressLint
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.text.TextUtils
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import kotlin.math.min
#SuppressLint("Recycle")
#Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "DEPRECATION")
object FileManager {
fun getPath(context: Context, uri: Uri): String? {
// check here to KITKAT or new version
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
var selection: String? = null
var selectionArgs: Array<String>? = null
// DocumentProvider
if (isKitKat) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
//val type = split[0]
val fullPath = getPathFromExtSD(split)
return if (fullPath !== "") {
fullPath
} else {
null
}
}
// DownloadsProvider
if (isDownloadsDocument(uri)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null)
if (cursor != null && cursor.moveToFirst()) {
val fileName: String = cursor.getString(0)
val path: String = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
if (!TextUtils.isEmpty(path)) {
return path
}
}
} finally {
cursor?.close()
}
val id: String = DocumentsContract.getDocumentId(uri)
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:".toRegex(), "")
}
val contentUriPrefixesToTry = arrayOf("content://downloads/public_downloads", "content://downloads/my_downloads")
for (contentUriPrefix in contentUriPrefixesToTry) {
return try {
val contentUri: Uri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), java.lang.Long.valueOf(id))
getDataColumn(context, contentUri, null, null)
} catch (e: NumberFormatException) {
//In Android 8 and Android P the id is not a number
uri.path?.replaceFirst("^/document/raw:", "")?.replaceFirst("^raw:", "")
}
}
}
} else {
val id = DocumentsContract.getDocumentId(uri)
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:".toRegex(), "")
}
var contentUri : Uri?= null
try {
contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
} catch (e: NumberFormatException) {
e.printStackTrace()
}
if (contentUri != null) {
return getDataColumn(context, contentUri, null, null)
}
}
}
// MediaProvider
if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
val type = split[0]
var contentUri: Uri? = null
when (type) {
"image" -> {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
"video" -> {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
"audio" -> {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
}
selection = "_id=?"
selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri!!, selection, selectionArgs)
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(context,uri)
}
if (isWhatsAppFile(uri)) {
return getFilePathForWhatsApp(context, uri)
}
if ("content".equals(uri.scheme, ignoreCase = true)) {
if (isGooglePhotosUri(uri)) {
return uri.lastPathSegment
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(context, uri)
}
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// return getFilePathFromURI(context,uri);
copyFileToInternalStorage(context, uri, "userfiles")
// return getRealPathFromURI(context,uri);
} else {
getDataColumn(context, uri, null, null)
}
}
if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}
} else {
if (isWhatsAppFile(uri)) {
return getFilePathForWhatsApp(context, uri)
}
if ("content".equals(uri.scheme, ignoreCase = true)) {
val projection = arrayOf(MediaStore.Images.Media.DATA)
val cursor: Cursor
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)!!
val columnIndex: Int = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
if (cursor.moveToFirst()) {
return cursor.getString(columnIndex)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
return null
}
private fun fileExists(filePath: String): Boolean {
val file = File(filePath)
return file.exists()
}
private fun getPathFromExtSD(pathData: Array<String>): String {
val type = pathData[0]
val relativePath = "/" + pathData[1]
var fullPath : String
// on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
// something like "71F8-2C0A", some kind of unique id per storage
// don't know any API that can get the root path of that storage based on its id.
//
// so no "primary" type, but let the check here for other devices
if ("primary".equals(type, ignoreCase = true)) {
fullPath = Environment.getExternalStorageDirectory().toString() + relativePath
if (fileExists(fullPath)) {
return fullPath
}
}
// Environment.isExternalStorageRemovable() is `true` for external and internal storage
// so we cannot relay on it.
//
// instead, for each possible path, check if file exists
// we'll start with secondary storage as this could be our (physically) removable sd card
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath
if (fileExists(fullPath)) {
return fullPath
}
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath
return if (fileExists(fullPath)) {
fullPath
} else fullPath
}
private fun getDriveFilePath(context: Context, uri: Uri): String? {
val returnUri: Uri = uri
val returnCursor: Cursor = context.contentResolver.query(returnUri, null, null, null, null)!!
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
val nameIndex: Int = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
// val sizeIndex: Int = returnCursor.getColumnIndex(OpenableColumns.SIZE)
returnCursor.moveToFirst()
val name: String = returnCursor.getString(nameIndex)
// val size = returnCursor.getLong(sizeIndex).toString()
val file = File(context.cacheDir, name)
try {
val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
val outputStream = FileOutputStream(file)
var read : Int
val maxBufferSize = 1 * 1024 * 1024
val bytesAvailable: Int = inputStream?.available()!!
//int bufferSize = 1024;
val bufferSize = min(bytesAvailable, maxBufferSize)
val buffers = ByteArray(bufferSize)
while (inputStream.read(buffers).also { read = it } != -1) {
outputStream.write(buffers, 0, read)
}
Timber.d("File Size Size ${file.length()}")
inputStream.close()
outputStream.close()
Timber.d("File Path Path ${file.path}")
Timber.d("File Size Size ${file.length()}")
} catch (e: Exception) {
Timber.e("Exception ${e.message}")
}
return file.path
}
/***
* Used for Android Q+
* #param uri
* #param newDirName if you want to create a directory, you can set this variable
* #return
*/
private fun copyFileToInternalStorage(context: Context, uri: Uri, newDirName: String): String? {
val returnUri: Uri = uri
val returnCursor: Cursor = context.contentResolver.query(returnUri, arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE), null, null, null)!!
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
val nameIndex: Int = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
//val sizeIndex: Int = returnCursor.getColumnIndex(OpenableColumns.SIZE)
returnCursor.moveToFirst()
val name: String = returnCursor.getString(nameIndex)
// val size = returnCursor.getLong(sizeIndex).toString()
val output: File = if (newDirName != "") {
val dir = File(context.filesDir.toString() + "/" + newDirName)
if (!dir.exists()) {
dir.mkdir()
}
File(context.filesDir.toString() + "/" + newDirName + "/" + name)
} else {
File(context.filesDir.toString() + "/" + name)
}
try {
val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
val outputStream = FileOutputStream(output)
var read = 0
val bufferSize = 1024
val buffers = ByteArray(bufferSize)
while (inputStream?.read(buffers).also {
if (it != null) {
read = it
}
} != -1) {
outputStream.write(buffers, 0, read)
}
inputStream?.close()
outputStream.close()
} catch (e: Exception) {
Timber.e("Exception${e.message}")
}
return output.path
}
private fun getFilePathForWhatsApp(context: Context, uri: Uri): String? {
return copyFileToInternalStorage(context, uri, "whatsapp")
}
private fun getDataColumn(context: Context, uri: Uri, selection: String?, selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val index: Int = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
private fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
private fun isWhatsAppFile(uri: Uri): Boolean {
return "com.whatsapp.provider.media" == uri.authority
}
private fun isGoogleDriveUri(uri: Uri): Boolean {
return "com.google.android.apps.docs.storage" == uri.authority || "com.google.android.apps.docs.storage.legacy" == uri.authority
}
}
To launch
val intent = Intent(ACTION_GET_CONTENT)
intent.apply {
type = "application/pdf"
addCategory(Intent.CATEGORY_OPENABLE)
}
resultLauncher.launch(intent)
and you can get the result in your acivity
private val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
var file: File? = null
val disposable = Single.fromCallable {
val filePath = FileManager.getPath(this, result?.data?.data!!)
file = File(filePath)
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe({
Timber.d("==File==Path===${file?.path}\nname==${file?.name}\nabsolutePath =${file?.absolutePath}")
}, {
it.printStackTrace()
})
}
}
You will not try yo convert an uri to a file system path in Android 10.
Even if you manage the path is mostly not accessable.
You are not a regular reader of stackoverflow pages are you?
I have create custom incoming call screen that can current show the name and phone number of an incoming call. If the contact has a profile pic set that image should display in the ImageView. I calls the below method, and assigns the picture to the ImageView. The problem is that the else statement is always executed:
public static Uri getPhotoUri(String savedNumber, Context context) {
try {
Cursor cur = context
.getContentResolver()
.query(
ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID
+ "="
+ getContactIDFromNumber(savedNumber,
context)
+ " AND "
+ ContactsContract.Data.MIMETYPE
+ "='"
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
+ "'", null, null);
if (cur != null) {
if (!cur.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,
getContactIDFromNumber(savedNumber, context));
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}
public static int getContactIDFromNumber(String contactNumber,Context context) {
int phoneContactID = 0;
Cursor contactLookupCursor = context.getContentResolver().query(
Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(contactNumber)),
new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup._ID},
null, null, null);
try {
contactLookupCursor.moveToFirst();
while (contactLookupCursor.moveToNext()) {
phoneContactID = contactLookupCursor.getInt(contactLookupCursor
.getColumnIndexOrThrow(ContactsContract.PhoneLookup._ID));
}
} finally {
contactLookupCursor.close();
}
return phoneContactID;
}
IncomingActivity:
#Override
protected void onResume() {
super.onResume();
callerNumber.setText(savedNumber);
callerName.setText(CommonMethods.getCallerName(savedNumber, this));
callerImageUri = CommonMethods.getPhotoUri(savedNumber, this);
if (callerImageUri != null) {
callerImage.setImageURI(callerImageUri);
} else {
callerImage.setImageResource(R.drawable.contact_default);
}
}
Does anyone have any ideas as to why "callerInamgeUri" is remaining null?
I am new to Android and Java and this week I've been doing a self-taught crash course. So far what I've learned has not been too complicated as I've already built a number of years of coding experience. So, background history out of the way, onto my question.
The below code is two functions I wrote to take an image ID from a database and parse the correct Uri which I can then use to upload the photo to a website. So could you kind folks look over my code and let me know if I'm doing a terrible job or if I am heading in the right direction or even if there is a better/native way to do what I need.
Also, note: the below code does work. I just don't know if it is the right way to do it.
Thanks!
// Usage Map idPath = ImageIdPathFetcher.getRealIdPathFromID(getApplicationContext(), Integer.valueOf(image_id));
public static Map getRealIdPathFromID(Context context, Integer id) {
Map<String,String> idPath = new HashMap<String, String>();
Uri external_images_uri = MediaStore.Images.Media.getContentUri("external");
Uri internal_images_uri = MediaStore.Images.Media.getContentUri("internal");
// initialize uri
Uri uri = external_images_uri;
String ext_img_uri = external_images_uri.toString()+"/"+id;
String int_img_uri = internal_images_uri.toString()+"/"+id;
if(check_uri(context, ext_img_uri))
{
uri = Uri.parse(ext_img_uri);
}else if(check_uri(context, int_img_uri))
{
uri = Uri.parse(int_img_uri);
}else {
idPath.put("id", "");
idPath.put("path", "");
return idPath;
}
String[] proj = { Media.DATA, Media._ID };
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(Media.DATA);
cursor.moveToFirst();
String filepath = cursor.getString(column_index);
idPath.put("id", id.toString());
idPath.put("path", filepath);
return idPath;
}
public static boolean check_uri(Context context, String uri)
{
try{
ContentResolver cr = context.getContentResolver();
String[] projection = {MediaStore.MediaColumns.DATA};
Cursor cur = cr.query(Uri.parse(uri), projection, null, null, null);
if(cur != null)
{
cur.moveToFirst();
String filePath = cur.getString(0);
if(! new File(filePath).exists()){
return false;
}
} else {
return false;
}
} catch (Exception e)
{
return false;
}
return true;
}
This is what I use
public static Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID},
MediaStore.Images.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(id));
}
} finally {
cursor.close();
}
}
cursor = context.getContentResolver().query(
MediaStore.Images.Media.INTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID},
MediaStore.Images.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(MediaStore.Images.Media.INTERNAL_CONTENT_URI, String.valueOf(id));
}
} finally {
cursor.close();
}
}
return null;
}
It is possible to query both internal and external MediaStore database also with MergeCursor:
String myIdImgStr = "123"; // the unique ID of the image in the MediaStore
ContentResolver contentResolver = this.getContext().getContentResolver();
String [] proj = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID };
MergeCursor cursor = new MergeCursor(new Cursor[] {
MediaStore.Images.Media.query(contentResolver,
Uri.parse(MediaStore.Images.Media.INTERNAL_CONTENT_URI + "/" + myIdImgStr),
proj),
MediaStore.Images.Media.query(contentResolver,
Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + myIdImgStr),
proj)
});
if(cursor.getCount() == 1) {
cursor.moveToFirst();
String filepath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
I am trying to retrieve contact names given the contact phone number. I made a function that should work in all API versions, by I can't make it work in 1.6 and I can't see the problem, maybe someone can spot it?
Note that, I've replaced the API constants for strings so I don't have deprecated warning problems.
public String getContactName(final String phoneNumber)
{
Uri uri;
String[] projection;
if (Build.VERSION.SDK_INT >= 5)
{
uri = Uri.parse("content://com.android.contacts/phone_lookup");
projection = new String[] { "display_name" };
}
else
{
uri = Uri.parse("content://contacts/phones/filter");
projection = new String[] { "name" };
}
uri = Uri.withAppendedPath(uri, Uri.encode(phoneNumber));
Cursor cursor = this.getContentResolver().query(uri, projection, null, null, null);
String contactName = "";
if (cursor.moveToFirst())
{
contactName = cursor.getString(0);
}
cursor.close();
cursor = null;
return contactName;
}
This seems to work fine in the latest versions:
private String getContactName(Context context, String number) {
String name = null;
// define the columns I want the query to return
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup._ID};
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
// query time
Cursor cursor = context.getContentResolver().query(contactUri, projection, null, null, null);
if(cursor != null) {
if (cursor.moveToFirst()) {
name = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
Log.v(TAG, "Started uploadcontactphoto: Contact Found # " + number);
Log.v(TAG, "Started uploadcontactphoto: Contact name = " + name);
} else {
Log.v(TAG, "Contact Not Found # " + number);
}
cursor.close();
}
return name;
}
Use reflections instead of comparing sdk version.
public String getContactName(final String phoneNumber)
{
Uri uri;
String[] projection;
mBaseUri = Contacts.Phones.CONTENT_FILTER_URL;
projection = new String[] { android.provider.Contacts.People.NAME };
try {
Class<?> c =Class.forName("android.provider.ContactsContract$PhoneLookup");
mBaseUri = (Uri) c.getField("CONTENT_FILTER_URI").get(mBaseUri);
projection = new String[] { "display_name" };
}
catch (Exception e) {
}
uri = Uri.withAppendedPath(mBaseUri, Uri.encode(phoneNumber));
Cursor cursor = this.getContentResolver().query(uri, projection, null, null, null);
String contactName = "";
if (cursor.moveToFirst())
{
contactName = cursor.getString(0);
}
cursor.close();
cursor = null;
return contactName;
}
public static String getContactName(Context context, String phoneNumber)
{
ContentResolver cr = context.getContentResolver();
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cr.query(uri, new String[]{PhoneLookup.DISPLAY_NAME}, null, null, null);
if (cursor == null)
{
return null;
}
String contactName = null;
if(cursor.moveToFirst())
{
contactName = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
}
if(cursor != null && !cursor.isClosed()) {
cursor.close();
}
return contactName;
}
private String getContactNameFromNumber(String number) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
Cursor cursor = context.getContentResolver().query(uri, new String[]{PhoneLookup.DISPLAY_NAME},null,null,null);
if (cursor.moveToFirst())
{
name = cursor.getString(cursor.getColumnIndex(PhoneLookup.D