When I launch a Photo Capture intent, the photo path that is gave to me in return is : content://media/external/images/media/40209 but when I look in my device, the photo path should have been something like [..]/pictures/1456164469539.jpg
Do you know how to get the second path from the first ?
note I use the method described there Android ACTION_IMAGE_CAPTURE Intent by yanokwa.
Thanks,
-------------------- EDIT
I launch my intent like so :
private void launchPhotoIntent() {
Uri photoUri = getActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new ContentValues());
Log.i("renaud","photoUri : "+mPhotoUri.toString());
SharedPreferences sharedPreferences = getActivity().getSharedPreferences(AppConstants.SP,Context.MODE_PRIVATE);
sharedPreferences.edit().putString("test",photoUri.toString()).commit();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
getActivity().startActivityForResult(intent, ACTION_TAKE_PHOTO);
}
and In my Callback :
else if(requestCode == PostMessageWindowFragment.ACTION_TAKE_PHOTO && resultCode == Activity.RESULT_OK){
Uri uri = Uri.parse(sharedPreferences.getString("test",null)); // data.getData();
File file = new File(event.uri.getPath());
Log.i("PICTEST",""+file.length());
}
It logs "0"
When I launch a Photo Capture intent, the photo path that is gave to me in return is : content://media/external/images/media/40209
That is not a path. That is a Uri, pointing to content.
the photo path should have been something like [..]/pictures/1456164469539.jpg
Not necessarily.
First, there are thousands of Android device models and thousands of camera apps (both pre-installed and installed by users), some of which implement ACTION_IMAGE_CAPTURE. What one camera app does will not necessarily match what another camera app does.
Second, if you read the documentation for ACTION_IMAGE_CAPTURE, you will notice that there is no "photo path that is gave to me in return". If you supply EXTRA_OUTPUT, your photo should be in that location. If you do not, use getExtra("data") on the Intent passed to onActivityResult() to get a thumbnail bitmap. You appear to be assuming that the Intent will have a Uri, and few camera apps do that.
Do you know how to get the second path from the first ?
That is not possible in general, as a Uri does not have to point to a file, let alone a file that you can access. Use ContentResovler to work with Uri values, such as openInputStream() to read in the content pointed to by a Uri.
The path you get is the file URI. Try with converting it to path using this Convert file: Uri to File in Android
Related
In Android Nougat and above versions the method to capture image from camera intent is changed and following code is working fine for me.
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// File file = new File(AppGlobal.URI_CAPTURED_IMAGE.getPath());
AppGlobal.URI_CAPTURED_IMAGE = FileProvider.getUriForFile(parent, context.getPackageName() + ".provider", AppGlobal.getOutputMediaFile());
}
else
{
AppGlobal.URI_CAPTURED_IMAGE = Uri.fromFile(AppGlobal.getOutputMediaFile());
}
camera.putExtra(MediaStore.EXTRA_OUTPUT, AppGlobal.URI_CAPTURED_IMAGE);
camera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(camera, WritePostFragment.REQUEST_CODE_PHOTO_CAPTURE);
In onActivityResult method I'm able to show the captured image in ImageViews as well.
Glide.with(parent).load(AppGlobal.URI_CAPTURED_IMAGE).centerCrop().into(profilePic_iv);
But when i use the same uri to get File then it says no file exists at given path. What could be the issue? How can i parse the Uri to get File. It seems to be version related stuff.
Sample uri is as follows:
content://com.example.demo.provider/external_files/Camera/IMG_20171213_015646.jpg
How can i parse the Uri to get File
You don't. Moreover, you do not need to. Your file is whatever AppGlobal.getOutputMediaFile() returns. You need to hold onto that value (including putting it in the saved instance state Bundle, in case your process is terminated while the camera app is in the foreground). See this sample app for how to use ACTION_IMAGE_CAPTURE with FileProvider.
in my app i would like to have the user choose an image from the gallery and retrieve the result (thumbnail + full image uri). i would also like the user to be able to choose which gallery app to open (i.e. default gallery app or some other gallery app).
initially, according to this guide by google i copied and pasted this code:
public void selectImage() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_GET);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_GET && resultCode == RESULT_OK) {
Bitmap thumbnail = data.getParcelable("data");
Uri fullPhotoUri = data.getData();
// Do work with photo saved at fullPhotoUri
...
}
}
while it does get me the thumbnail and the full Uri in onActivityResult(...), the problem is that it does not open a chooser for the user to select which gallery app to use and instead it opens this thing (see images below), which i assume is a default "image-chooser" thing where you could select another app via a menu.
i feel it's silly that the user would have to open this default "image chooser" first and once they are already in an "image chooser", select the gallery app that they actually want to use (sure, the user could just choose the image from this thing, but i want to give them a convenient choice).
so i changed my code to this and it does indeed display a proper chooser for the user and he can go straight to hes favorite gallery app:
Intent intent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
if (intent.resolveActivity(getActivity().getPackageManager()) != null)
{
startActivityForResult(intent, Utils.REQUEST_CODE_OPEN_GALLERY);
}
however now i have a new problem: in onActivityResult(...) the line data.getParcelable("data"); returns null. in other words, i don't get back a thumbnail.
i also tried
Bundle extras = data.getExtras();
Bitmap thumbnail = (Bitmap) extras.get("data");
but "extras" is null.
is it possible to have a proper "app chooser" AND get back a thumbnail?
however now i have a new problem: in onActivityResult(...) the line data.getParcelable("data"); returns null. in other words, i don't get back a thumbnail.
You do not get that from ACTION_GET_CONTENT, either. You can tell this by reading the documentation for ACTION_GET_CONTENT. It is certainly possible that there are some buggy ACTION_GET_CONTENT activities that happen to return a thumbnail Bitmap in a "data" extra, but you should not assume that any user will have such a buggy ACTION_GET_CONTENT activity, let alone choose it. Besides, ACTION_GET_CONTENT is not limited to images; what would a "thumbnail" be of application/json or text/csv be?
Likewise, if you read the documentation for ACTION_PICK, you will see that there is no discussion of a thumbnail.
is it possible to have a proper "app chooser" AND get back a thumbnail?
No, insofar as you do not get a thumbnail back from anything except ACTION_IMAGE_CAPTURE, and that is for taking photos.
I made an app. It has 2 options for uploading photo:
1) by taking a photo using camera
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
2) by picking from gallery
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 2);
My problem is getting file path after these intents in onActivityResult.
Is there any methods to get those paths for new File(path) , that also takes care of sdk level changes? For example till KitKat is 1 type of file system , after KitKat is other type.
My problem is getting file path after these intents in onActivityResult.
There will be no file path for the ACTION_IMAGE_CAPTURE approach, because you did not provide EXTRA_OUTPUT. If you do provide EXTRA_OUTPUT, then you already know what the file path is.
There is no file path for ACTION_PICK, insofar as there is no requirement that what the user picks be in a file that you have access to. For example, it could be an image on removable storage. Use a ContentResolver and methods like openInputStream() to get the content represented by the Uri that you are given.
If you can able to get path from camera then for Intent.ACTION_PICK you can directly get uri of image using data.getData() and then you can get file path using this method(as suggested in the link provided by Gennadii Saprykin
public String getRealPathFromURI(Uri uri) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx); }
I'm currently creating a functionnality for the user to upload images to my server. He can either takes pictures with his camera or from his gallery.
I'm using this code to take a picture with the camera :
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
tempFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), ".jpeg", ContextCompat.getExternalCacheDirs(a)[0]);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
And then to manipulate the image I use onActivityResult as such :
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// use tempFile to recreate bitmap and do some heavy-wooshy-wishy stuff
...
}
}
It works totally fine but I'm confused with the Intent data parameter when using the camera. In this case it is null and to use the taken picture I need to re-create it from the path I gave to the ... intent.
What I find especially confusing is that if I don't put any EXTRA_OUTPUT parameter, then the Intent data isn't null and I can easily get the path of the picture with data.getData().
BUT THEN I just get a thumbnail from the original picture.
Is there any way to get the original picture from the camera and the path from the intent ? I don't have any real use case, but let's say the tempFile field gets modified or destroyed when you're taking the picture. Then on onActivityResult you will not be able to use the just taken picture.
What I find especially confusing is that if I don't put any EXTRA_OUTPUT parameter, then the Intent data isn't null and I can easily get the path of the picture with data.getData().
Not generally. There is no requirement for ACTION_IMAGE_CAPTURE to provide you a path to anything. Getting a thumbnail back via the data extra, if you do not provide EXTRA_OUTPUT, is the only "result" that you are supposed to get back in onActivityResult().
Is there any way to get the original picture from the camera and the path from the intent ?
No, because you never get the path from the Intent. It may be that a few camera apps leak this information. Not all will.
but let's say the tempFile field gets modified or destroyed when you're taking the picture
It is your job to not make that sort of mistake. For example, make sure that you retain this value across configuration changes and short-lived process termination, via onSavedInstanceState().
I am trying to figure out the right way to get a file path from the camera after a picture is taken:
Launch the camera intent. Since I am telling the camera to write to internal storage give it the uri and read permission:
File file = new File(context.getFilesDir(), "picture.jpg");
Uri uri = FileProvider.getUriForFile(getApplicationContext(), "my.app.package.fileprovider", file);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, ACTION_IMAGE_CAPTURE_REQUEST_CODE);
Listen for the camera intent result:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
switch (requestCode) {
case ACTION_IMAGE_CAPTURE_REQUEST_CODE:
// How do I get the local path to the file here?
break;
}
}
What is the best way to get the file path on camera intent return. Sure I can save off the file path to a member variable before launching the intent, but that seems bad, seems I should get the path from the onActivityResult.
I have tried this (Get Image path from camera intent):
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(MediaStore.Images.Media.INTERNAL_CONTENT_URI,projection, null, null, null);
int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToLast();
String imagePath = cursor.getString(column_index_data);
Only difference being that I am using INTERNAL_CONTENT_URI as I am trying to store the pic internally. If I do this I get an exception:
Error getting data column
java.lang.IllegalArgumentException: column '_data' does not exist
Am I going about this wrong. I want to take a pic and store that pic in internal storage.
EDIT:
One more thought. Should I be storing pics internally? I am right not because of the new android M permissions. I already have to ask the user for Camera permission, if I store pic to external storage, I have to ask the user for permission to write to to external. Lastly if I store the image externally, it is readable by all applications on the device that can read from external storage. This may be a privacy issue for my app.
What is the best way to get the file path on camera intent return
You specified the file path in EXTRA_OUTPUT. Either the camera put the photo there, or it didn't. If it did, then you already know the file path: new File(context.getFilesDir(), "picture.jpg"). That should be the case the vast majority of the time.
Some camera apps are buggy and will ignore EXTRA_OUTPUT. In those cases:
You can see if the camera app returned a Uri in the Intent passed to onActivityResult(), then use ContentResolver and openInputStream() to begin the process of copying the image to your desired location, or
You can see if the "data" extra exists, in which case that's a Bitmap thumbnail that you can save to your desired location.
In all of these cases, the file path is what you specified; it is merely a question of whether or not it takes additional work for you to get the image there.
Sure I can save off the file path to a member variable before launching the intent, but that seems bad
I have no idea why you would think that.
seems I should get the path from the onActivityResult
You are welcome to believe whatever you want. Camera app developers are hopefully reading the documentation for ACTION_IMAGE_CAPTURE. That documentation does not state that the camera app has to return anything if you provide EXTRA_OUTPUT. Hence, many camera apps will not return anything.
UPDATE based on edit:
Should I be storing pics internally?
Um, you already are.
if I store pic to external storage, I have to ask the user for permission to write to to external
That depends on where you are writing. getExternalFilesDir(), getExternalCacheDir(), and kin from Context do not require a permission on Android 4.4+. The methods you call on Environment for external storage locations (e.g., getExternalStoragePublicDirectory()) do require WRITE_EXTERNAL_STORAGE, which is a dangerous permission and would need to be requested at runtime.