Nowadays the camera is a very common feature that lots of apps provide. Most of the required image capture feature in own application. eg. profile image, creating a post with an image, every food or social media app required camera feature in own application. Basically, Image capturing is very simple task, even if you are using custom. In this article, we are going to see how to capture image from camera and gallery using FileProvider in your Android app.
Google introduces FileProvider in version 22.1.0. FileProvider class is a derived class from ContentProvider. In other words you can say, FileProvider provide facilitates to secure file sharing in android via content://Uri
instead of a file:///Uri
This article includes the following topics:
- Initial project setup with including dependency
- Defining a FileProvider
- Granting Permissions to a URI, Storage & Camera
- Image Capture using Camera
- Pick Image from Gallery
- Manage Result and Image Compression
- Show the final image over the ImageView
After following the above step we will prepare final output like video
1. Initial project setup with including dependency
Go to the File menu -> New -> New Project -> Fill details Project Name & Package Details -> Next -> Select Empty Activity from templates -> click on Finish. Now open build.gradle and add below dependency.
dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.cardview:cardview:1.0.0' implementation 'com.google.android.material:material:1.0.0' // reactive implementation "io.reactivex.rxjava2:rxjava:$rootProject.rxjava2Version" implementation "io.reactivex.rxjava2:rxandroid:$rootProject.rxandroidVersion" implementation('com.github.bumptech.glide:glide:4.7.1@aar') { transitive = true } /** * For managing request permission */ implementation 'com.karumi:dexter:4.2.0' // code generator for view implementation "com.jakewharton:butterknife:$rootProject.butterKnifeVersion" annotationProcessor "com.jakewharton:butterknife-compiler:$rootProject.butterKnifeVersion" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' }
Open project build.gradle define version extension
// Define versions in a single place ext { // App dependencies rxjava2Version = '2.1.9' rxandroidVersion = '2.1.1' butterKnifeVersion = '10.1.0' }
2. Defining a FileProvider
2.1 In the res folder create a resource directory named
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="my_images" path="Android/data/com.androidwave.filepicker/files/Pictures"/> <!-- replace com.androidwave.filepicker with your package name --> </paths>
Note – Replace com.androidwave.filepicker with your package name
2.2 In AndroidMenifest.xml you have to specify FileProvider component by adding an element<provider>
like below
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_provider_paths"/> </provider>
3. Granting Permissions to a URI, Storage & Camera
3.1 We have to need to declare uses-permission in Manifest file for using device camera and storage. Open AndroidMenifest.xml and add Camera and Storage permission inside <manifest> tag
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera.flash" />
3.2 In Android 6, it contain a permission system for certain tasks. Each application can request the required permission on runtime. So let’s open Activity class add below code for requesting runtime permission
/** * Requesting multiple permissions (storage and camera) at once * This uses multiple permission model from dexter * On permanent denial opens settings dialog */ private void requestStoragePermission(boolean isCamera) { Dexter.withActivity(this) .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA) .withListener(new MultiplePermissionsListener() { @Override public void onPermissionsChecked(MultiplePermissionsReport report) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { if (isCamera) { dispatchTakePictureIntent(); } else { dispatchGalleryIntent(); } } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied()) { // show alert dialog navigating to Settings showSettingsDialog(); } } @Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) { token.continuePermissionRequest(); } }) .withErrorListener( error -> Toast.makeText(getApplicationContext(), "Error occurred! ", Toast.LENGTH_SHORT) .show()) .onSameThread() .check(); } /** * Showing Alert Dialog with Settings option * Navigates user to app settings * NOTE: Keep proper title and message depending on your app */ private void showSettingsDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Need Permissions"); builder.setMessage( "This app needs permission to use this feature. You can grant them in app settings."); builder.setPositiveButton("GOTO SETTINGS", (dialog, which) -> { dialog.cancel(); openSettings(); }); builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel()); builder.show(); } // navigating user to app settings private void openSettings() { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivityForResult(intent, 101); }
4. Image Capture using Camera
Forgoing forward we have to define two things.
- We need to create an Image file
- Create a new Intent with FileProvider URI
4.1 Now I’m creating a method that creates and return an empty file inside Picture Directory
/** * Create file with current timestamp name * @throws IOException */ private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); String mFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File mFile = File.createTempFile(mFileName, ".jpg", storageDir); return mFile; }
4.2 Create a new Intent with FileProvider URI
/** * Capture image from camera */ private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { ex.printStackTrace(); // Error occurred while creating the File } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", photoFile); mPhotoFile = photoFile; takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } } }
5. Pick Image from Gallery
Similarly, create an intent for pick image from gallery and add FLAG_GRANT_READ_URI_PERMISSION flag for temporary flag
/** * Select image fro gallery */ private void dispatchGalleryIntent() { Intent pickPhoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); pickPhoto.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivityForResult(pickPhoto, REQUEST_GALLERY_PHOTO); }
6. Manage Result and Image Compression
After action performing, we will manage the result on onActivityResult by using ResultCode and RequestCode. In
- Get actual file path or file from result intent
- Compress file using FileCompressor utility
- Finally set final output over the ImageView in Android
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == REQUEST_TAKE_PHOTO) { try { mPhotoFile = mCompressor.compressToFile(mPhotoFile); } catch (IOException e) { e.printStackTrace(); } Glide.with(MainActivity.this) .load(mPhotoFile) .apply(new RequestOptions().centerCrop() .circleCrop() .placeholder(R.drawable.profile_pic_place_holder)) .into(imageViewProfilePic); } else if (requestCode == REQUEST_GALLERY_PHOTO) { Uri selectedImage = data.getData(); try { mPhotoFile = mCompressor.compressToFile(new File(getRealPathFromUri(selectedImage))); } catch (IOException e) { e.printStackTrace(); } Glide.with(MainActivity.this) .load(mPhotoFile) .apply(new RequestOptions().centerCrop() .circleCrop() .placeholder(R.drawable.profile_pic_place_holder)) .into(imageViewProfilePic); } } }
In case of Gallery Intent we get result back as a URI. But we need to actual file path from compressing the image. So fetch the actual path from URI by using below code
/** * Get real file path from URI */ public String getRealPathFromUri(Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = getContentResolver().query(contentUri, proj, null, null, null); assert cursor != null; int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } finally { if (cursor != null) { cursor.close(); } } }
As you using I’m using a FileCompressor utility for compress resulted image file. Now I’m Creating FileCompressor.java file.
package com.androidwave.filepicker.utils; import android.content.Context; import android.graphics.Bitmap; import io.reactivex.Flowable; import java.io.File; import java.io.IOException; import java.util.concurrent.Callable; public class FileCompressor { //max width and height values of the compressed image is taken as 612x816 private int maxWidth = 612; private int maxHeight = 816; private Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG; private int quality = 80; private String destinationDirectoryPath; public FileCompressor(Context context) { destinationDirectoryPath = context.getCacheDir().getPath() + File.separator + "images"; } public FileCompressor setMaxWidth(int maxWidth) { this.maxWidth = maxWidth; return this; } public FileCompressor setMaxHeight(int maxHeight) { this.maxHeight = maxHeight; return this; } public FileCompressor setCompressFormat(Bitmap.CompressFormat compressFormat) { this.compressFormat = compressFormat; return this; } public FileCompressor setQuality(int quality) { this.quality = quality; return this; } public FileCompressor setDestinationDirectoryPath(String destinationDirectoryPath) { this.destinationDirectoryPath = destinationDirectoryPath; return this; } public File compressToFile(File imageFile) throws IOException { return compressToFile(imageFile, imageFile.getName()); } public File compressToFile(File imageFile, String compressedFileName) throws IOException { return ImageUtil.compressImage(imageFile, maxWidth, maxHeight, compressFormat, quality, destinationDirectoryPath + File.separator + compressedFileName); } public Bitmap compressToBitmap(File imageFile) throws IOException { return ImageUtil.decodeSampledBitmapFromFile(imageFile, maxWidth, maxHeight); } public Flowable<File> compressToFileAsFlowable(final File imageFile) { return compressToFileAsFlowable(imageFile, imageFile.getName()); } public Flowable<File> compressToFileAsFlowable(final File imageFile, final String compressedFileName) { return Flowable.defer(new Callable<Flowable<File>>() { @Override public Flowable<File> call() { try { return Flowable.just(compressToFile(imageFile, compressedFileName)); } catch (IOException e) { return Flowable.error(e); } } }); } public Flowable<Bitmap> compressToBitmapAsFlowable(final File imageFile) { return Flowable.defer(new Callable<Flowable<Bitmap>>() { @Override public Flowable<Bitmap> call() { try { return Flowable.just(compressToBitmap(imageFile)); } catch (IOException e) { return Flowable.error(e); } } }); } }
One more utility using here is
package com.androidwave.filepicker.utils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.media.ExifInterface; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class ImageUtil { private ImageUtil() { } static File compressImage(File imageFile, int reqWidth, int reqHeight, Bitmap.CompressFormat compressFormat, int quality, String destinationPath) throws IOException { FileOutputStream fileOutputStream = null; File file = new File(destinationPath).getParentFile(); if (!file.exists()) { file.mkdirs(); } try { fileOutputStream = new FileOutputStream(destinationPath); // write the compressed bitmap at the destination specified by destinationPath. decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight).compress(compressFormat, quality, fileOutputStream); } finally { if (fileOutputStream != null) { fileOutputStream.flush(); fileOutputStream.close(); } } return new File(destinationPath); } static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) throws IOException { // First decode with inJustDecodeBounds=true to check dimensions BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options); //check the rotation of the image and display it properly ExifInterface exif; exif = new ExifInterface(imageFile.getAbsolutePath()); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); Matrix matrix = new Matrix(); if (orientation == 6) { matrix.postRotate(90); } else if (orientation == 3) { matrix.postRotate(180); } else if (orientation == 8) { matrix.postRotate(270); } scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true); return scaledBitmap; } private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; } }
Finally set the output image file over the ImageView using Glide Image library
Glide.with(MainActivity.this) .load(mPhotoFile) .apply(new RequestOptions().centerCrop() .circleCrop() .placeholder(R.drawable.profile_pic_place_holder)) .into(imageViewProfilePic);
7. Define some color value inside Open color.xml like below
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#039BE5</color> <color name="colorPrimaryDark">#0288D1</color> <color name="colorAccent">#FF4081</color> <color name="start_color">#29B6F6</color> <color name="end_color">#4FC3F7</color> <color name="white">#FFFFFF</color> </resources>
8. Open activity_main.xml or add some views. I have try to build user profile look in this layout
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" tools:context=".MainActivity"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/relativeLayout" android:layout_width="match_parent" android:layout_height="405dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="350dp" android:background="@drawable/gradient_bg" android:orientation="vertical"> <ImageView android:id="@+id/imageViewProfilePic" android:layout_width="150dp" android:layout_height="150dp" android:layout_gravity="center_horizontal" android:layout_marginTop="45dp" android:src="@drawable/profile_picture" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="10dp" android:text="Morris" android:textColor="#fff" android:textSize="21sp" android:textStyle="bold" /> </LinearLayout> <androidx.cardview.widget.CardView android:layout_width="400dp" android:layout_height="120dp" android:layout_centerHorizontal="true" android:layout_marginTop="275dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:weightSum="3"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Photos" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="10dp" android:text="125" android:textColor="@color/start_color" android:textSize="20sp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Followers" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="10dp" android:text="1205" android:textColor="@color/start_color" android:textSize="20sp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Following" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="10dp" android:text="360" android:textColor="@color/start_color" android:textSize="20sp" android:textStyle="bold" /> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> </RelativeLayout> <LinearLayout android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:orientation="vertical" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/relativeLayout"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:padding="16dp" android:text="@string/email" android:textStyle="bold" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:padding="16dp" android:text="@string/contact_number" android:textStyle="bold" /> </LinearLayout> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="16dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:layout_marginTop="16dp" android:background="@drawable/button_style" android:text="Follow Me" android:textColor="#fff" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/linearLayout" /> </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView>
9. Finally, open your main activity (MainActivity.java) and modify the code as below.
- Set ContentView activity_main.xml
- Bind view with id using ButterKnife
- Set onClick Listener over the ImageView
- Create alert popup to the user for choose want to Capture a picture or pick from Gallery
- Check permission using dexer
Add dispatch intent inside the onPermissionCheck methods
10. The final code looks as
package com.androidwave.filepicker; import android.Manifest; import android.app.AlertDialog; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.provider.Settings; import android.widget.ImageView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import com.androidwave.filepicker.utils.FileCompressor; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import com.karumi.dexter.Dexter; import com.karumi.dexter.MultiplePermissionsReport; import com.karumi.dexter.PermissionToken; import com.karumi.dexter.listener.PermissionRequest; import com.karumi.dexter.listener.multi.MultiplePermissionsListener; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; public class MainActivity extends AppCompatActivity { static final int REQUEST_TAKE_PHOTO = 1; static final int REQUEST_GALLERY_PHOTO = 2; File mPhotoFile; FileCompressor mCompressor; @BindView(R.id.imageViewProfilePic) ImageView imageViewProfilePic; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); mCompressor = new FileCompressor(this); } /** * Alert dialog for capture or select from galley */ private void selectImage() { final CharSequence[] items = { "Take Photo", "Choose from Library", "Cancel" }; AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setItems(items, (dialog, item) -> { if (items[item].equals("Take Photo")) { requestStoragePermission(true); } else if (items[item].equals("Choose from Library")) { requestStoragePermission(false); } else if (items[item].equals("Cancel")) { dialog.dismiss(); } }); builder.show(); } /** * Capture image from camera */ private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { ex.printStackTrace(); // Error occurred while creating the File } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", photoFile); mPhotoFile = photoFile; takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } } } /** * Select image fro gallery */ private void dispatchGalleryIntent() { Intent pickPhoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); pickPhoto.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivityForResult(pickPhoto, REQUEST_GALLERY_PHOTO); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == REQUEST_TAKE_PHOTO) { try { mPhotoFile = mCompressor.compressToFile(mPhotoFile); } catch (IOException e) { e.printStackTrace(); } Glide.with(MainActivity.this) .load(mPhotoFile) .apply(new RequestOptions().centerCrop() .circleCrop() .placeholder(R.drawable.profile_pic_place_holder)) .into(imageViewProfilePic); } else if (requestCode == REQUEST_GALLERY_PHOTO) { Uri selectedImage = data.getData(); try { mPhotoFile = mCompressor.compressToFile(new File(getRealPathFromUri(selectedImage))); } catch (IOException e) { e.printStackTrace(); } Glide.with(MainActivity.this) .load(mPhotoFile) .apply(new RequestOptions().centerCrop() .circleCrop() .placeholder(R.drawable.profile_pic_place_holder)) .into(imageViewProfilePic); } } } /** * Requesting multiple permissions (storage and camera) at once * This uses multiple permission model from dexter * On permanent denial opens settings dialog */ private void requestStoragePermission(boolean isCamera) { Dexter.withActivity(this) .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA) .withListener(new MultiplePermissionsListener() { @Override public void onPermissionsChecked(MultiplePermissionsReport report) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { if (isCamera) { dispatchTakePictureIntent(); } else { dispatchGalleryIntent(); } } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied()) { // show alert dialog navigating to Settings showSettingsDialog(); } } @Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) { token.continuePermissionRequest(); } }) .withErrorListener( error -> Toast.makeText(getApplicationContext(), "Error occurred! ", Toast.LENGTH_SHORT) .show()) .onSameThread() .check(); } /** * Showing Alert Dialog with Settings option * Navigates user to app settings * NOTE: Keep proper title and message depending on your app */ private void showSettingsDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Need Permissions"); builder.setMessage( "This app needs permission to use this feature. You can grant them in app settings."); builder.setPositiveButton("GOTO SETTINGS", (dialog, which) -> { dialog.cancel(); openSettings(); }); builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel()); builder.show(); } // navigating user to app settings private void openSettings() { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivityForResult(intent, 101); } /** * Create file with current timestamp name * * @throws IOException */ private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); String mFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File mFile = File.createTempFile(mFileName, ".jpg", storageDir); return mFile; } /** * Get real file path from URI */ public String getRealPathFromUri(Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = getContentResolver().query(contentUri, proj, null, null, null); assert cursor != null; int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } finally { if (cursor != null) { cursor.close(); } } } @OnClick(R.id.imageViewProfilePic) public void onViewClicked() { selectImage(); } }
Run the project and click user profile you will show an alert dialog for choosing camera and gallery after that choose action that you want. the final output will show on your screen. If you have any queries, feel free to ask them in the comment section below.
Source Code – Capture Image from Camera & Gallery
8 Comments
(java.lang.IllegalArgumentException: Couldn’t find meta-data for provider with authority com.karumi.dexter.provider)
I got this error when to open Take Photo. why?
I’d love to see an updated tutorial showing how this would work with scoped storage. Running your current example won’t work with API 29 unless your AndroidManifest.xml has android:requestLegacyExternalStorage=”true”.
how to insert it into database
Hi, i need help please
I am under Android and I try to integrate the function of capturing a photo for a profile,it works when I choose a photo from the gallery but when I try to take a picture from the camera it does not run the application,go back to the previous menu here is the error message.
there is my error message/
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.company_name.nidhal, PID: 14052
java.lang.IllegalArgumentException: Couldn’t find meta-data for provider with authority com.bumptech.glide.provider
change the contents of file_provider_paths.xml
to this
I assume that I can use the same logic when recording a video?
Yes, same logic will work
it dosen’t save it into the hard drive of the device