String chooseTitle = activity.getString(R.string.select_or_take_picture);
Intent getIntent = new Intent();
getIntent.setType("image/*");
getIntent.setAction(Intent.ACTION_GET_CONTENT);
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
galleryIntent.setType("image/*");
PackageManager pm = activity.getApplicationContext().getPackageManager();
for (ResolveInfo ri: pm.queryIntentActivities(galleryIntent, PackageManager.MATCH_DEFAULT_ONLY)) {
Intent intent = pm.getLaunchIntentForPackage(ri.activityInfo.packageName);
intent.setAction(Intent.ACTION_PICK);
intents.add(intent);
}
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, photoUri);
for (ResolveInfo ri : pm.queryIntentActivities(cameraIntent, 0)) {
Intent intent = pm.getLaunchIntentForPackage(ri.activityInfo.packageName);
intents.add(intent);
}
Intent chooserIntent = Intent.createChooser(getIntent, chooseTitle);
chooserIntent.putExtra(
Intent.EXTRA_INITIAL_INTENTS,
intents.toArray(new Parcelable[] {})
);
By doing this way, the chooser shows:
The camera intent doesn't show at all.
But if I change the line
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, photoUri);
to
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
It works just fine:
But the problem is, I really want to pass photoUri. How can I do with it?
I know a possible alternative is to write my own chooser dialog, but I do want to know if it's a bug in intent chooser, or if I don't use it correctly.
p.s.
#dkarmazi, Here's how I generate Uri:
public Uri generatePhotoUri() {
String timeStamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
String imageFileName = "XXX_" + timeStamp + ".jpg";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File imageFile = new File(storageDir, imageFileName);
return Uri.fromFile(imageFile);
}
Here's my onActivityResult
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case PICK_PHOTO:
if (resultCode != Activity.RESULT_OK) {
break;
}
Uri source = data == null ?
mPhotoUri : // take picture
data.getData(); // choose from other app
if (source == null) {
break;
}
// TODO: do with source
break;
}
//....
}
#dkarmazi, I've debugged it, and I make sure resultCode is RESULT_CANCELED.
I recently worked on the same problem and here is my solution:
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
Then, once the user takes a picture, you should be able to access it by using the provided photoUri
Here is some documentation on EXTRA_OUTPUT and you can also lookup ACTION_IMAGE_CAPTURE on the same page.
UPDATE on Intent Chooser:
// we create intent chooser by picking one of the intents
Intent chooserIntent = Intent.createChooser(cameraIntent, getResources().getString(R.string.pick_action_string_for_user));
// then we add any additional intents
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { getIntent });
// chooserIntent is ready
startActivityForResult(chooserIntent, requestCode);
Thank #dkarmazi very much for helping me debug this issue. It seems we haven't enough reputation to refine the answer together, so I'm posting the solution here. Later in our chat we find a probable cause, and after my experimenting, now it works. It's actually an issue how I gather cameraIntents, so change this part of code
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, photoUri);
for (ResolveInfo ri : pm.queryIntentActivities(cameraIntent, 0)) {
Intent intent = pm.getLaunchIntentForPackage(ri.activityInfo.packageName);
intents.add(intent);
}
to
final Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
for(ResolveInfo ri : pm.queryIntentActivities(cameraIntent, 0)) {
final String packageName = ri.activityInfo.packageName;
final Intent intent = new Intent(cameraIntent);
intent.setComponent(new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name));
intent.setPackage(packageName);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
intents.add(intent);
}
Also need to change
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
galleryIntent.setType("image/*");
PackageManager pm = activity.getApplicationContext().getPackageManager();
for (ResolveInfo ri: pm.queryIntentActivities(galleryIntent, PackageManager.MATCH_DEFAULT_ONLY)) {
Intent intent = pm.getLaunchIntentForPackage(ri.activityInfo.packageName);
intent.setAction(Intent.ACTION_PICK);
intents.add(intent);
}
to
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
galleryIntent.setType("image/*");
PackageManager pm = activity.getApplicationContext().getPackageManager();
for (ResolveInfo ri: pm.queryIntentActivities(galleryIntent, PackageManager.MATCH_DEFAULT_ONLY)) {
final String packageName = ri.activityInfo.packageName;
final Intent intent = new Intent(galleryIntent);
intent.setComponent(new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name));
intent.setPackage(packageName);
intents.add(intent);
}
I hate the boilerplate of it, but finally it works.
Related
I am trying to choose Image from Camera or Gallery and using the following code and want all the gallery options be be availble in the first chooser screen instead of being clubbed under another option.
open fun getImageFromPhone() {
val pickIntent = Intent()
pickIntent.type = "image/*"
pickIntent.action = Intent.ACTION_GET_CONTENT
val takePhotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val galleryIntent = Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
galleryIntent.setType("image/gallery");
val pickTitle = "Select or take a new Picture"
var outputFileUri: Uri? = Uri.fromFile(File.createTempFile(TEMP_FILE, EXTENSION))
val chooserIntent = Intent.createChooser(pickIntent, pickTitle)
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(takePhotoIntent, galleryIntent))
chooserIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri)
startActivityForResult(chooserIntent, CODE_IMG_GALLERY)
}
This leads to showing the following options:
On clicking on Android System I get the gallery options:
However, I want these options(in the above image) to be listed as separate options in the first menu itself.
This method is used to select image source from camera's (ACTION_IMAGE_CAPTURE) or gallery (ACTION_GET_CONTENT). I have posted all related methods, it works perfectly. Just call this Intent as below:
startActivityForResult(getPickImageChooserIntent(activity,"Your Title",false),PICK_IMAGE_CHOOSER_REQUEST_CODE)
public static Intent getPickImageChooserIntent(#NonNull Context context, CharSequence
title, boolean includeDocuments) {
List<Intent> allIntents = new ArrayList<>();
PackageManager packageManager = context.getPackageManager();
// collect all camera intents if Camera permission is available
if (!isExplicitCameraPermissionRequired(context)) {
allIntents.addAll(getCameraIntents(context, packageManager));
}
List<Intent> galleryIntents =
getGalleryIntents(packageManager, Intent.ACTION_GET_CONTENT,includeDocuments);
if (galleryIntents.size() == 0) {
// if no intents found for get-content try pick intent action (Huawei P9).
galleryIntents = getGalleryIntents(packageManager, Intent.ACTION_PICK, includeDocuments);
}
allIntents.addAll(galleryIntents);
Intent target;
if (allIntents.isEmpty()) {
target = new Intent();
} else {
target = allIntents.get(allIntents.size() - 1);
allIntents.remove(allIntents.size() - 1);
}
// Create a chooser from the main intent
Intent chooserIntent = Intent.createChooser(target, title);
// Add all other intents
chooserIntent.putExtra(
Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));
return chooserIntent;
}
public static boolean isExplicitCameraPermissionRequired(#NonNull Context context) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& hasPermissionInManifest(context, "android.permission.CAMERA")
&& context.checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED;
}
/** Get all Camera intents for capturing image using device camera apps. */
public static List<Intent> getCameraIntents(
#NonNull Context context, #NonNull PackageManager packageManager) {
List<Intent> allIntents = new ArrayList<>();
// Determine Uri of camera image to save.
Uri outputFileUri = getCaptureImageOutputUri(context);
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
if (outputFileUri != null) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
}
allIntents.add(intent);
}
return allIntents;
}
/**
* Get all Gallery intents for getting image from one of the apps of the device that handle
* images.
*/
public static List<Intent> getGalleryIntents(
#NonNull PackageManager packageManager, String action, boolean includeDocuments) {
List<Intent> intents = new ArrayList<>();
Intent galleryIntent =
action == Intent.ACTION_GET_CONTENT
? new Intent(action)
: new Intent(action, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
galleryIntent.setType("image/*");
List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
for (ResolveInfo res : listGallery) {
Intent intent = new Intent(galleryIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
intents.add(intent);
}
// remove documents intent
if (!includeDocuments) {
for (Intent intent : intents) {
if (intent
.getComponent()
.getClassName()
.equals("com.android.documentsui.DocumentsActivity")) {
intents.remove(intent);
break;
}
}
}
return intents;
}
/**
* Get URI to image received from capture by camera.
*
* #param context used to access Android APIs, like content resolve, it is your
* activity/fragment/widget.
*/
public static Uri getCaptureImageOutputUri(#NonNull Context context) {
Uri outputFileUri = null;
File getImage = context.getExternalCacheDir();
if (getImage != null) {
outputFileUri = Uri.fromFile(new File(getImage.getPath(), "pickImageResult.jpeg"));
}
return outputFileUri;
}
Im trying to start the choosePictureIntent. This is done by clicking on an image in an Ap
#Override
public void imageClicked(int position) {
if(data.get(position).getImgUri() != null) {
// IGNORE THIS
Intent intent= new Intent(context, FullScreenActivity.class);
intent.putExtra("data", data.get(position));
context.startActivity(intent);
} else {
// THIS IS THE CODE
Object[] chooseData;
chooseData = Utils.getChoosePictureIntent(context, context.getPackageManager());
Intent chooserIntent = (Intent) chooseData[0];
chooserIntent.putExtra("data", data.get(position)); // data is an array of information
chooserIntent.putExtra("outputFileUri", (Uri) chooseData[1]);
((Activity) context).startActivityForResult(chooserIntent, PICTURE_REQUEST);
}
}
When I click on the image, nothing happens, but I know that the else statement gets executed. After that, if I click on the view besides the image, the whole app freezes.
There are no error messages.
Any help is appreciated.
The source of getChoosePictureIntent():
public static String getUniqueFileName(String prefix, String surfix) {
return prefix + System.currentTimeMillis() + surfix;
}
public static Object[] getChoosePictureIntent(Context context, PackageManager manager) {
final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "imagedir" + File.separator);
root.mkdirs();
final String fName = Utils.getUniqueFileName("img_purchase_", ".jpg");
final File sdImageMainDirectory = new File(root, fName);
Uri outputFileUri = Uri.fromFile(sdImageMainDirectory);
// Camera.
final List<Intent> cameraIntents = new ArrayList<Intent>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = manager;
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(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// Chooser of filesystem options.
final Intent chooserIntent = Intent.createChooser(galleryIntent, context.getString(R.string.picture_chooser));
// Add the camera options.
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[cameraIntents.size()]));
return new Object[]{chooserIntent, outputFileUri};
}
If you are using targetSdk >=24, then you need to add File Provider in order to replace the File Uri received from Camera App to Content Uri because API level 24 has blocked File Uri from another app for security reason.You can check out this link for more info
I'm trying to allow my user to pick a picture from the phone gallery or to take a picture with the camera.
I wrote a piece of code working really well on my Samsung S6
private void openPictureIntent() {
final List<Intent> cameraIntents = new ArrayList<>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = 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);
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[cameraIntents.size()]));
startActivityForResult(chooserIntent, SELECT_PICTURE_CODE);
}
Then I tried it on a Nexus 5X and my app crashed. I learned that the intent retrieved in onActivityResult is null with some devices. The solution is to give the uri where to save the image taken with the camera. I implemented it and my code became
private void openPictureIntent() {
// Determine Uri of camera image to save.
final File dir = new File(Environment.getExternalStorageDirectory() + File.separator + "Directory" + File.separator);
dir.mkdirs();
final String fname = UUID.randomUUID() + ".jpg";
final File sdImageMainDirectory = new File(dir, fname);
outputFileUri = Uri.fromFile(sdImageMainDirectory);
new File(outputFileUri.getPath()).delete();
// Camera.
final List<Intent> cameraIntents = new ArrayList<>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = 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[cameraIntents.size()]));
startActivityForResult(chooserIntent, SELECT_PICTURE_CODE);
}
This is working but I'm not satisfied. I would like my photo to be stored with other camera photo and not in a special directory. How could I achieve that ?
I learned that the intent retrieved in onActivityResult is null with some devices.
It is supposed to be null for all camera apps. Some camera app developers fail to read the documentation for ACTION_IMAGE_CAPTURE.
I would like my photo to be stored with other camera photo and not in a special directory
That is not supported by ACTION_IMAGE_CAPTURE.
I am trying to open an android file picker or camera for taking pictures or videos using the following code:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICKFILE_RESULT_CODE && Activity.RESULT_OK == resultCode) {
try {
// Get the Uri of the selected file
Uri uri = data.getData();
LogS.d("File Uri: " + uri.toString());
// Get the path
String path = BeanUtils.getPath(getActivity().getApplicationContext(), uri);
AnnexFile f = new AnnexFile(path);
if (!addedFiles.contains(f)) {
addFileToLayout(f);
addedFiles.add(f);
} else {
Toast.makeText(getActivity(), R.string.you_allready_added_this_file_, Toast.LENGTH_SHORT).show();;
}
} catch (Exception e) {
LogS.e(e);
Toast.makeText(getActivity(), getString(R.string.file_manager_invalid), Toast.LENGTH_LONG).show();
}
} else if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE && Activity.RESULT_OK == resultCode) {
try {
Uri uri = data.getData();
LogS.d("File Uri: " + uri.toString());
// Get the path
String path = BeanUtils.getPath(getActivity().getApplicationContext(), uri);
AnnexFile f = new AnnexFile(path);
if (!addedFiles.contains(f)) {
addFileToLayout(f);
addedFiles.add(f);
} else {
Toast.makeText(getActivity(), R.string.you_allready_added_this_file_, Toast.LENGTH_SHORT).show();;
}
} catch (Exception e) {
LogS.e(e);
Toast.makeText(getActivity(), getString(R.string.file_manager_invalid), Toast.LENGTH_LONG).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void openImageIntent() {
// Camera.
final List<Intent> cameraIntents = new ArrayList<Intent>();
final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = 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);
cameraIntents.add(intent);
}
final Intent videoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
final List<ResolveInfo> listVideoCam = packageManager.queryIntentActivities(videoIntent, 0);
for (ResolveInfo res : listVideoCam){
final String packageName = res.activityInfo.packageName;
final Intent intent = new Intent(videoIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(packageName);
cameraIntents.add(intent);
}
//FileSystem
final Intent galleryIntent = new Intent();
galleryIntent.setType("image/*;video/*");
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[]{}));
startActivityForResult(chooserIntent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
The code works perfect on Samsung S4 and Sony Experia J but fails on Nexus 4 (android 5.1.1). When I debugged the application on nexus 4 I found that the following Uri uri = data.getData(); is null if the end user tries to make a picture. The application works on all devices if the user tries to make a video or to open an existing media file.
When I debugged the application on nexus 4 I found that the following Uri uri = data.getData(); is null if the end user tries to make a picture
You are assuming that ACTION_IMAGE_CAPTURE returns a result in the form of a Uri. It is not documented to do so. There are thousands of camera apps, pre-installed and user-installed. Many of them will advertise support for ACTION_IMAGE_CAPTURE. None have to return a Uri result.
I'm calling image intent method to get the options of camera or gallary while clicking on image view.I found the code here
Allow user to select camera or gallery for image
user David Manpearl
and this is the code I'm using
public static final int YOUR_SELECT_PICTURE_REQUEST_CODE=222;
public void openImageIntent1() {
// Determine Uri of camera image to save.
final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "userDir" + File.separator);
root.mkdirs();
final String fname = "img_"+ System.currentTimeMillis() + ".jpg";
final File sdImageMainDirectory = new File(root, fname);
outputFileUri = Uri.fromFile(sdImageMainDirectory);
// Camera.
final List<Intent> cameraIntents = new ArrayList<Intent>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = this.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[]{}));
startActivityForResult(chooserIntent, 222);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK) {
if(requestCode == 222) {
final boolean isCamera;
if(data == null)
isCamera = true;
else {
final String action = data.getAction();
if(action == null)
isCamera = false;
else
isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
}
Uri selectedImageUri;
if(isCamera)
selectedImageUri = outputFileUri;
else
selectedImageUri = data == null ? null : data.getData();
}
}
}
}
}
In this ,getting error on final PackageManager packageManager = this.getPackageManager() line.
Can you please help?
Thank you
I'm calling this method in another class by making object of this call
Never instantiate an Activity with new. It won't get properly initialized, and calling any activity or context method won't work. So it's no good for anything you'd want to use it for.
Instead, pass in a Context as a parameter to methods that need it like this.
To instantiate an activity, use startActivity() with Intent.