Pick image for crop from gallery and camera it\'s done for below Android 7.0 but in Android Nought it crashes in camera. I use fileprovider for it but doesn\'t work.
Have you added this in Manifest.xml??
<application
........
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
this has to be there in your manifest.. for effect in the naugut android 7.0.
Again you need to add provider_paths.xml file in xml.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
You can easily use this library which will be helpful to clean your project from boilerplate code for image pick and crop.
Following solution works for me. I've tested with Gallery, Google drive, Photos etc.
Sample is in Kotlin
language.
ImagePickUtils.kt
fun getImageUri(context: Context, contentURI: String): Uri {
var conUri = Uri.parse(contentURI)
var filePath = ""
if (DocumentsContract.isDocumentUri(context, conUri)) {
val wholeID = DocumentsContract.getDocumentId(conUri)
// Split at colon, use second item in the array
val id = wholeID.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
val column = arrayOf(MediaStore.Images.Media.DATA)
// where id is equal to
val sel = MediaStore.Images.Media._ID + "=?"
val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, arrayOf(id), null) ?: return conUri
val columnIndex = cursor.getColumnIndex(column[0])
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex)
}
cursor.close()
if (filePath.isNotEmpty()) {
filePath = filePath.replace(" ".toRegex(), "%20")
conUri = Uri.parse("file://$filePath")
}
}
return conUri
}
onActivityResult of Activity / Fragment:
if (data != null) {
val imagePath: Uri
if (data.data != null) {
val mImageUri = data.data
imagePath = getImageUri(this@HomeActivity, mImageUri.toString())
Log.i(TAG+" Image actual path", imagePath.toString())
}
}
Hope this would help you.
Intent pickImageIntent = new Intent("com.android.camera.action.CROP");
Uri contentUri = imageUri;
pickImageIntent.setDataAndType(contentUri, "image/*");
pickImageIntent.putExtra("crop", "true");
pickImageIntent.putExtra("aspectX", 1);
pickImageIntent.putExtra("aspectY", 1);
pickImageIntent.putExtra("outputX", 400);
pickImageIntent.putExtra("outputY", 400);
pickImageIntent.putExtra("return-data", true);
startActivityForResult(pickImageIntent, RESULT_CROP);
Uri uri = FileProvider.getUriForFile(this, getPackageName() + Configs.FILE_PROVIDER_NAME, inFile);
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setDataAndType(uri, "image/*");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));
You should notice that the uri for EXTRA_OUTPUT should not be modified by FileProvider. And your paths.xml should like this
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_sd" path="."/>
<external-files-path name="external_app" path="."/>
<files-path name="files" path="."/>
<cache-path name="cache" path="."/>
Because you create crop file under getExternalFilesDir. So <external-files-path>
is necessary.
I have two source for crop,one is gallery and the other one is camera
the method gallery:
//take a photo from gallery
public void gallery() {
//set UUID to filename
String PHOTO_FILE_NAME = UUID.randomUUID().toString()+".jpg";
Utils.putValue(this, Constants.UserPortraitFilePath,PHOTO_FILE_NAME);
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
}
the method camera:
//take a photo from camera
public void camera() {
//check sdcard is usable or not
if (Utils.hasSdcard()) {
//set UUID to filename
String PHOTO_FILE_NAME = UUID.randomUUID().toString()+".jpg";
Utils.putValue(this,Constants.UserPortraitFilePath,PHOTO_FILE_NAME);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//set file location to DreamGo/Image
File path = Environment.getExternalStorageDirectory();
File dir = new File(path, "DreamGo/Image");
if(!dir.exists())
dir.mkdirs();
//Android N need use FileProvider get file
//uri because StrictMode System
//getUriForFile(content,provider author,file)
Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider",
new File(dir.getAbsolutePath(), PHOTO_FILE_NAME));
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(intent, PHOTO_REQUEST_CAMERA);
}else {
showToast("no storage device");
}
}
the crop method:
//Android N crop image
public void crop(Uri uri) {
context.grantUriPermission("com.android.camera",uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
//Android N need set permission to uri otherwise system camera don't has permission to access file wait crop
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.putExtra("crop", "true");
//The proportion of the crop box is 1:1
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
//Crop the output image size
intent.putExtra("outputX", 800);
intent.putExtra("outputY", 800);
//image type
intent.putExtra("outputFormat", "JPEG");
intent.putExtra("noFaceDetection", true);
//true - don't return uri | false - return uri
intent.putExtra("return-data", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, PHOTO_REQUEST_CUT);
}
the onActivityResult method :
private static final int PHOTO_REQUEST_CAMERA = 0;//camera
private static final int PHOTO_REQUEST_GALLERY = 1;//gallery
private static final int PHOTO_REQUEST_CUT = 2;//image crop
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
String PHOTO_FILE_NAME = Utils.getValue(this, Constants.UserPortraitFilePath);
File path = Environment.getExternalStorageDirectory();
File dir = new File(path, "DreamGo/Image");
if(!dir.exists())
dir.mkdirs();
switch (requestCode)
{
case PHOTO_REQUEST_GALLERY:
if (data != null){
//file from gallery
File sourceFile = new File(getRealPathFromURI(data.getData()));
//blank file DreamGo/Image/uuid.jpg
File destFile = new File(dir.getAbsolutePath(), PHOTO_FILE_NAME);
Log.e("photo",data.getData().getPath());
try {
//copy file from gallery to DreamGo/Image/uuid.jpg
// otherwise crop method can't cut image without write permission
copyFile(sourceFile,destFile);
//Android N need use FileProvider to get file uri
Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider", destFile);
//cut image
crop(photoURI);
} catch (IOException e) {
e.printStackTrace();
}
}
break;
case PHOTO_REQUEST_CAMERA:
//whether sdcard is usable has been checked before use camera
File tempFile = new File(dir.getAbsolutePath(), PHOTO_FILE_NAME);
Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider", tempFile);
crop(photoURI);
break;
case PHOTO_REQUEST_CUT:
try {
if(data!=null) {
file = new File(dir.getAbsolutePath(), PHOTO_FILE_NAME);
icon.loadImage("file://" + file.getAbsolutePath());
}else {
showToast("a error happened when cut picture");
}
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
the realted code:
//copy sourceFile to destFile
public void copyFile(File sourceFile, File destFile) throws IOException {
if (!sourceFile.exists()) {
return;
}
FileChannel source = new FileInputStream(sourceFile).getChannel();
FileChannel destination = new FileOutputStream(destFile).getChannel();
if (destination != null && source != null) {
destination.transferFrom(source, 0, source.size());
}
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
//file uri to real location in filesystem
public String getRealPathFromURI(Uri contentURI) {
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) {
// Source is Dropbox or other similar local file path
return contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}
}
public static final String getValue(Context context, String key) {
return getSharedPreference(context).getString(key, "");
}
public static final boolean putValue(Context context, String key,
String value) {
value = value == null ? "" : value;
SharedPreferences.Editor editor = getSharedPreference(context).edit();
editor.putString(key, value);
boolean result = editor.commit();
if (!result) {
return false;
}
return true;
}