Getting an image from Gallery on from the Picasa//Google + synced folders doesn't work
Solution 1:
I wasted now lots of hours and now i found a solution which works in all cases without any magic downloading in special threads or something. The following method returns a stream from the content which the user selected and this works with everything in the wild.
FileInputStream getSourceStream(Uri u) throws FileNotFoundException {
FileInputStream out = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ParcelFileDescriptor parcelFileDescriptor =
mContext.getContentResolver().openFileDescriptor(u, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
out = new FileInputStream(fileDescriptor);
} else {
out = (FileInputStream) mContext.getContentResolver().openInputStream(u);
}
return out;
}
Solution 2:
After a lot of research, I felt that there were too many workarounds to do something which seems to be quite simple. So, I went ahead a wrote a small library that handles all the complex if elses and happens to work for all possible scenarios that I can think of. Do give it a try and see if this helps.
http://techdroid.kbeanie.com/2013/03/easy-image-chooser-library-for-android.html
This is an initial implementation. Although it handles almost every situation, there could be a few bugs. If you use this library, please let me know your feedback and if at all it could be improved any further.
Solution 3:
I faced the same problem about year ago.. I show you my solution (code is quite messy, please refactor it). So, you have the image URI which was returned from gallery:
ImageInfo getImage(URI imageUri) {
ImageInfo result = null;
final String[] cursorColumns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION};
// some devices (OS versions return an URI of com.android instead of com.google.android
if (imageUri.toString().startsWith("content://com.android.gallery3d.provider")) {
// use the com.google provider, not the com.android provider.
imageUri = Uri.parse(imageUri.toString().replace("com.android.gallery3d","com.google.android.gallery3d"));
}
Cursor cursor = App.getContext().getContentResolver().query(imageUri, cursorColumns, null, null, null);
if (cursor != null) {
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
int orientationColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);
cursor.moveToFirst();
// if it is a picasa image on newer devices with OS 3.0 and up
if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {
result = new ImageInfo(downloadImage(imageUri), "0");
} else { // it is a regular local image file
result = new ImageInfo(cursor.getString(dataColumnIndex), cursor.getString(orientationColumnIndex));
}
cursor.close();
} else {
result = new ImageInfo(downloadImage(imageUri), "0");
}
return result;
}
And now we need function to download image:
private String downloadImage(URI imageUri) {
File cacheDir;
// if the device has an SD card
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),".OCFL311");
} else {
// it does not have an SD card
cacheDir = App.getContext().getCacheDir();
}
if(!cacheDir.exists()) cacheDir.mkdirs();
File f = new File(cacheDir, PUT_HERE_FILE_NAME_TO_STORE_IMAGE);
try {
InputStream is = null;
if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {
is = App.getContext().getContentResolver().openInputStream(imageUri);
} else {
is = new URL(imageUri.toString()).openStream();
}
OutputStream os = new FileOutputStream(f);
Utils.InputToOutputStream(is, os);
return f.getAbsolutePath();
} catch (Exception ex) {
Log.d(this.getClass().getName(), "Exception: " + ex.getMessage());
// something went wrong
ex.printStackTrace();
return null;
}
}
ImageInfo is my class to store path to image and its orientation.
public static class ImageInfo {
public final String filePath;
public final String imageOrientation;
public ImageInfo(String filePath, String imageOrientation) {
this.filePath = filePath;
if (imageOrientation == null) imageOrientation = "0";
this.imageOrientation = imageOrientation;
}
}
Solution 4:
Based on @drindt answer, below codes give downloaded temporary File
path from Google Photo cloud-synced-but-not-in-device file.
@SuppressLint("NewApi")
public static String getFilePath(final Context context, final Uri uri) {
// Google photo uri example
// content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2FAF1QipMObgoK_wDY66gu0QkMAi/ORIGINAL/NONE/114919
if ("content".equalsIgnoreCase(uri.getScheme())) {
String result = getDataColumn(context, uri, null, null); //
if (TextUtils.isEmpty(result))
if (uri.getAuthority().contains("com.google.android")) {
try {
File localFile = createImageFile(context, null);
FileInputStream remoteFile = getSourceStream(context, uri);
if(copyToFile(remoteFile, localFile))
result = localFile.getAbsolutePath();
remoteFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
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;
}
/**
* Copy data from a source stream to destFile.
* Return true if succeed, return false if failed.
*/
private static boolean copyToFile(InputStream inputStream, File destFile) {
if (inputStream == null || destFile == null) return false;
try {
OutputStream out = new FileOutputStream(destFile);
try {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} finally {
out.close();
}
return true;
} catch (IOException e) {
return false;
}
}
public static String getTimestamp() {
try {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ROOT).format(new Date());
} catch (RuntimeException e) {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
}
}
public static File createImageFile(Context context, String imageFileName) throws IOException {
if (TextUtils.isEmpty(imageFileName))
imageFileName = getTimestamp(); // make random filename if you want.
final File root;
imageFileName = imageFileName;
root = context.getExternalCacheDir();
if (root != null && !root.exists())
root.mkdirs();
return new File(root, imageFileName);
}
public static FileInputStream getSourceStream(Context context, Uri u) throws FileNotFoundException {
FileInputStream out = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(u, "r");
FileDescriptor fileDescriptor = null;
if (parcelFileDescriptor != null) {
fileDescriptor = parcelFileDescriptor.getFileDescriptor();
out = new FileInputStream(fileDescriptor);
}
} else {
out = (FileInputStream) context.getContentResolver().openInputStream(u);
}
return out;
}
Solution 5:
Below trick worked for me, what i am doing here is if there is any authority url in URI, then i am creating a temporary image using below code & returning the Content URI of the same.
I have answered similar question here as well..
public static String getImageUrlWithAuthority(Context context, Uri uri) {
InputStream is = null;
if (uri.getAuthority() != null) {
try {
is = context.getContentResolver().openInputStream(uri);
Bitmap bmp = BitmapFactory.decodeStream(is);
return writeToTempImageAndGetPathUri(context, bmp).toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}