I tried to take a photo and then to use the photo. Here is what I did.
My device was Nexus 6P (Android 7.1.1).
First, I created a Uri
:
Uri mPicPath = UriUtil.fromFile(this, UriUtil.createTmpFileForPic());
//Uri mPicPath = UriUtil.fromFile(this, UriUtil.createFileForPic());
And then, I started Intent
:
Intent intent = ActivityUtils.getTakePicIntent(mPicPath);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, RequestCode.TAKE_PIC);
}
At last, I handled this Uri
on onActivityResult
:
if (requestCode == RequestCode.TAKE_PIC) {
if (resultCode == RESULT_OK && mPicPath != null) {
Bitmap requireBitmap = BitmapFactory.decodeFile(mPicPath.getPath());
//path is like this: /Download/Android/data/{@applicationId}/files/Pictures/JPEG_20170216_173121268719051242.jpg
requireBitmap.recycle();//Here NPE was thrown.
}
}
At the meantime, Here are UriUtil
:
public class UriUtil {
public static File createFileForPic() throws IOException {
String fileName = "JPEG_" + new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.getDefault()).format(new Date()) + ".jpg";
File storageDic = SPApplication.getInstance().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return new File(storageDic, fileName);
}
public static File createTmpFileForPic() throws IOException {
String fileName = "JPEG_" + new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.getDefault()).format(new Date());
File storageDic = SPApplication.getInstance().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(fileName, ".jpg", storageDic);
}
public static Uri fromFile(@NonNull Context context, @NonNull File file) {
if (context == null || file == null) {
throw new RuntimeException("context or file can't be null");
}
if (ActivityUtils.requireSDKInt(Build.VERSION_CODES.N)) {
return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".file_provider", file);
} else {
return Uri.fromFile(file);
}
}
}
and getTakePicIntent(Uri)
:
public static Intent getTakePicIntent(Uri mPicPath) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPicPath);
if (!ActivityUtils.requireSDKInt(Build.VERSION_CODES.KITKAT_WATCH)) {//in pre-KitKat devices, manually grant uri permission.
List<ResolveInfo> resInfoList = SPApplication.getInstance().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
SPApplication.getInstance().grantUriPermission(packageName, mPicPath, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
} else {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
return intent;
}
and requireSDKInt
:
public static boolean requireSDKInt(int sdkInt) {
return Build.VERSION.SDK_INT >= sdkInt;
}
Everything worked on different Android API except on Android Nougat(7.x.x). Even 'FileProvider' was provided, 'requireBitmap' always be returned as 'null'.
After logs read, FileNotFoundException
was thrown from BitmapFactory
. It was like:
BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /Download/Android/data/{@applicationId}/files/Pictures/JPEG_20170216_1744551601425984925.jpg (No such file or directory)
It seems all is clear, but I still can't understand that.
How could it be? Clearly I created a File
! How could I solve that? Any ideas?
The ImageView class is pointed at a bitmap stored under one of the drawable folders in the res project folders. Start by creating a basic app project that will contain the ImageView and bitmap to display. Here the new project created in Android Studio is called Bitmap and an Empty Activity used.
insertImage(inContext. getContentResolver(), inImage, "Title", null); the line mentioned above create a thumbnail using bitmap, that may consume some extra space in your android device. This method may help you to get the Uri from bitmap without consuming some extra memory.
Choose the most appropriate decode method based on your image data source. These methods attempt to allocate memory for the constructed bitmap and therefore can easily result in an OutOfMemory exception. Each type of decode method has additional signatures that let you specify decoding options via the BitmapFactory.
Bitmap is a ready image ( set of bytes with color data ) and URI is a path to something. URI can be /emulated/home/... , can be http://google.com and so on.
I tried your code. Here's the sample of my try.https://github.com/raghunandankavi2010/SamplesAndroid/tree/master/StackOverFlowTest.
Have a look at this blog https://commonsware.com/blog/2016/03/15/how-consume-content-uri.html
In the blog commonsware mentions that you should not do new File (mPicPath.getPath())
.
Instead you should use the below in onActivityResult
try {
InputStream ims = getContentResolver().openInputStream(mPicPath);
// just display image in imageview
imageView.setImageBitmap(BitmapFactory.decodeStream(ims));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
And the xml
<external-files-path name="external_files" path="path" />
Note: its a content uri that you have. On my phone i get the uri as below. Tested only on Nexus6p.
content://com.example.raghu.stackoverflowtest.fileProvider/external_files/Pictures/JPEG_20170424_161429691143693160.jpg
More on file provider https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Try this function may be you get path from it. This is works for me
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getRealPathFromURI_API19(Context context, Uri uri) {
if (HelperFunctions.isExternalStorageDocument(uri)) {
// ExternalStorageProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
} else if (HelperFunctions.isDownloadsDocument(uri)) {
// DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return HelperFunctions.getDataColumn(context, contentUri, null, null);
} else if (HelperFunctions.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;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return HelperFunctions.getDataColumn(context, contentUri, selection,
selectionArgs);
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (HelperFunctions.isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return HelperFunctions.getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
here is my static function HelperFunction class which use above.
public class HelperFunction{
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With