-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Pick image for cropping from Camera or Gallery
##TL;DR
- Add permissions to manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- Add CropImageActivity to manifest
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat"/> <!-- optional (needed if default theme has no action bar) -->
- Start Crop Image Activity
private void startCropImageActivity() {
CropImage.activity()
.start(this);
}
- Start pick-image-chooser
public void onSelectImageClick(View view) {
CropImage.startPickImageActivity(this);
}
- Handle onActivityResult
@Override
@SuppressLint("NewApi")
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// handle result of pick image chooser
if (requestCode == CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri imageUri = CropImage.getPickImageResultUri(this, data);
// For API >= 23 we need to check specifically that we have permissions to read external storage.
if (CropImage.isReadExternalStoragePermissionsRequired(this, imageUri)) {
// request permissions and handle the result in onRequestPermissionsResult()
mCropImageUri = imageUri;
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE);
} else {
// no permissions required or already granted, can start crop image activity
startCropImageActivity(imageUri);
}
}
}
- Handle onRequestPermissionsResult
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE) {
if (mCropImageUri != null && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// required permissions granted, start crop image activity
startCropImageActivity(mCropImageUri);
} else {
Toast.makeText(this, "Cancelling, required permissions are not granted", Toast.LENGTH_LONG).show();
}
}
}
- Start Crop Image Activity
private void startCropImageActivity(Uri imageUri) {
CropImage.activity(imageUri)
.start(this);
}
Create "chooser" intent using Intent.createChooser
that will contains all the available Camera (MediaStore.ACTION_IMAGE_CAPTURE
) and Gallery (Intent.ACTION_GET_CONTENT
) activities on the device.
Your can start the activity quickly by CropImage.startPickImageActivity
, get the chooser intent using CropImage.getPickImageChooserIntent
or create the intent yourself possible separating camera and gallery intents.
There is an edge scenario starting with Marshmallow that if the app requests <uses-permission android:name="android.permission.CAMERA"/>
in the manifests it must explicitly request them in runtime to be able to use the MediaStore.ACTION_IMAGE_CAPTURE
action intent, otherwise selecting camera in the chooser won't work. So first a check is done to see if explicit camera permission is required.
From UX perspective it may be better, in this scenario, to separate capture image by camera and pick image from gallery to different UI triggers (buttons).
@SuppressLint("NewApi")
public void onSelectImageClick(View view) {
if (CropImage.isExplicitCameraPermissionRequired(this)) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, CropImage.CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE);
} else {
CropImage.startPickImageActivity(this);
}
}
The result of pick image activity is returned in onActivityResult
method for the activity that started it.
To retrieve the picked image uri use CropImage.getPickImageResultUri
that will handle if the user used Camera or Gallery activity.
Some Gallery activities may use external storage to pass the picked image so will require READ_EXTERNAL_STORAGE
permissions to read it. For pre-Marshmallow (SDK 23) you need to request the permissions in the manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Starting from Marshmallow you need to request it at runtime. Because not all activities require external storage it is best to first check it using CropImage.isReadExternalStoragePermissionsRequired
so only to request it if-and-only-if it is required. Calling requestPermissions
method will request the permission from the user asynchronously so starting of the crop activity is postponed to onRequestPermissionsResult
.
@Override
@SuppressLint("NewApi")
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// handle result of pick image chooser
if (requestCode == CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri imageUri = CropImage.getPickImageResultUri(this, data);
// For API >= 23 we need to check specifically that we have permissions to read external storage.
if (CropImage.isReadExternalStoragePermissionsRequired(this, imageUri)) {
// request permissions and handle the result in onRequestPermissionsResult()
mCropImageUri = imageUri;
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE);
} else {
// no permissions required or already granted, can start crop image activity
startCropImageActivity(imageUri);
}
}
}
Result of permissions request is returned in onRequestPermissionsResult
method.
If the required permissions are not granted you can cancel gracefully or present an explanation dialog and request the permissions again, it either case you cannot continue.
For camera capture permissions you can start the pick image chooser activity, and the crop activity for external storage permissions.
The permission request was shown right after the user picked the image for cropping so it is obvious why the app required the permissions, no special dialog is required in that case, IMHO.
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == CropImage.CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
CropImage.startPickImageActivity(this);
} else {
Toast.makeText(this, "Cancelling, required permissions are not granted", Toast.LENGTH_LONG).show();
}
}
if (requestCode == CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE) {
if (mCropImageUri != null && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// required permissions granted, start crop image activity
startCropImageActivity(mCropImageUri);
} else {
Toast.makeText(this, "Cancelling, required permissions are not granted", Toast.LENGTH_LONG).show();
}
}
}
Finally you can start the crop activity, be it the built-in CropImageActivity
or your custom activity using CropImageView
.
private void startCropImageActivity(Uri imageUri) {
CropImage.activity(imageUri)
.start(this);
}