Tuesday 6 March 2018

Android Take Photo From Camera and Gallery - Code Sample

Objective

The main objective of this post is to help you understand how to take photo /picture/image from the camera or gallery in your Android phone. 


User will have two choices:
  1. Capture photo/ image from camera in Android
  2. Choose photo/ image from gallery in Android
User will need to choose one option from the above two options and then depending on the option chosen by the user, we will either capture an image from the camera or open the gallery.

You will get Final Output:



Step 1 Create Layout

First, we'll show a button to user – user can click the button and we'll give an option to user where he can get image from the camera or get image from gallery in Android. Lets get started with creating the layout
  • <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  •     xmlns:tools="http://schemas.android.com/tools"
  •     android:id="@+id/LinearLayout1"
  •     android:layout_width="match_parent"
  •     android:layout_height="match_parent"
  •     android:orientation="vertical"
  •     android:padding="10dp" >
  •  
  •     <LinearLayout
  •         android:layout_width="match_parent"
  •         android:layout_height="wrap_content"
  •         android:gravity="center"
  •         android:padding="5dp" >
  •  
  •         <Button
  •             android:id="@+id/btnSelectPhoto"
  •             android:layout_width="match_parent"
  •             android:layout_height="wrap_content"
  •             android:text="Select Photo" />
  •  
  •     </LinearLayout>
  •  
  •     <LinearLayout
  •         android:layout_width="match_parent"
  •         android:layout_height="wrap_content"
  •         android:gravity="center"
  •         android:orientation="vertical"
  •         android:padding="10dp" >
  •  
  •         <ImageView
  •             android:id="@+id/ivImage"
  •             android:layout_width="wrap_content"
  •             android:layout_height="wrap_content"
  •             android:src="@drawable/ic_launcher" />
  •     </LinearLayout>
  •  
  • </LinearLayout>

Step 2 Create options Dialog box

>> We want show the dialog box to user with options when user clicks on the Select Photo button.

So for this, we will create new method into MainActivity File called selectImage() Method. In this method we'll create the dialog box with the three options you can see in the screenshot above.
  • private void selectImage() {
  • 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) {
  • boolean result=Utility.checkPermission(MainActivity.this);
  • if (items[item].equals("Take Photo")) {
  • userChoosenTask="Take Photo";
  • if(result)
  • cameraIntent();
  • } else if (items[item].equals("Choose from Library")) {
  • userChoosenTask="Choose from Library";
  • if(result)
  • galleryIntent();
  • } else if (items[item].equals("Cancel")) {
  • dialog.dismiss();
  • }
  • }
  • });
  • builder.show();
  • }
Let's dig deeper and see what exactly we are doing in this method

2.1 Set Dialogbox Items

  • final CharSequence[] items = { "Take Photo", "Choose from Library",
  • "Cancel" };
  • AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
  • builder.setTitle("Add Photo!");
We are creating an AlertDialog with three items as given in an array called items, And in last line we are setting the title for the Dialog box as Add Photo! Now, lets see what we are doing when user chooses any of the options.

2.2 Requesting Permission at Runtime

If you are using a device having MarshMallow version of Android, then your application will definitely crash or will not work properly without calling below method.
  • boolean result=Utility.checkPermission(MainActivity.this);
Here, checkPermission() method checks the permission for storage group at runtime. Even if you have declared permission in AndroidManifest file, you need to check Runtime Permission in MarshMallow.
Let’s look at checkPermission() method:
  • public class Utility {
  • public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123;
  • @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  • public static boolean checkPermission(final Context context)
  • {
  • int currentAPIVersion = Build.VERSION.SDK_INT;
  • if(currentAPIVersion>=android.os.Build.VERSION_CODES.M)
  • {
  • if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
  • if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.READ_EXTERNAL_STORAGE)) {
  • AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
  • alertBuilder.setCancelable(true);
  • alertBuilder.setTitle("Permission necessary");
  • alertBuilder.setMessage("External storage permission is necessary");
  • alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
  • @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  • public void onClick(DialogInterface dialog, int which) {
  • ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
  • }
  • });
  • AlertDialog alert = alertBuilder.create();
  • alert.show();
  • } else {
  • ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
  • }
  • return false;
  • } else {
  • return true;
  • }
  • } else {
  • return true;
  • }
  • }
  • }
This method will check permission at runtime for Marshmallow & greater than Marshmallow version.
If current API version is less than Marshmallow, then checkPermission() will return true, which means permission is granted (in Manifest file, no support for runtime permission).
If current API version is Marshmallow or greater, and if permission is already granted then the method returns true. Otherwise, the method returns false and will show a dialog box to a user with allow or deny options.

2.3 Check for Camera Request

  • if (items[item].equals("Take Photo")) {
  • userChoosenTask="Take Photo";
  • if(result)
  • cameraIntent();
  • }
If user chooses Take Photo option:
Here, I stored Take Photo in String variable userChoosenTask. This variable will be used in onRequestPermissionsResult() method to check which item is selected.
If permission has already been granted previously, then ‘result’ variable will contain true & call cameraIntent() method.
Let’s look at cameraIntent() method:
  • private void cameraIntent()
  • {
  • Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  • startActivityForResult(intent, REQUEST_CAMERA);
  • }
We are calling Implicit Intent to open the camera application on user's phone.
  • Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Learn more about Implicit Intent here please refer the following link:
Check the list of Common Intents here from the below link:
>> We are starting the Camera Activity, but instead of passing the intent in startActivity() we are passing the intent in method startActivityForResult(). This method will give us a result back. In our case, it will give us an image capture by camera.
  • startActivityForResult(intent, REQUEST_CAMERA);
Learn more about startActivityForResult() please refer the following link:
Now, we'll learn how to pick image from gallery in Android.

2.4 Check for Gallery Request

  • else if (items[item].equals("Choose from Library")) {
  • userChoosenTask="Choose from Library";
  • if(result)
  • galleryIntent();
  • }
If user chooses Take Photo option:
  • Here, I stored “Choose from Library” in String variable userChoosenTask. This variable will be used in onRequestPermissionsResult() method to check which item is selected.
  • If permission has already been granted previously, then ‘result’ variable will contain true & call galleryIntent() method.
Let’s look at galleryIntent() method:
  • private void galleryIntent()
  • {
  • Intent intent = new Intent();
  • intent.setType("image/*");
  • intent.setAction(Intent.ACTION_GET_CONTENT);//
  • startActivityForResult(Intent.createChooser(intent, "Select File"),SELECT_FILE);
  • }
Similar to what we have done with the previous option, again we are calling an implicit intent to open the gallery and than calling startActivityForResult() and passing the intent.
  • intent.setType("image/*");
This line is used to select only images from the media storage.
Tip:  if you want to get images as well as videos, you can use following code
  • intent.setType("image/* video/*");
I think rest of the stuff is self-explanatory in this file. Lets move forward.

2.5 Grant Permission at Runtime

If permission has not been granted, then checkPermssion() method will display a dialog to user with two options.
  1. Allow the permission request or
  2. Deny the permission request
onRequestPermissionsResult() is inbuilt method which receives a callback of this dialog action for particular activity from which checkPermssion() has been called
  • @Override
  • public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
  • switch (requestCode) {
  • case Utility.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
  • if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  • if(userChoosenTask.equals("Take Photo"))
  • cameraIntent();
  • else if(userChoosenTask.equals("Choose from Library"))
  • galleryIntent();
  • } else {
  • //code for deny
  • }
  • break;
  • }
  • }
If permission has been granted then the value of grantResults[0] would be PERMISSION_GRANTED. And if permission has been revoked then the value of grantResults[0] would be PERMISSION_DENIED.
Here, if permission has been granted, then I am calling method for specific Intent according to value of userChoosenTask variable.

Step 3 Handling Image

Now, we have got the image either from camera or from gallery, its time to handle that image. We need handle the result we have received by calling startActivityForResult() Method. So add onActivityResult() Method into Main activity class.
>> The code will look something like this:
  • @Override
  • public void onActivityResult(int requestCode, int resultCode, Intent data) {
  • super.onActivityResult(requestCode, resultCode, data);
  • if (resultCode == Activity.RESULT_OK) {
  • if (requestCode == SELECT_FILE)
  • onSelectFromGalleryResult(data);
  • else if (requestCode == REQUEST_CAMERA)
  • onCaptureImageResult(data);
  • }
  • }
  • @SuppressWarnings("deprecation")
  • private void onSelectFromGalleryResult(Intent data) {
  • Bitmap bm=null;
  • if (data != null) {
  • try {
  • bm = MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(), data.getData());
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • ivImage.setImageBitmap(bm);
  • }
  • private void onCaptureImageResult(Intent data) {
  • Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
  • ByteArrayOutputStream bytes = new ByteArrayOutputStream();
  • thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
  • File destination = new File(Environment.getExternalStorageDirectory(),
  • System.currentTimeMillis() + ".jpg");
  • FileOutputStream fo;
  • try {
  • destination.createNewFile();
  • fo = new FileOutputStream(destination);
  • fo.write(bytes.toByteArray());
  • fo.close();
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • ivImage.setImageBitmap(thumbnail);
  • }
As mentioned earlier, onActivityResult() Method handles the results we have received.
Lets dissect the code and see what it does.
When we are taking an image from the camera:

3.1 onActivityResult() Method

  • @Override
  • protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  • super.onActivityResult(requestCode, resultCode, data);
Arguments:
int requestCode
The request code is what you have passed to startActivityForResult(). In our case it is REQUEST_CAMERA.
int resultCode
RESULT_OK if the operation was successful or
RESULT_CANCEL if the operation was somehow cancelled or unsuccessful.
intent dataThe intent carries the result data – in our case it is the image we have captured from the camera.
Bitmap.CompressFormat format
This argument states the format of a compressed image –
can be JPEG, PNG, WEBP More about CompressFormat class over here:
int quality
Quality on the scale of 0 to 100, with 0 being the lowest and 100 being the highest. PNG is lossless compression, so it will ignore the quality settings.
OutputStream streamThe stream to write the compressed data.

You can learn about onActivityResult() from the below link:
Next, we are handling the input we have received from Camera

3.2 Handling Camera Request For Capturing an Image

  • if (resultCode == RESULT_OK) {
  • if (requestCode == REQUEST_CAMERA) {
Here we are just checking if our operation was successful by checking RESULT_OK and then checking if the requestCode is REQUEST_CAMERA. If the both the conditions are satisfied, we move forward.
  • Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
We get our data in our Intent, so we are first getting that data through data.getsExtras().get("data") and then we are casting that data into Bitmap since we want it as an image.
  • ByteArrayOutputStream bytes = new ByteArrayOutputStream();
  • thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
We want to make thumbnail of an image, so we need to first take the ByteArrayOutputStream and than pass it into thumbnail.compress() method.
Arguments:

Learn more about Bitmap.compress() method please refer the following link:
  • File destination = new File(Environment.getExternalStorageDirectory(),
  • System.currentTimeMillis() + ".jpg");
  • FileOutputStream fo;
  • try {
  • destination.createNewFile();
  • fo = new FileOutputStream(destination);
  • fo.write(bytes.toByteArray());
  • fo.close();
  • } catch (FileNotFoundException e) {
  • e.printStackTrace();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
Now, we are storing the file we have created into External Storage.
If you want to learn more about it, please refer the following link:
  • ivImage.setImageBitmap(thumbnail);
And in the end, we are just setting up the bitmap in our imageView.
When we select image from the gallery

3.3 Handling Gallery Request For Selecting Image

  • if (requestCode == SELECT_FILE)
  • onSelectFromGalleryResult(data);
On selecting image from gallery, onSelectFromGalleryResult(data) will be called
  • private void onSelectFromGalleryResult(Intent data) {
  • Bitmap bm=null;
  • if (data != null) {
  • try {
  • bm = MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(), data.getData());
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • ivImage.setImageBitmap(bm);
  • }
Android saves the images in its own database. We can fetch it using different ways. I have used MediaStore.Images.Media.getBitmap() here.
Learn more about MediaStore.Images.Media please refer the following link:
Here, I am fetching image from specific path(here, data.getData() ) as Bitmap by calling getBitmap() method & displaying it in ImageView.

Step 4 Add permission to manifest file

  • <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  • <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
For generating bitmap we need to add WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE permission.
I hope you enjoy this tutorial and you have learnt how to get image from gallery or caputre image from camera in Android.
  •  
  •  
  •