I'm having serious problems getting a picture coming from an IntentChooser. It lets you choose between getting a picture from the camera or your drive:
Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);
boolean cameraAvailable = isCameraAvailable(this);
String pickTitle = cameraAvailable? "Select or take a new Picture" : "Select a Picture";
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
if(cameraAvailable)
{
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
chooserIntent.putExtra
(
Intent.EXTRA_INITIAL_INTENTS,
new Intent[] { takePhotoIntent }
);
}
startActivityForResult(chooserIntent, GET_PICTURE);
Where isCameraAvailable(Context context) checks if there is a camera waiting in the system.
The problem is that, when in onActivityResult, both intents (take picture or get picture from gallery) have, of course, the same requestCode, so I have to make a difference in another way. I've found out that the intent coming from the camera, has an action of inline-data, while the other just has no action at all:
if(intent.getAction() == "inline-data")
{
bitmap = (Bitmap) intent.getExtras().get("data");
}
else
{
InputStream stream = getContentResolver().openInputStream(
intent.getData());
bitmap = BitmapFactory.decodeStream(stream);
stream.close();
}
Now, the problem comes that I'm not pretty sure this is the best solution to differentiate, and I was thinking if there is a way to check the complete action (MediaStore.ACTION_IMAGE_CAPTURE or Intent.ACTION_GET_CONTENT) or another one. Thanks in advance.
Tiny edit: In my case, which consists in grabbing a picture from anywhere or create it from scratch, the example just works, but for the sake of improving my code (and finding a more generic answer) I'll leave it open to suggestions.
Related
I have the following code which request user to pick an image from photo apps or capture an image by camera apps:
// Camera
final List<Intent> cameraIntents = new ArrayList<Intent>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = fragment.getActivity().getPackageManager();
final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for(ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(packageName);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
cameraIntents.add(intent);
}
// Filesystem.
final Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
// Chooser of filesystem options.
final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");
// Add the camera options.
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
fragment.startActivityForResult(chooserIntent, UPLOAD_IMAGE_ACTIVITY_REQUEST_CODE);
And my code of onActivityResult:
if(requestCode == UPLOAD_IMAGE_ACTIVITY_REQUEST_CODE)
{
final boolean isCamera;
if(data == null)
{
isCamera = true;
}
else
{
final String action = data.getAction(); // data is always empty here after capture image by default camera in 5.1.1!
if(action == null)
{
isCamera = false;
}
else
{
isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
}
}
//do sth according to value of isCamera
}
These codes work well in the previous android versions. However, when I updated my nexus 5 to Android 5.1.1 (together updating the camera app to latest version), the codes doesn't work well when requesting default camera to capture photos.
According to debugger, when the code reaches final String action = data.getAction(); after capturing an image by the default camera app, the result Intent data is always an empty Intent (not null though) that contains no action , extras, data, etc. So final String action = data.getAction(); always return null and fails my following codes.
I guess something is changed for the default camera app in 5.1.1 so the camera intent behavior is different. But then I get no idea on how to make it works.
Any suggestions would be appreciate. Thanks!
I have added one more condition. It seems working fine without any problem in 5.1.1 as well as in different API levels
if(data == null){
isCamera = true;
}else if(data.getData() == null){
isCamera = true;
}
else{
//....
Your guess is correct, there is a change in Lollipop: http://developer.android.com/reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE
public static final String ACTION_IMAGE_CAPTURE
Added in API level 3
Standard Intent action that can be sent to have the camera application capture an image and return it.
The caller may pass an extra EXTRA_OUTPUT to control where this image will be written. If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap object in the extra field. This is useful for applications that only need a small image. If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri value of EXTRA_OUTPUT. As of LOLLIPOP, this uri can also be supplied through setClipData(ClipData). If using this approach, you still must supply the uri through the EXTRA_OUTPUT field for compatibility with old applications. If you don't set a ClipData, it will be copied there for you when calling startActivity(Intent).
You need to set the ClipData in the intent, that's how i do it
intent.setClipData(ClipData.newRawUri(null, Uri.fromFile(file)));
in your case i think it is
intent.setClipData(ClipData.newRawUri(null, outputFileUri));
Also i don't set MediaStore.EXTRA_OUTPUT, because for me it returns null data, i dont't know how you don't get a null data, setting MediaStore.EXTRA_OUTPUT, but that's another thing: Camera activity returning null android
I got same issue and i added
mFileTemp.getParentFile().mkdirs();
before passing uri to intent and its resolved for me.
I found the solution of this after some research and testing.
The solution is to make either file or path of file object in static while creating temp file.
private static String path;
private File createImageFile() throws IOException {
File storageDir = Environment.getExternalStorageDirectory();
File image = File.createTempFile(
"hoivia_image", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
path=image.getpath();
return image;
}
This might be happening because the current activity objects become null at onActivityResult().
Hope it helps you.
I am trying to pick an image from the Android Gallery only, not other applications like Photos, file manager etc
I need a solution to open the Gallery App directly, or is it possible to use the Photos Application to pick image?
1) Choose from gallery
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
startActivityForResult(intent,CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
2) onActivityResult result code
try {
// bimatp factory
BitmapFactory.Options options = new BitmapFactory.Options();
// downsizing image as it throws OutOfMemory Exception for larger images
options.inSampleSize = 2;
final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),options);
descimage.setImageBitmap(bitmap);
bitmap.compress(CompressFormat.JPEG, 80, new FileOutputStream(new File(fileUri.getPath())));
photostatus = 1;
pbar.setVisibility(View.VISIBLE);
txtbrowser.setEnabled(false);
new upload().execute();
} catch (NullPointerException e) {
e.printStackTrace();
}
You should be aware that Gallery no longer exists on some devices running Lollipop. The photos app is the replacement and it should have no problems handling the intent to select an image. Intent.ACTION_GET_CONTENT is usually recommended for selecting images, such as:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, ID);
Opening the gallery on devices that do have it installed is discussed here. Basically every different vendor may ship a different gallery app.
It is possible to launch a specific activity for an implicit intent (such as selecting an image) without showing the chooser dialog by using the PackageManager.queryIntentActivities() API to iterate all the available packages on the users device so you can explicitly launch the one you require.
This intent allows you to pick the image from the default gallery.
// in onCreate or any event where your want the user to select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
For receiving the selected image in onActivityResult()
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
}
}
}
i got the solution from here
so I have the code below working fine until android 4.4. I was able to get the path from the uri by intent.getData() in onActivityResult then do something special about the uri to get the path of the photo that was selected.
private Intent createPhotoIntent() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
Intent chooser = createPhotoChooserIntent(createPhotoFromCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, intent);
return chooser;
}
private Intent createPhotoChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE, "Please Choose Your Image");
return chooser;
}
private Intent createPhotoFromCameraIntent() {
return new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
}
what I dont understand is why I'm not able to get anything from intent.getData() now?? I also insert a line break to check what I received from the intent in onActivityResult, and I see nothing related to the path. I was able to see content://media/external/images/media/1249 but not anymore now....what happen to android 4.4!!??
please help.
I am trying to programatically launch or open the photo gallery after passing a photo name search parameter.
I am new at this. I am thinking maybe intents can be used but not sure so I am wondering if anyone could please point me in the right direction. Preferably with some code examples.
Much thanks.
RE-EDIT
As requested, this is the code I have so far..
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
// CAMERA_PIC_REQUEST = 2600;
cameraIntent = Intent.createChooser(intent,"Select Picture");
you can try follow code:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(photoUri);
context.startActivity(intent);
I think this is what you mean, correct me if I'm wrong:
String nameOfPhotoToBeRetrieved = "myPhoto";
String WHERE = "TITLE ="+nameOfPhotoToBeRetrieved;
Then you can use the following line to deliver a result to your cursor/listener:
CursorLoader(context,content_uri,null,WHERE,null,null).deliverResult(myCursor);
I'm developing an app for Android 2.1 upwards. I want to enable my users to select a profile picture within my app (I'm not using the contacts framework).
The ideal solution would be to fire an intent that enables the user to select an image from the gallery, but if an appropriate image is not available then use the camera to take a picture (or vice-versa i.e. allow user to take picture but if they know they already have a suitable image already, let them drop into the gallery and pick said image).
Currently I can do one or the other but not both.
If I go directly into camera mode using MediaStore.ACTION_IMAGE_CAPTURE then there is no option to drop into the gallery.
If I go directly to the gallery using Intent.ACTION_PICK then I can pick an image but if I click the camera button (in top right hand corner of gallery) then a new camera intent is fired. So, any picture that is taken is not returned directly to my application. (Sure you can press the back button to drop back into the gallery and select image from there but this is an extra unnecessary step and is not at all intuitive).
So is there a way to combine both or am I going to have to offer a menu to do one or the other from within my application? Seems like it would be a common use case...surely I'm missing something?
You can try doing something like this:
// ...
// Within your enclosing Class
// ...
private static final int SELECT_PICTURE = 1;
// ...
Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String pickTitle = "Select or take a new Picture"; // Or get from strings.xml
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra
(
Intent.EXTRA_INITIAL_INTENTS,
new Intent[] { takePhotoIntent }
);
startActivityForResult(chooserIntent, SELECT_PICTURE);
To see how to handle the activitiy's result, please refer to this question
Note: a critical point is how to determine whether the camera or gallery was used. That is shown in this code example: https://stackoverflow.com/a/12347567/294884
UPDATE: The other answer, using EXTRA_INITIAL_INTENTS, is a better one at this point. At the time I wrote my answer, EXTRA_INITIAL_INTENTS did not yet exist, as it was added in API Level 5.
So is there a way to combine both or
am I going to have to offer a menu to
do one or the other from within my
application?
Write your own gallery that has the features you desire.
I would think a menu would be simpler.
Seems like it would be a common use
case...surely I'm missing something?
The developer next to you will think the gallery should allow you to pick from the local gallery or else hop out to Flickr to make a selection from there. Another developer will think the camera should not only allow to "take a picture" via the camera but to "take a picture" via choosing something from the gallery, inverting things from the way you envision it. Yet another developer will think that the gallery should allow picking from the local gallery, or Flickr, or the camera, or a network-attached webcam. Still another developer will think that the gallery is stupid and users should just pick files via a file explorer. And so on.
All of this in an environment (mobile phones) where flash for the OS is at a premium.
Hence, IMHO, it is not completely shocking that the core Android team elected to provide building blocks for you to assemble as you see fit, rather than trying to accommodate every possible pattern.
You can proceed in this way in your Activity:
private static final int REQUEST_CODE_PICTURE= 1;
/**
* Click on View to change photo. Sets into View of your layout, android:onClick="clickOnPhoto"
* #param view View
*/
public void clickOnPhoto(View view) {
Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String pickTitle = "Take or select a photo";
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { takePhotoIntent });
startActivityForResult(chooserIntent, REQUEST_CODE_PICTURE);
}
Then, add always in your Activity the method onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICTURE && resultCode == Activity.RESULT_OK) {
if (data == null) {
return;
}
try {
InputStream inputStream = getContentResolver().openInputStream(data.getData());
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
imgPhoto.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
My Answer is almost identical to #Macarse solution but I also add an additional intent to show gallery apps (Ex: Google Photos) and is written in Kotlin:
val REQUEST_CODE_GET_IMAGE = 101
private fun addProfileImage() {
val pickImageFileIntent = Intent()
pickImageFileIntent.type = "image/*"
pickImageFileIntent.action = Intent.ACTION_GET_CONTENT
val pickGalleryImageIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
val captureCameraImageIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val pickTitle = "Capture from camera or Select from gallery the Profile photo"
val chooserIntent = Intent.createChooser(pickImageFileIntent, pickTitle)
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(captureCameraImageIntent, pickGalleryImageIntent))
startActivityForResult(chooserIntent, REQUEST_CODE_GET_IMAGE)
}
Extract image from result intent:
private var imageTempFile: File? = null
private var imageMimeType: String? = null
private fun extractImage(intent: Intent?) {
val imageUri = intent?.data
imageUri?.let {
Glide.with(this)
.load(imageUri)
.into(profileImageCiv)
imageTempFile = MediaUtils.copyContentFromUriToCacheFile(this, imageUri, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
imageMimeType = MediaUtils.getMimeType(this, imageUri)
} ?: run {
intent?.extras?.get("data")?.let { bitmap -> // Bitmap was returned as raw bitmap
Glide.with(this)
.load(bitmap)
.into(profileImageCiv)
imageTempFile = MediaUtils.writeBitmapToCacheFile(this, bitmap as Bitmap, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
imageMimeType = "image/jpeg" // The bitmap was compressed as JPEG format. The bitmap itself doesn't have any format associated to it
} ?: run {
imageTempFile = null
imageMimeType = null
Log.e("Intent data is null.")
Log.d("Error during photo selection")
}
}
}