Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
* Added value you get out-of-the-box is some edge case handling that you may miss otherwise, like the
* stupid-ass Android camera result URI that may differ from version to version and from device to device.
*/
@SuppressWarnings("WeakerAccess, unused")
public final class CropImage {

//region: Fields and Consts
Expand Down Expand Up @@ -164,8 +165,10 @@ public static Intent getPickImageChooserIntent(@NonNull Context context, CharSeq
List<Intent> allIntents = new ArrayList<>();
PackageManager packageManager = context.getPackageManager();

// collect all camera intents
allIntents.addAll(getCameraIntents(context, packageManager));
// collect all camera intents if Camera permission is available
if (!isExplicitCameraPermissionRequired(context)) {
allIntents.addAll(getCameraIntents(context, packageManager));
}

List<Intent> galleryIntents = getGalleryIntents(packageManager, Intent.ACTION_GET_CONTENT, includeDocuments);
if (galleryIntents.size() == 0) {
Expand Down Expand Up @@ -350,13 +353,10 @@ public static boolean isUriRequiresPermissions(@NonNull Context context, @NonNul
* Result will be recieved in {@link Activity#onActivityResult(int, int, Intent)} and can be retrieved
* using {@link #getActivityResult(Intent)}.
*
* @param uri the image Android uri source to crop
* @param uri the image Android uri source to crop or null to start a picker
* @return builder for Crop Image Activity
*/
public static ActivityBuilder activity(@NonNull Uri uri) {
if (uri == null || uri.equals(Uri.EMPTY)) {
throw new IllegalArgumentException("Uri must be non null or empty");
}
public static ActivityBuilder activity(@Nullable Uri uri) {
return new ActivityBuilder(uri);
}

Expand All @@ -380,14 +380,15 @@ public static final class ActivityBuilder {
/**
* The image to crop source Android uri.
*/
@Nullable
private final Uri mSource;

/**
* Options for image crop UX
*/
private final CropImageOptions mOptions;

private ActivityBuilder(@NonNull Uri source) {
private ActivityBuilder(@Nullable Uri source) {
mSource = source;
mOptions = new CropImageOptions();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,23 @@

package com.theartofdev.edmodo.cropper;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
Expand All @@ -38,24 +44,43 @@ public class CropImageActivity extends AppCompatActivity implements CropImageVie
*/
private CropImageView mCropImageView;

/**
* Persist URI image to crop URI if specific permissions are required
*/
private Uri mCropImageUri;

/**
* the options that were set for the crop image
*/
private CropImageOptions mOptions;

@Override
@SuppressLint("NewApi")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.crop_image_activity);

mCropImageView = (CropImageView) findViewById(R.id.cropImageView);

Intent intent = getIntent();
Uri source = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_SOURCE);
mCropImageUri = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_SOURCE);
mOptions = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_OPTIONS);

if (savedInstanceState == null) {
mCropImageView.setImageUriAsync(source);
if (mCropImageUri == null || mCropImageUri.equals(Uri.EMPTY)) {
if (CropImage.isExplicitCameraPermissionRequired(this)) {
// request permissions and handle the result in onRequestPermissionsResult()
requestPermissions(new String[]{Manifest.permission.CAMERA}, CropImage.CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE);
} else {
CropImage.startPickImageActivity(this);
}
} else if (CropImage.isReadExternalStoragePermissionsRequired(this, mCropImageUri)) {
// request permissions and handle the result in onRequestPermissionsResult()
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE);
} else {
// no permissions required or already grunted, can start crop image activity
mCropImageView.setImageUriAsync(mCropImageUri);
}
}

ActionBar actionBar = getSupportActionBar();
Expand Down Expand Up @@ -140,6 +165,51 @@ public void onBackPressed() {
setResultCancel();
}

@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) {
if (resultCode == Activity.RESULT_CANCELED) {
//User cancelled the picker. We don't have anything to crop
setResultCancel();
}

if (resultCode == Activity.RESULT_OK) {
mCropImageUri = CropImage.getPickImageResultUri(this, data);

// For API >= 23 we need to check specifically that we have permissions to read external storage.
if (CropImage.isReadExternalStoragePermissionsRequired(this, mCropImageUri)) {
// request permissions and handle the result in onRequestPermissionsResult()
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE);
} else {
// no permissions required or already grunted, can start crop image activity
mCropImageView.setImageUriAsync(mCropImageUri);
}
}
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull 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
mCropImageView.setImageUriAsync(mCropImageUri);
} else {
Toast.makeText(this, "Cancelling, required permissions are not granted", Toast.LENGTH_LONG).show();
setResultCancel();
}
}

if (requestCode == CropImage.CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE) {
//Irrespective of whether camera permission was given or not, we show the picker
//The picker will not add the camera intent if permission is not available
CropImage.startPickImageActivity(this);
}
}

@Override
public void onSetImageUriComplete(CropImageView view, Uri uri, Exception error) {
if (error == null) {
Expand Down
1 change: 1 addition & 0 deletions quick-start/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>

<application
android:allowBackup="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@

package com.theartofdev.edmodo.cropper.quick.start;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
Expand All @@ -29,11 +25,6 @@

public class MainActivity extends AppCompatActivity {

/**
* Persist URI image to crop URI if specific permissions are required
*/
private Uri mCropImageUri;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand All @@ -44,28 +35,12 @@ protected void onCreate(Bundle savedInstanceState) {
* Start pick image activity with chooser.
*/
public void onSelectImageClick(View view) {
CropImage.startPickImageActivity(this);
startCropImageActivity(null);
}

@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}, 0);
} else {
// no permissions required or already grunted, can start crop image activity
startCropImageActivity(imageUri);
}
}

// handle result of CropImageActivity
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
CropImage.ActivityResult result = CropImage.getActivityResult(data);
Expand All @@ -78,16 +53,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
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 for the given image.
*/
Expand Down