154

What I'm trying to do seems very simple, but after a few days of searching I can't quite figure it out.

I have an application that allows the user to select multiple(up to 5) images. I'm using an ImageView. When the user clicks on the ImageView, I'd like to allow them the option to

  1. Select the image from the gallery, or
  2. Use the camera to capture an image.

I started by using the ACTION_GET_CONTENT intent, and that works well for getting to the gallery. So then I tried using the ACTION_PICK_ACTIVITY intent to allow the user to choose camera or gallery:

Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
Intent gallIntent=new Intent(Intent.ACTION_GET_CONTENT);
gallIntent.setType("image/*"); 
Intent camIntent = new Intent("android.media.action.IMAGE_CAPTURE");
pickIntent.putExtra(Intent.EXTRA_INTENT, camIntent);
pickIntent.putExtra(Intent.EXTRA_INTENT, gallIntent)
pickIntent.putExtra(Intent.EXTRA_TITLE, "Select Source");
startActivityForResult(pickIntent, IMAGE_SELECTOR);

But it appears I can only add one EXTRA_INTENT. The menu show up as expected, but the only options are Gallery and Files....no Camera).

Is there a better/easier way to do this that I'm missing? Thanks for any help.

Mario Velasco
  • 3,178
  • 1
  • 29
  • 48
Wulfgar
  • 1,543
  • 3
  • 10
  • 4
  • FYI similar answer, supplementary to David's superlative answer below. http://stackoverflow.com/a/11676554/294884 thanks again David from everyone!!! – Fattie Jun 02 '14 at 17:01
  • Take a look to this answer with an intent that merges both requests (Camera & Gallery) in a unique Intent: http://stackoverflow.com/a/32475805/2232889 – Mario Velasco Sep 09 '15 at 09:31
  • Simple: Use a library like [this](https://github.com/jrvansuita/PickImage). – Vansuita Jr. Feb 07 '17 at 04:33

17 Answers17

330

How to launch a single Intent to select images from either the Gallery or the Camera, or any application registered to browse the filesystem.

Rather than creating a Dialog with a list of Intent options, it is much better to use Intent.createChooser in order to get access to the graphical icons and short names of the various 'Camera', 'Gallery' and even Third Party filesystem browser apps such as 'Astro', etc.

This describes how to use the standard chooser-intent and add additional intents to that.

private Uri outputFileUri;

private void openImageIntent() {

    // Determine Uri of camera image to save.
    final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "MyDir" + File.separator);
    root.mkdirs();
    final String fname = Utils.getUniqueImageFilename();
    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 = 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(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, YOUR_SELECT_PICTURE_REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == YOUR_SELECT_PICTURE_REQUEST_CODE) {
            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();
            }
        }
    }
}
samis
  • 5,746
  • 6
  • 29
  • 64
David Manpearl
  • 11,858
  • 8
  • 50
  • 69
  • 3
    works nice! but how can I figure out witch source comes the picture from? My actual code only handle the intent correclty if user has choosed the camera. – Lucas Jota Nov 19 '12 at 12:43
  • 1
    Lucas, I added an edit that shows how to determine if the source of the image is the Camera or the Gallery (isCamera) in the 'onActivityResult' method. It also determines the saved image URI which can be very different depending on platform and device. The only sure way to know the camera URI on all devices is to specify it in advance. – David Manpearl Nov 28 '12 at 21:54
  • 12
    Very good! Just a quick improvement: in the first else isCamera = MediaStore.ACTION_IMAGE_CAPTURE.equals(data.getAction()); One line to rule them all ;) – Glatzial Jan 23 '13 at 10:41
  • 1
    I recommend to make the field outputFileUri static, because of the possible orientation change. And.... One line to rule them ALL: Uri selectedImageUri = (intent == null ? true : MediaStore.ACTION_IMAGE_CAPTURE.equals(intent.getAction())) ? outputFileUri : (intent == null ? null : intent.getData()); – peter.bartos Mar 18 '13 at 13:13
  • 1
    This is awesome, thanks. Just 1 small problem, it always uses Holo theme even if all my activities use Holo.Light. How can I change the theme of the popup? Thanks – Darren May 16 '13 at 11:05
  • 8
    In my case `final String fname = Utils.getUniqueImageFilename();` is not working... it says `Utils cannot be resolved`:( – Shajeel Afzal Jul 27 '13 at 09:01
  • 34
    @Shajeel, `Utils.getUniqueImageFilename()` is my own method for generating a unique filename. There are many ways to do it. One of the simplest is to use something like `"img_"+ System.currentTimeMillis() + ".jpg"`. Another is `File.createTempFile()`. – David Manpearl Jul 28 '13 at 04:55
  • ohh got it. What about extensions? can i specify other than .jpg? and is specifying extension is optional or mandatory? – Shajeel Afzal Jul 28 '13 at 12:35
  • Yes, I'm stuck here too.. I need to have the correct extension because the file is then being uploaded to a webserver where it will be displayed.. if the extension is wrong, then It breaks on the webserver. Thanks. – Todd Painton Jul 28 '13 at 16:40
  • I believe that the Android camera can only capture in jpeg format, so you should always use a ".jpg" filename extension (there actually are ways to get native raw formats out of the camera callback, but those are thumbnail size and complicated to decode, so do not go down that path unless absolutely necessary because of pseudo-real-time requirements or similar). – David Manpearl Jul 29 '13 at 21:57
  • 10
    This worked great for me but I had one problem where using the camera as the source was not calling onActivityResult and the camera itself was not dismissing. The root cause was a missing permission in the manifest: – BitsEvolved Sep 01 '13 at 19:38
  • 1
    Thanks for this answer it works great. And thanks to @BitsEvolved for Camera not dismissing, just add to manifest. – jayellos Feb 20 '14 at 08:37
  • 4
    How is this code working for people on KitKat OS 4.4? It seems to have dropped the "Galley" and "Photos" selections and replaced them with "Documents" which isn't very friendly. This post http://androiddev.orkitra.com/?p=128645 seems to say it is the expected behavior but it doesn't seem very good. – Ryan May 30 '14 at 19:11
  • @David, like everyone I say thanks - a critical point for me was to determine **whether the user used the camera or the gallery**. Your "data==null" was the secret for me! THANKS! – Fattie Jun 02 '14 at 17:00
  • 3
    I used this code as it is but isCamara always returns false even if i select camera from chooser intent. Any idea?? – akshay7692 Aug 02 '14 at 13:39
  • @Ryan see Plexus's answer below. – Hackmodford Nov 06 '14 at 18:51
  • 4
    Can any one please tell me why am I getting null for outputFileUri (only when using camera, with gallery it's working fine) ? My test device is Galaxy s2 with Anroid 4.2. – Tina Nov 19 '14 at 13:04
  • 1
    Hey I also want to add Remove Image Button..how to make it possible?? – Akshay Mar 16 '15 at 06:46
  • 6
    Just ran this on 5.1.1. I see data!=null and data.getAction()==null. This causes attaching a camera captured image to fail since the uri is eventually null. Any pointers? – Rohan Jun 15 '15 at 15:22
  • 12
    As Rohan said, this is changed on 5.1.1. You'll need to do `if (data == null || data.getData() == null)`. – Ryan Jun 25 '15 at 22:43
  • 4
    I found it to be `if (data == null || (data.getData() == null && data.getClipData() == null))` as `data.getClipData()` might be not null if the user has chosen multiple images from the library. – ticofab Jul 28 '15 at 16:57
  • 1
    @Tina It is known issue that everybody faces a NullPointerException while working with inbuilt camera application. When we launch the camera it actually restarts our activity which causes outputFileUri to be null. So when we use outputFileUri to display captured image or recorded video, we will get NullPointerException.So in order to fix it we have to use onSaveInstanceState() and onRestoreInstanceState() to retain outputFileUri value. – Swapnil Oct 01 '15 at 07:08
  • 8
    Using `Intent.ACTION_PICK` instead of `Intent.ACTION_GET_CONTENT` will return the more natural Photos app instead of the Documents app in the resulting action chooser. – 92tonywills Dec 07 '15 at 16:45
  • in my case, google camera is not being open when I touch the camera from the chooser. Although both the camera and gallery are being listed in the chooser. I am running android 6.0 Marshmallow. – Sam Dec 10 '15 at 13:58
  • 1
    I try `if (data == null || data.getScheme().equals("file"))` and it works well – Raymond Lukanta May 24 '16 at 16:16
  • Always ended up with empty images with this answer so I had to adapt it: see http://stackoverflow.com/questions/38090474/image-file-is-empty-on-return-from-activity-on-android – Antzi Jul 01 '16 at 08:15
  • This is a nice answer but the result is kind of convoluted. For instance, now I have the option to pick from ES file explorer and Android System. ES file explorer is straight forward but wait until you access Android System, it shows option for ES File Manager, default file explorer, gallery etc. These options are already available before. Now I only wanted to narrow down the option to Gallery, File System + external apps that can access file system (if there is any) and Camera – Neon Warge Jan 25 '17 at 04:26
  • 1
    Hi, When I choose camera, it returns null, just if i pick a from gallery works! –  Jan 29 '17 at 11:05
  • Someone kind enough to share a firemonkey (fmx) version of that code? For example, I cannot find createChooser under JIntent. Thanks. – sandman Feb 27 '17 at 07:58
  • When using the camera I always get resultCode == Activity.RESULT_CANCELED in onActivityResult. Using Android 7+ – MobileMon Jun 26 '17 at 13:19
  • I used this code. on button click I got 2 option camera and document,(I want gallery). the second point is when I select the same image two times getting an error that image not found. when I select the first time It works. – Ramdeo angh Jul 06 '17 at 08:37
  • My app opens the camera but if I click ok nothing happens. Any idea about that? I dont know what is the problem – Alonso Ato Neyra Aug 21 '18 at 01:01
31

You'll have to create your own chooser dialog merging both intent resolution results.

To do this, you will need to query the PackageManager with PackageManager.queryIntentActivities() for both original intents and create the final list of possible Intents with one new Intent for each retrieved activity like this:

List<Intent> yourIntentsList = new ArrayList<Intent>();

List<ResolveInfo> listCam = packageManager.queryIntentActivities(camIntent, 0);
for (ResolveInfo res : listCam) {
    final Intent finalIntent = new Intent(camIntent);
    finalIntent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
    yourIntentsList.add(finalIntent);
}

List<ResolveInfo> listGall = packageManager.queryIntentActivities(gallIntent, 0);
for (ResolveInfo res : listGall) {
    final Intent finalIntent = new Intent(gallIntent);
    finalIntent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
    yourIntentsList.add(finalIntent);
}

(I wrote this directly here so this may not compile)

Then, for more info on creating a custom dialog from a list see https://developer.android.com/guide/topics/ui/dialogs.html#AlertDialog

Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Kevin Gaudin
  • 9,647
  • 3
  • 29
  • 34
23

I found this. Using:

galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

for one of the intents shows the user the option of selecting 'documents' in Android 4, which I found very confusing. Using this instead shows the 'gallery' option:

Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Willi Mentzel
  • 21,499
  • 16
  • 88
  • 101
plexus
  • 1,482
  • 1
  • 13
  • 12
  • this works fine..but when we browse camera image,portrait image shows in landscape mode.. –  Feb 07 '15 at 11:45
  • @user5060065 and others having problems with the orientation of the selected picture, see http://stackoverflow.com/a/6931373/1975002 to get the correct orientation, and then rotate it if necessary. – Michaël Polla Aug 21 '16 at 12:55
12

I also had this issue and what I did was create an AlertDialog and use the setItems() method along with the DialogInterface listener:

AlertDialog.Builder getImageFrom = new AlertDialog.Builder(Fotos.this);
getImageFrom.setTitle("Select:");
final CharSequence[] opsChars = {getResources().getString(R.string.takepic), getResources().getString(R.string.opengallery)};
getImageFrom.setItems(opsChars, new android.content.DialogInterface.OnClickListener(){

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if(which == 0){
            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
        }else
            if(which == 1){
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent,
                    getResources().getString(R.string.pickgallery)), SELECT_PICTURE);
            }
        dialog.dismiss();
    }
});
Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Paulina D.
  • 370
  • 3
  • 14
11

I have merged some solutions to make a complete util for picking an image from Gallery or Camera. These are the features of ImagePicker util (also in a Github lib):

  • Merged intents for Gallery and Camera resquests.
  • Resize selected big images (e.g.: 2500 x 1600)
  • Rotate image if necesary

Screenshot:

ImagePicker starting intent

Edit: Here is a fragment of code to get a merged Intent for Gallery and Camera apps together. You can see the full code at ImagePicker util (also in a Github lib):

public static Intent getPickImageIntent(Context context) {
    Intent chooserIntent = null;

    List<Intent> intentList = new ArrayList<>();

    Intent pickIntent = new Intent(Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    takePhotoIntent.putExtra("return-data", true);
    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(context)));
    intentList = addIntentsToList(context, intentList, pickIntent);
    intentList = addIntentsToList(context, intentList, takePhotoIntent);

    if (intentList.size() > 0) {
        chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1),
                context.getString(R.string.pick_image_intent_text));
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
    }

    return chooserIntent;
}

private static List<Intent> addIntentsToList(Context context, List<Intent> list, Intent intent) {
    List<ResolveInfo> resInfo = context.getPackageManager().queryIntentActivities(intent, 0);
    for (ResolveInfo resolveInfo : resInfo) {
        String packageName = resolveInfo.activityInfo.packageName;
        Intent targetedIntent = new Intent(intent);
        targetedIntent.setPackage(packageName);
        list.add(targetedIntent);
    }
    return list;
}
Mario Velasco
  • 3,178
  • 1
  • 29
  • 48
  • 1
    This works really well. Thanks. Only issue I'm having is that photos taken with the camera in portrait are coming appearing as landscape. What do I need to do to get rotate required images? – 365SplendidSuns Nov 02 '15 at 10:48
  • @365SplendidSuns Can you check if it is entering in the method `getRotationFromCamera` (`ImagePicker.java`) and what value it is returning? In which phone are you testing? – Mario Velasco Nov 02 '15 at 12:37
  • I'm using a Sony Experia C and the Android Studio emulator. I just put in some break points to check the things you asked about and it seems boolean isCamera is false in the getRotation method which is stopping the getRotationFromCamera from being called. – 365SplendidSuns Nov 02 '15 at 12:43
  • What Android version are you trying? I added a modification last week on line 58, check if it solved it: `boolean isCamera = (imageReturnedIntent == null || imageReturnedIntent.getData() == null);` – Mario Velasco Nov 02 '15 at 12:48
  • Ok, the emulator is version 6.0 and it seems line 58 is working fine on this. On the emulator isCamera is true and getRotationFromCamera is being called fine but int orientation is 0 which means getRotationFromCamera is returning 0... The Sony device is using Android 4.2 and on this one neither imageReturnedIntent or imageReturnedIntent.getData() are null on line 58 meaning isCamera is false and I'm not getting as far as calling getRotationFromCamera. – 365SplendidSuns Nov 02 '15 at 13:10
  • Probably the emulator does not have sensors to know if the photo was taking in portrait or landscape, but in the phone should be working. I will investigate more why it is not working on that phone. Tell me if you find the solution. – Mario Velasco Nov 02 '15 at 13:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93993/discussion-between-mario-velasco-and-365splendidsuns). – Mario Velasco Nov 02 '15 at 13:47
8

this code will help you, in that there is two button one for Camera and another for Gallery, and Image will be displayed in ImageView

https://github.com/siddhpuraamitr/Choose-Image-From-Gallery-Or-Camera

Panchal Amit
  • 12,802
  • 10
  • 73
  • 137
  • 5
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes – MrEngineer13 Sep 08 '14 at 20:54
7

This should take care of Tina's null outputFileUri issue:

private static final String STORED_INSTANCE_KEY_FILE_URI = "output_file_uri";

@Override
public void onSaveInstanceState( Bundle outState ) {
    super.onSaveInstanceState( outState );

    if ( outputFileUri != null ) {
        outState.putString( STORED_INSTANCE_KEY_FILE_URI, outputFileUri.toString() );
    }
}

@Override
public void onViewStateRestored( Bundle savedInstanceState ) {
    super.onViewStateRestored( savedInstanceState );

    if ( savedInstanceState != null ) {
      final String outputFileUriStr = savedInstanceState.getString( STORED_INSTANCE_KEY_FILE_URI );
      if ( outputFileUriStr != null && !outputFileUriStr.isEmpty() ) {
          outputFileUri = Uri.parse( outputFileUriStr );
      }
    }
}

Note: I'm using this code inside android.support.v4.app.Fragment your overridden methods might change depending on what Fragment/Activity version you're using.

Willi Mentzel
  • 21,499
  • 16
  • 88
  • 101
Shah
  • 200
  • 1
  • 4
  • 7
6

For those getting error on 4.4 upward while trying to use the Image selection can use the code below.

Rather than creating a Dialog with a list of Intent options, it is much better to use Intent.createChooser in order to get access to the graphical icons and short names of the various 'Camera', 'Gallery' and even Third Party filesystem browser apps such as 'Astro', etc.

This describes how to use the standard chooser-intent and add additional intents to that.

private void openImageIntent(){

    // Determine Uri of camera image to save.
    final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "amfb" + File.separator);
    root.mkdir();
    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(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[]{}));
    startActivityForResult(chooserIntent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);

}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
            final boolean isCamera;
            if (data == null) {
                isCamera = true;
            } else {
                final String action = data.getAction();
                if (action == null) {
                    isCamera = false;
                } else {
                    isCamera = action.equals(MediaStore.ACTION_IMAGE_CAPTURE);
                }
            }

            Uri selectedImageUri;
            if (isCamera) {
                selectedImageUri = outputFileUri;
                //Bitmap factory
                BitmapFactory.Options options = new BitmapFactory.Options();
                // downsizing image as it throws OutOfMemory Exception for larger
                // images
                options.inSampleSize = 8;
                final Bitmap bitmap = BitmapFactory.decodeFile(selectedImageUri.getPath(), options);
                preview.setImageBitmap(bitmap);
            } else {
                selectedImageUri = data == null ? null : data.getData();
                Log.d("ImageURI", selectedImageUri.getLastPathSegment());
                // /Bitmap factory
                BitmapFactory.Options options = new BitmapFactory.Options();
                // downsizing image as it throws OutOfMemory Exception for larger
                // images
                options.inSampleSize = 8;
                try {//Using Input Stream to get uri did the trick
                    InputStream input = getContentResolver().openInputStream(selectedImageUri);
                    final Bitmap bitmap = BitmapFactory.decodeStream(input);
                    preview.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    } else if (resultCode == RESULT_CANCELED){
        // user cancelled Image capture
        Toast.makeText(getApplicationContext(),
                "User cancelled image capture", Toast.LENGTH_SHORT)
                .show();
    } else {
        // failed to capture image
        Toast.makeText(getApplicationContext(),
                "Sorry! Failed to capture image", Toast.LENGTH_SHORT)
                .show();
    }
}
Willi Mentzel
  • 21,499
  • 16
  • 88
  • 101
  • Hi. I have tried your solution, but picking a picture from gallary isn't working: take a look here: http://stackoverflow.com/questions/36884651/picking-a-image-from-camera-works-but-not-from-the-gallary/36884842#36884842 –  Apr 27 '16 at 09:40
  • On my marshmallow device this messes up when using the camera. for me data is not null, but action is, causing isCamera to be set to false. – JStephen May 13 '16 at 18:39
5

You can create option dialog

Open Camera:

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                                MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString());
                        if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null) {
                            startActivityForResult(cameraIntent, CAMERA_IMAGE);
                        }

Open Gallery:

if (Build.VERSION.SDK_INT <= 19) {
            Intent i = new Intent();
            i.setType("image/*");
            i.setAction(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            startActivityForResult(i, GALLARY_IMAGE);
        } else if (Build.VERSION.SDK_INT > 19) {
            Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(intent, GALLARY_IMAGE);
        }

To get selection result

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == GALLARY_IMAGE) {
                Uri selectedImageUri = data.getData();
                String selectedImagePath = getRealPathFromURI(selectedImageUri);
            } else if (requestCode == CAMERA_IMAGE) {
                Bundle extras = data.getExtras();
                Bitmap bmp = (Bitmap) extras.get("data");
                SaveImage(bmp);
            }
        }
    }

 public String getRealPathFromURI(Uri uri) {
        if (uri == null) {
            return null;
        }
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, null);
        if (cursor != null) {
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        return uri.getPath();
    }

Method to save captured image

 private void SaveImage(final Bitmap finalBitmap) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                String root = Environment.getExternalStorageDirectory().toString();

                File myDir = new File(root + "/Captured Images/");
                if (!myDir.exists())
                    myDir.mkdirs();

                String fname = "/image-" + System.currentTimeMillis() + ".jpg";
                File file = new File(myDir, fname);
                try {
                    FileOutputStream out = new FileOutputStream(file);
                    finalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
                    out.flush();
                    out.close();
                    localImagePath = myDir + fname;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }


        });
        t.start();

    }
Muhammad Umair Shafique
  • 1,984
  • 1
  • 22
  • 35
2

Resolved too big image issue and avoid to out of memory.

    private static final int SELECT_PICTURE = 0;
    private static final int REQUEST_CAMERA = 1;
    private ImageView mImageView;

    private void selectImage() {
        final CharSequence[] items = {"Take Photo", "Choose from Library",
                "Cancel"};
        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setTitle("Add Photo!");
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                if (items[item].equals("Take Photo")) {
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    File f = new File(android.os.Environment
                            .getExternalStorageDirectory(), "temp.jpg");
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                    startActivityForResult(intent, REQUEST_CAMERA);
                } else if (items[item].equals("Choose from Library")) {
                    Intent intent = new Intent(
                            Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                    intent.setType("image/*");
                    startActivityForResult(
                            Intent.createChooser(intent, "Select File"),
                            SELECT_PICTURE);
                } else if (items[item].equals("Cancel")) {
                    dialog.dismiss();
                }
            }
        });
        builder.show();
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == REQUEST_CAMERA) {
                File f = new File(Environment.getExternalStorageDirectory()
                        .toString());
                for (File temp : f.listFiles()) {
                    if (temp.getName().equals("temp.jpg")) {
                        f = temp;
                        break;
                    }
                }
                try {
                    Bitmap bm;
                    BitmapFactory.Options btmapOptions = new BitmapFactory.Options();
                    btmapOptions.inSampleSize = 2;
                    bm = BitmapFactory.decodeFile(f.getAbsolutePath(),
                            btmapOptions);

                    // bm = Bitmap.createScaledBitmap(bm, 70, 70, true);
                    mImageView.setImageBitmap(bm);

                    String path = android.os.Environment
                            .getExternalStorageDirectory()
                            + File.separator
                            + "test";
                    f.delete();
                    OutputStream fOut = null;
                    File file = new File(path, String.valueOf(System
                            .currentTimeMillis()) + ".jpg");
                    fOut = new FileOutputStream(file);
                    bm.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
                    fOut.flush();
                    fOut.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (requestCode == SELECT_PICTURE) {
                Uri selectedImageUri = data.getData();
                String tempPath = getPath(selectedImageUri, this.getActivity());
                Bitmap bm;
                btmapOptions.inSampleSize = 2;
                BitmapFactory.Options btmapOptions = new BitmapFactory.Options();
                bm = BitmapFactory.decodeFile(tempPath, btmapOptions);
                mImageView.setImageBitmap(bm);
            }
        }
    }
    public String getPath(Uri uri, Activity activity) {
        String[] projection = {MediaStore.MediaColumns.DATA};
        Cursor cursor = activity
                .managedQuery(uri, projection, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }
Willi Mentzel
  • 21,499
  • 16
  • 88
  • 101
Luna Kong
  • 2,745
  • 21
  • 18
1

Adding my solution - it will return a callback whether it is from the camera or from the galley alongside the intent:

public class ImagePickerManager extends BaseAdapter {

private List<ResolveInfo> mApplications;
private TreeSet<Integer> mImageCaptureIntents;
private TreeSet<Integer> mImagePickerIntents;
private Context mContext;
private final ImagePickerManagerListener listener;

private static enum intentType {
    choosePhoto,
    takePhoto,
    unknown;

    public int getIntValue() {
        switch (this) {
            case choosePhoto:
                return 0;
            case takePhoto:
                return 1;
            case unknown:
                return 2;
        }
        return 0;
    }
}

public interface ImagePickerManagerListener {
    void onChooseImage(Intent intent);
    void onCaptureImage(Intent intent);
}

public ImagePickerManager(Context context,ImagePickerManagerListener listenr) {
    this.mContext = context;
    this.listener = listenr;

    mImageCaptureIntents = new TreeSet<>();
    mImagePickerIntents = new TreeSet<>();

    //Picking photo intent
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType("image/*");
    mApplications = mContext.getPackageManager().queryIntentActivities(intent, 0);

    int index = 0;
    for (int i = 0; i < mApplications.size(); i++) {
        mImagePickerIntents.add(index);
        index++;
    }

    //Capture photo intent
    intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    List<ResolveInfo> resolveInfoList = mContext.getPackageManager().queryIntentActivities(intent, 0);
    mApplications.addAll(resolveInfoList);
    for (int i = 0; i < mApplications.size(); i++) {
        mImageCaptureIntents.add(index);
        index++;
    }
}

public static void openChooseAndCaptureImageDialog(final Context context, final ImagePickerManagerListener listener) {

    Log.d("openChooseAndCaptureImageDialog", "enter");

    final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    final ImagePickerManager imagePickerManager = new ImagePickerManager(context,listener);
    builder.setTitle(context.getString(R.string.image_picker_dialog_box_title));
    builder.setAdapter(imagePickerManager, new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialoginterface, int i) {
            ResolveInfo resolveInfo = (ResolveInfo) imagePickerManager.getItem(i);
            Intent pickerIntent = imagePickerManager.getIntentForPackage(context,resolveInfo,i);
            switch (imagePickerManager.getIntentType(i)){
                case choosePhoto:
                    listener.onChooseImage(pickerIntent);
                    break;
                case takePhoto:
                    listener.onCaptureImage(pickerIntent);
                    break;
                case unknown:
                    break;
            }
        }
    });

    builder.setCancelable(true);
    builder.setInverseBackgroundForced(true);
    AlertDialog dialog = builder.create();
    dialog.show();
}


private intentType getIntentType(int index) {

    if (mImageCaptureIntents.contains(index)) {
       return intentType.takePhoto;
    } else if(mImagePickerIntents.contains(index)) {
        return intentType.choosePhoto;
    }
    return intentType.unknown;
}

private Intent getIntentForPackage(Context context, ResolveInfo info,int index) {
    Intent intent = context.getPackageManager().getLaunchIntentForPackage(info.activityInfo.packageName);

    ComponentName chosenName = new ComponentName(
            info.activityInfo.packageName,
            info.activityInfo.name);

    intent.setComponent(chosenName);
    intent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
    if (mImageCaptureIntents.contains(index)) {
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
    } else if(mImagePickerIntents.contains(index)) {
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_PICK);
    }
    return intent;
}

@Override
public int getCount() {
    return mApplications.size();
}

@Override
public Object getItem(int position) {
    return mApplications.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ResolveInfo item = mApplications.get(position);
    if (convertView == null) {
        TextView applicationTextView = new TextView(mContext);
        LayoutParams param = new LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.WRAP_CONTENT);
        applicationTextView.setLayoutParams(param);
        final int horizontalPadding = (int) FVRGeneralUtils.convertDpToPx(mContext, 15);
        final int verticalPadding = (int) FVRGeneralUtils.convertDpToPx(mContext, 5);
        applicationTextView.setPadding(horizontalPadding,verticalPadding, horizontalPadding, verticalPadding);
        applicationTextView.setGravity(android.view.Gravity.CENTER_VERTICAL);
        Resources.Theme th = mContext.getTheme();
        TypedValue tv = new TypedValue();

        if (th.resolveAttribute(android.R.attr.textAppearanceMedium, tv, true)) {
            applicationTextView.setTextAppearance(mContext, tv.resourceId);
        }

        applicationTextView.setMinHeight((int) FVRGeneralUtils.convertDpToPx(mContext, 25));
        applicationTextView.setCompoundDrawablePadding((int) FVRGeneralUtils.convertDpToPx(mContext, 7));
        convertView = applicationTextView;
    }

    TextView textView = (TextView) convertView;
    textView.setText(item.loadLabel(mContext.getPackageManager()));
    textView.setCompoundDrawablesWithIntrinsicBounds(item.loadIcon(mContext.getPackageManager()), null, null, null);
    return textView;
} }
oznus
  • 2,318
  • 2
  • 23
  • 17
1

You can try this :

To open Gallery :

private void browseImage() {

        try {
  Intent galleryIntent = new Intent(Intent.ACTION_PICK,
                    android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
  startActivityForResult(galleryIntent, GALLERY_IMAGE_PICK); //GALLERY_IMAGE_PICK it is a string
  } catch (Exception e) {}
     }

To open Camera :

 private void captureImage() {
    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);

}
ZeroView
  • 142
  • 1
  • 15
  • 1
    This is a paste from elsewhere on SO. For example - what does getOutputMediaFileUri do? Please share complete examples, with explanation. – kilokahn Feb 07 '19 at 12:34
0

This is simple by using AlertDialog and Intent.ACTION_PICK

    //camOption is a string array contains two items (Camera, Gallery)
    AlertDialog.Builder builder = new AlertDialog.Builder(CarPhotos.this);
    builder.setTitle(R.string.selectSource)
    .setItems(R.array.imgOption, new DialogInterface.OnClickListener() {

    public void onClick(DialogInterface dialog, int which)

     {

        if (which==0) {
        Intent intent = new Intent(this, CameraActivity.class);
        startActivityForResult(intent, REQ_CAMERA_IMAGE);               }

        if (which==1) {
        Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(i, RESULT_LOAD_IMAGE);
            }

     }
            });
             builder.create();
             builder.show();
Seven
  • 375
  • 3
  • 7
0

Building upon David's answer, my two pennies on the onActivityResult() part. It takes care of the changes introduced in 5.1.1 and detects whether the user has picked a single or multiple image from the library.

private enum Outcome {
    camera, singleLibrary, multipleLibrary, unknown
}

/**
 * Returns a List<Uri> containing the image uri(s) chosen by the user
 *
 * @param data      The data intent coming from the onActivityResult()
 * @param cameraUri The uri that had been passed to the intent when the chooser was invoked.
 * @return A List<Uri>, never null.
 */
public List<Uri> getPicturesUriFromIntent(Intent data, Uri cameraUri) {

    Outcome outcome = Outcome.unknown;

    if (data == null || (data.getData() == null && data.getClipData() == null)) {
        outcome = Outcome.camera;
    } else if (data.getData() != null && data.getClipData() == null) {
        outcome = Outcome.singleLibrary;
    } else if (data.getData() == null) {
        outcome = Outcome.multipleLibrary;
    } else {
        final String action = data.getAction();
        if (action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE)) {
            outcome = Outcome.camera;
        }
    }

    // list the uri(s) we got back
    List<Uri> uris = new ArrayList<>();
    switch (outcome) {
        case camera:
            uris.add(cameraUri);
            break;

        case singleLibrary:
            uris.add(data.getData());
            break;

        case multipleLibrary:
            final ClipData clipData = data.getClipData();
            for (int i = 0; i < clipData.getItemCount(); i++) {
                ClipData.Item item = clipData.getItemAt(i);
                uris.add(item.getUri());
            }
            break;
    }

    return uris;
}
ticofab
  • 7,169
  • 11
  • 44
  • 81
0

Try this way

final CharSequence[] items = { "Take Photo", "Choose from Library",
            "Cancel" };

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("Add Photo!");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Take Photo")) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File f = new File(android.os.Environment
                        .getExternalStorageDirectory(), "temp.jpg");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                startActivityForResult(intent, REQUEST_CAMERA);
            } else if (items[item].equals("Choose from Library")) {
                Intent intent = new Intent(
                        Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(
                        Intent.createChooser(intent, "Select File"),
                        SELECT_FILE);
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();

Then create onactivityresult method and do something like this

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == REQUEST_CAMERA) {
            File f = new File(Environment.getExternalStorageDirectory()
                    .toString());
            for (File temp : f.listFiles()) {
                if (temp.getName().equals("temp.jpg")) {
                    f = temp;
                    break;
                }
            }
            try {
                Bitmap bm;
                BitmapFactory.Options btmapOptions = new BitmapFactory.Options();

                bm = BitmapFactory.decodeFile(f.getAbsolutePath(),
                        btmapOptions);

                // bm = Bitmap.createScaledBitmap(bm, 70, 70, true);
                ivImage.setImageBitmap(bm);

                String path = android.os.Environment
                        .getExternalStorageDirectory()
                        + File.separator
                        + "Phoenix" + File.separator + "default";
                f.delete();
                OutputStream fOut = null;
                File file = new File(path, String.valueOf(System
                        .currentTimeMillis()) + ".jpg");
                try {
                    fOut = new FileOutputStream(file);
                    bm.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
                    fOut.flush();
                    fOut.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (requestCode == SELECT_FILE) {
            Uri selectedImageUri = data.getData();

            String tempPath = getPath(selectedImageUri, MainActivity.this);
            Bitmap bm;
            BitmapFactory.Options btmapOptions = new BitmapFactory.Options();
            bm = BitmapFactory.decodeFile(tempPath, btmapOptions);
            ivImage.setImageBitmap(bm);
        }
    }
}

See this http://www.theappguruz.com/blog/android-take-photo-camera-gallery-code-sample

Aditya Vyas-Lakhan
  • 12,393
  • 15
  • 55
  • 92
0

Selecting camera or gallery for image in Android

I had worked hard on Camera or gallery Image Selection, and created some util class for this work. With the use of these class 'Selecting image camera or gallery is too easy' it just took 5-10 mints of your development.

Step-1: Add these classes in your code.

ImagePickerUtils :- http://www.codesend.com/view/f8f7c637716bf1c693d1490635ed49b3/

BitmapUtils :- http://www.codesend.com/view/81c1c2a3f39f1f7e627f01f67be282cf/

ConvertUriToFilePath :- http://www.codesend.com/view/f4668a29860235dd1b66eb419c5a58b5/

MediaUtils :- https://codeshare.io/5vKEMl

We need to Add these Permission in menifest :

  <uses-permission android:name="android.permission.CAMERA" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-feature android:name="android.hardware.camera" />
  <uses-feature android:name="android.hardware.camera.autofocus" />

This class function (checkAndRequestPermissions) auto check the permission in Android-Marshmallow and Android - Nougat.

Step-2. Calling camera class for launching camera intent :

 //Create a global veriable .  
     private Uri mCameraUri;
     private static final int CAMERA_REQUEST_CODE = 100;

// Call this function when you wants to select or capture an Image.
       mCameraUri = ImagePickerUtils.createTakePictureIntent(this, CAMERA_REQUEST_CODE);

Step-3: Add onActivityResult in your Activity for receiving data from Intent

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            Uri fileUri = ImagePickerUtils.getFileUriOfImage(this, data, mCameraUri);
            try {
                Bitmap bitmap = null;
                if (CAMERA_REQUEST_CODE == requestCode) {
                    bitmap = new BitmapUtils().getDownsampledBitmap(this, fileUri, imageView.getWidth(), imageView.getHeight());
                }
                if (bitmap != null)
                imageView.setImageBitmap(bitmap);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

I hope it helps you, If any one having any suggestion to improve these class please add your review in comments.

A-Droid Tech
  • 2,145
  • 21
  • 32
0

As per David Manpearl answer
https://stackoverflow.com/a/12347567/7226732

we just need to modify onActivityResult() like

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == YOUR_SELECT_PICTURE_REQUEST_CODE) {
            final boolean isCamera;
            if (data.getExtras() == 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 = fileUri;
                try {
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri);
                    Toast.makeText(CreateWaterType.this, "Image Saved!", Toast.LENGTH_SHORT).show();
                    image_view.setImageBitmap(bitmap);

                } catch (IOException e) {
                    e.printStackTrace();
                    Toast.makeText(CreateWaterType.this, "Failed!", Toast.LENGTH_SHORT).show();
                }

            } else {
                selectedImageUri = data == null ? null : data.getData();
                try {
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri);

                    Toast.makeText(CreateWaterType.this, "Image Saved!", Toast.LENGTH_SHORT).show();
                    image_view.setImageBitmap(bitmap);

                } catch (IOException e) {
                    e.printStackTrace();
                    Toast.makeText(CreateWaterType.this, "Failed!", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
}

and set the capture or pick images in image view.

Mohammad
  • 445
  • 5
  • 12