java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri









up vote
0
down vote

favorite












I am trying to use camera and save image. Followed the steps as commonsware suggested. Constantly I am getting error -



2018-11-12 02:10:54.588 3145-3173/com.bisw.weac E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri content://com.bisw.weac.provider/external_files/Android/data/com.bisw.weac/files/wallpaper/theme.jpg from pid=5566, uid=10071 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider.enforceWritePermissionInner(ContentProvider.java:713)
at android.content.ContentProvider$Transport.enforceWritePermission(ContentProvider.java:519)
at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:491)
at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:389)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:251)
at android.os.Binder.execTransact(Binder.java:682)



I have tried almost everything like - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); but nothing helps. I am croping the image from camera.
Activity code



public class LocalAlbumActivity extends BaseActivity implements View.OnClickListener 

private static final int REQUEST_IMAGE_CAPTURE_THEME = 1;
private static final int REQUEST_IMAGE_CAPTURE_QRCODE_LOGO = 4;
private static final int REQUEST_IMAGE_CROP_THEME = 2;
private static final int REQUEST_IMAGE_CROP_QRCODE_LOGO = 5;
private static final int REQUEST_ALBUM_DETAIL = 3;

public static final String ALBUM_PATH = "album_path";
public static final String ALBUM_NAME = "album_name";
private LocalAlbumAdapter mLocalAlbumAdapter;
private List<ImageBucket> mLocalAlbumList;
private AsyncTask<Void, Void, List<ImageBucket>> mBucketLoadTask;
private ListView mLocalAlbumListView;


/**
* 访问本地相册类型:0,主题;1,扫码;2,造码
*/
private int mRequestType;

@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
OttoAppConfig.getInstance().register(this);

setContentView(R.layout.activity_local_album);
ViewGroup backGround = (ViewGroup) findViewById(R.id.background);
MyUtil.setBackgroundBlur(backGround, this);

initAdapter();
assignViews();



private void initAdapter()

mLocalAlbumList = new ArrayList<>();
mLocalAlbumAdapter = new LocalAlbumAdapter(this, mLocalAlbumList);
//trying permission



mBucketLoadTask = new AsyncTask<Void, Void, List<ImageBucket>>()

@Override
protected void onPreExecute()
super.onPreExecute();
// showLoading();


@Override
protected List<ImageBucket> doInBackground(Void... params)

return LocalAlbumImagePickerHelper.getInstance(LocalAlbumActivity.this)
.getImagesBucketList();


@Override
protected void onPostExecute(List<ImageBucket> list)
dismissLoadingDialog();

TextView emptyView = (TextView) findViewById(R.id.local_album_lv_empty);
mLocalAlbumListView.setEmptyView(emptyView);

mLocalAlbumList.addAll(list);
mLocalAlbumAdapter.notifyDataSetChanged();

;

mBucketLoadTask.execute();


private void dismissLoadingDialog()
ViewGroup progressBarLlyt = (ViewGroup) findViewById(R.id.progress_bar_llyt);
progressBarLlyt.setVisibility(View.GONE);


private void assignViews()
TextView loadingMsg = (TextView) findViewById(R.id.loading_msg);
loadingMsg.setText(R.string.scanning);

ImageView backBtn = (ImageView) findViewById(R.id.action_back);
TextView captureBtn = (TextView) findViewById(R.id.action_capture);

backBtn.setOnClickListener(this);

mRequestType = getIntent().getIntExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, 0);
switch (mRequestType)
// 主题
case 0:
// 造码
case 2:
captureBtn.setOnClickListener(this);
break;
// 扫码
case 1:
// 隐藏拍照按钮
captureBtn.setVisibility(View.GONE);
break;


mLocalAlbumListView = (ListView) findViewById(R.id.local_album_lv);
mLocalAlbumListView.setAdapter(mLocalAlbumAdapter);
mLocalAlbumListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
if (MyUtil.isFastDoubleClick())
return;

Intent intent = new Intent(LocalAlbumActivity.this, LocalAlbumDetailActivity.class);
intent.putParcelableArrayListExtra(ALBUM_PATH,
mLocalAlbumAdapter.getItem(position).bucketList);
intent.putExtra(ALBUM_NAME, mLocalAlbumAdapter.getItem(position).bucketName);
intent.putExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, mRequestType);
startActivityForResult(intent, REQUEST_ALBUM_DETAIL);

);

// OverScrollDecoratorHelper.setUpOverScroll(mLocalAlbumListView);


private Uri mImageUri;

@Override
public void onClick(View v)
switch (v.getId())
// 返回
case R.id.action_back:
myFinish();
break;
// 拍照
case R.id.action_capture:
PackageManager pm = getPackageManager();
// FEATURE_CAMERA - 后置相机
// FEATURE_CAMERA_FRONT - 前置相机
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) Intent.FLAG_GRANT_READ_URI_PERMISSION);

intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
startActivityForResult(intent, requestType);
overridePendingTransition(0, R.anim.zoomin);
else // 没有可用相机
Intent intent = new Intent(this, MyDialogActivitySingle.class);
intent.putExtra(WeacConstants.TITLE, getString(R.string.prompt));
intent.putExtra(WeacConstants.DETAIL, getString(R.string.camera_error));
startActivity(intent);

break;



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK)
// 截图/相机返回
overridePendingTransition(0, R.anim.zoomout);
return;


// 扫描二维码相册详细取消
if (data != null)
boolean isFinishMe = data.getBooleanExtra(LocalAlbumDetailActivity.FINISH_ACTIVITY, false);
if (isFinishMe && !isFinishing())
myFinish2();
return;



switch (requestCode)
// 拍照(截取主题壁纸)
case REQUEST_IMAGE_CAPTURE_THEME:
cropImage(0, REQUEST_IMAGE_CROP_THEME, WeacConstants.DIY_WALLPAPER_PATH);
break;
// 拍照(截取二维码logo)
case REQUEST_IMAGE_CAPTURE_QRCODE_LOGO:
cropImage(1, REQUEST_IMAGE_CROP_QRCODE_LOGO, WeacConstants.DIY_QRCODE_LOGO_PATH);
break;
// 截图(截取主题壁纸)
case REQUEST_IMAGE_CROP_THEME:
String filePath = MyUtil.getFilePath(this, WeacConstants.DIY_WALLPAPER_PATH);
// 更新壁纸信息
MyUtil.saveWallpaper(this, WeacConstants.WALLPAPER_PATH, filePath);
// 发送壁纸更新事件
OttoAppConfig.getInstance().post(new WallpaperEvent());
myFinish();
break;
// 截图(截取二维码logo)
case REQUEST_IMAGE_CROP_QRCODE_LOGO:
String logoPath = MyUtil.getFilePath(this, WeacConstants.DIY_QRCODE_LOGO_PATH);
// 保存自定义二维码logo地址
MyUtil.saveQRcodeLogoPath(this, logoPath);
// 发送自定义二维码logo截取地址事件
OttoAppConfig.getInstance().post(new QRcodeLogoEvent(logoPath));
myFinish();
break;
// 相册详细图片
case REQUEST_ALBUM_DETAIL:
assert data != null;
String url = data.getStringExtra(WeacConstants.IMAGE_URL);
OttoAppConfig.getInstance().post(new ScanCodeEvent(url));
myFinish2();
break;



private void cropImage(int type, int requestType, String path)

ToastUtil.showLongToast(this, "path:"+path);
Intent intent = MyUtil.getCropImageOptions(this, mImageUri, path, type);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (intent.resolveActivity(getPackageManager()) != null)
startActivityForResult(intent, requestType);
overridePendingTransition(0, 0);
else
// 不可以复制其他应用的内部文件
// TODO: 全屏裁剪&自定义裁剪功能
ToastUtil.showLongToast(this, getString(R.string.no_crop_action));



@Subscribe
public void finishMeEvent(FinishLocalAlbumActivityEvent event)
myFinish2();


@Override
public void onBackPressed()
myFinish();


private void myFinish()
finish();
if (mRequestType != 2)
overridePendingTransition(0, R.anim.zoomout);
else
overridePendingTransition(0, R.anim.move_out_bottom);



private void myFinish2()
finish();
overridePendingTransition(0, 0);


@Override
protected void onDestroy()
super.onDestroy();
OttoAppConfig.getInstance().unregister(this);
if (null != mBucketLoadTask && mBucketLoadTask.getStatus() == AsyncTask.Status.RUNNING)
mBucketLoadTask.cancel(true);





Helper Methods



/**
* Returns specified directory(/mnt/sdcard/...).
* directory will be created on SD card by defined path if card
* is mounted. Else - Android defines files directory on device's
* files(/data/data/<application package>/files) system.
*
* @param context context
* @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jp")
* @return File @link File directory
*/
public static File getFileDirectory(Context context, String path)
File file = null;
if (isHasSDCard())
file = new File(Environment.getExternalStorageDirectory(), path);
if (!file.getParentFile().exists())
if (!file.getParentFile().mkdirs())
file = null;



if (file == null)
// 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
// 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
file = new File(context.getFilesDir(), path);

return file;


/**
* Returns specified directory(/mnt/sdcard/Android/data/<application package>/files/...).
* directory will be created on SD card by defined path if card
* is mounted. Else - Android defines files directory on device's
* files(/data/data/<application package>/files) system.
*
* @param context context
* @param path file path (e.g.: "/music/a.mp3", "/pictures/a.jpg")
* @return File @link File directory
*/
public static File getExternalFileDirectory(Context context, String path)
File file = null;
if (isHasSDCard())
file = new File(context.getExternalFilesDir(null), path);
if (!file.getParentFile().exists())
if (!file.getParentFile().mkdirs())
file = null;



if (file == null)
// 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
// 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
file = new File(context.getFilesDir(), path);

return file;


public static boolean isHasSDCard()
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());


/**
* Returns directory absolutePath.
*
* @param context context
* @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
* @return /mnt/sdcard/Android/data/<application package>/files/....
*/
public static String getFilePath(Context context, String path)
return getExternalFileDirectory(context, path).getAbsolutePath();


/**
* set intent options
*
* @param context context
* @param uri image path uri
* @param filePath save path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
* @param type 0,截取壁纸/拍照;1,截取Logo
* @return Intent
*/
public static Intent getCropImageOptions(Context context, Uri uri, String filePath, int type)
int width;
int height;
// 截取壁纸/拍照
if (type == 0)
width = context.getResources().getDisplayMetrics().widthPixels;
height = context.getResources().getDisplayMetrics().heightPixels;
else // 截取logo
width = height = dip2px(context, 30);

//filePath="/Internal storage/Download/a.jpg";
LogUtil.e(LOG_TAG, " filePath:" + filePath );
Intent intent = new Intent();
intent.setAction("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);


intent.putExtra("crop", "true");
// 裁剪框比例
intent.putExtra("aspectX", width);
intent.putExtra("aspectY", height);
// 保存路径


//#ToDO: Uri.fromFile change to FileProvider.getUriForFile
Uri mImageUri;
//mImageUri=Uri.fromFile(getExternalFileDirectory(context, filePath));

intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".provider",getExternalFileDirectory(context, filePath)));

// 是否去除面部检测
intent.putExtra("noFaceDetection", true);

intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// 是否保留比例
intent.putExtra("scale", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// 裁剪区的宽高
intent.putExtra("outputX", width);
intent.putExtra("outputY", height);

// 是否将数据保留在Bitmap中返回
intent.putExtra("return-data", false);
return intent;










share|improve this question

























    up vote
    0
    down vote

    favorite












    I am trying to use camera and save image. Followed the steps as commonsware suggested. Constantly I am getting error -



    2018-11-12 02:10:54.588 3145-3173/com.bisw.weac E/DatabaseUtils: Writing exception to parcel
    java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri content://com.bisw.weac.provider/external_files/Android/data/com.bisw.weac/files/wallpaper/theme.jpg from pid=5566, uid=10071 requires the provider be exported, or grantUriPermission()
    at android.content.ContentProvider.enforceWritePermissionInner(ContentProvider.java:713)
    at android.content.ContentProvider$Transport.enforceWritePermission(ContentProvider.java:519)
    at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:491)
    at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:389)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:251)
    at android.os.Binder.execTransact(Binder.java:682)



    I have tried almost everything like - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); but nothing helps. I am croping the image from camera.
    Activity code



    public class LocalAlbumActivity extends BaseActivity implements View.OnClickListener 

    private static final int REQUEST_IMAGE_CAPTURE_THEME = 1;
    private static final int REQUEST_IMAGE_CAPTURE_QRCODE_LOGO = 4;
    private static final int REQUEST_IMAGE_CROP_THEME = 2;
    private static final int REQUEST_IMAGE_CROP_QRCODE_LOGO = 5;
    private static final int REQUEST_ALBUM_DETAIL = 3;

    public static final String ALBUM_PATH = "album_path";
    public static final String ALBUM_NAME = "album_name";
    private LocalAlbumAdapter mLocalAlbumAdapter;
    private List<ImageBucket> mLocalAlbumList;
    private AsyncTask<Void, Void, List<ImageBucket>> mBucketLoadTask;
    private ListView mLocalAlbumListView;


    /**
    * 访问本地相册类型:0,主题;1,扫码;2,造码
    */
    private int mRequestType;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    super.onCreate(savedInstanceState);
    OttoAppConfig.getInstance().register(this);

    setContentView(R.layout.activity_local_album);
    ViewGroup backGround = (ViewGroup) findViewById(R.id.background);
    MyUtil.setBackgroundBlur(backGround, this);

    initAdapter();
    assignViews();



    private void initAdapter()

    mLocalAlbumList = new ArrayList<>();
    mLocalAlbumAdapter = new LocalAlbumAdapter(this, mLocalAlbumList);
    //trying permission



    mBucketLoadTask = new AsyncTask<Void, Void, List<ImageBucket>>()

    @Override
    protected void onPreExecute()
    super.onPreExecute();
    // showLoading();


    @Override
    protected List<ImageBucket> doInBackground(Void... params)

    return LocalAlbumImagePickerHelper.getInstance(LocalAlbumActivity.this)
    .getImagesBucketList();


    @Override
    protected void onPostExecute(List<ImageBucket> list)
    dismissLoadingDialog();

    TextView emptyView = (TextView) findViewById(R.id.local_album_lv_empty);
    mLocalAlbumListView.setEmptyView(emptyView);

    mLocalAlbumList.addAll(list);
    mLocalAlbumAdapter.notifyDataSetChanged();

    ;

    mBucketLoadTask.execute();


    private void dismissLoadingDialog()
    ViewGroup progressBarLlyt = (ViewGroup) findViewById(R.id.progress_bar_llyt);
    progressBarLlyt.setVisibility(View.GONE);


    private void assignViews()
    TextView loadingMsg = (TextView) findViewById(R.id.loading_msg);
    loadingMsg.setText(R.string.scanning);

    ImageView backBtn = (ImageView) findViewById(R.id.action_back);
    TextView captureBtn = (TextView) findViewById(R.id.action_capture);

    backBtn.setOnClickListener(this);

    mRequestType = getIntent().getIntExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, 0);
    switch (mRequestType)
    // 主题
    case 0:
    // 造码
    case 2:
    captureBtn.setOnClickListener(this);
    break;
    // 扫码
    case 1:
    // 隐藏拍照按钮
    captureBtn.setVisibility(View.GONE);
    break;


    mLocalAlbumListView = (ListView) findViewById(R.id.local_album_lv);
    mLocalAlbumListView.setAdapter(mLocalAlbumAdapter);
    mLocalAlbumListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id)
    if (MyUtil.isFastDoubleClick())
    return;

    Intent intent = new Intent(LocalAlbumActivity.this, LocalAlbumDetailActivity.class);
    intent.putParcelableArrayListExtra(ALBUM_PATH,
    mLocalAlbumAdapter.getItem(position).bucketList);
    intent.putExtra(ALBUM_NAME, mLocalAlbumAdapter.getItem(position).bucketName);
    intent.putExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, mRequestType);
    startActivityForResult(intent, REQUEST_ALBUM_DETAIL);

    );

    // OverScrollDecoratorHelper.setUpOverScroll(mLocalAlbumListView);


    private Uri mImageUri;

    @Override
    public void onClick(View v)
    switch (v.getId())
    // 返回
    case R.id.action_back:
    myFinish();
    break;
    // 拍照
    case R.id.action_capture:
    PackageManager pm = getPackageManager();
    // FEATURE_CAMERA - 后置相机
    // FEATURE_CAMERA_FRONT - 前置相机
    if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) Intent.FLAG_GRANT_READ_URI_PERMISSION);

    intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
    startActivityForResult(intent, requestType);
    overridePendingTransition(0, R.anim.zoomin);
    else // 没有可用相机
    Intent intent = new Intent(this, MyDialogActivitySingle.class);
    intent.putExtra(WeacConstants.TITLE, getString(R.string.prompt));
    intent.putExtra(WeacConstants.DETAIL, getString(R.string.camera_error));
    startActivity(intent);

    break;



    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != RESULT_OK)
    // 截图/相机返回
    overridePendingTransition(0, R.anim.zoomout);
    return;


    // 扫描二维码相册详细取消
    if (data != null)
    boolean isFinishMe = data.getBooleanExtra(LocalAlbumDetailActivity.FINISH_ACTIVITY, false);
    if (isFinishMe && !isFinishing())
    myFinish2();
    return;



    switch (requestCode)
    // 拍照(截取主题壁纸)
    case REQUEST_IMAGE_CAPTURE_THEME:
    cropImage(0, REQUEST_IMAGE_CROP_THEME, WeacConstants.DIY_WALLPAPER_PATH);
    break;
    // 拍照(截取二维码logo)
    case REQUEST_IMAGE_CAPTURE_QRCODE_LOGO:
    cropImage(1, REQUEST_IMAGE_CROP_QRCODE_LOGO, WeacConstants.DIY_QRCODE_LOGO_PATH);
    break;
    // 截图(截取主题壁纸)
    case REQUEST_IMAGE_CROP_THEME:
    String filePath = MyUtil.getFilePath(this, WeacConstants.DIY_WALLPAPER_PATH);
    // 更新壁纸信息
    MyUtil.saveWallpaper(this, WeacConstants.WALLPAPER_PATH, filePath);
    // 发送壁纸更新事件
    OttoAppConfig.getInstance().post(new WallpaperEvent());
    myFinish();
    break;
    // 截图(截取二维码logo)
    case REQUEST_IMAGE_CROP_QRCODE_LOGO:
    String logoPath = MyUtil.getFilePath(this, WeacConstants.DIY_QRCODE_LOGO_PATH);
    // 保存自定义二维码logo地址
    MyUtil.saveQRcodeLogoPath(this, logoPath);
    // 发送自定义二维码logo截取地址事件
    OttoAppConfig.getInstance().post(new QRcodeLogoEvent(logoPath));
    myFinish();
    break;
    // 相册详细图片
    case REQUEST_ALBUM_DETAIL:
    assert data != null;
    String url = data.getStringExtra(WeacConstants.IMAGE_URL);
    OttoAppConfig.getInstance().post(new ScanCodeEvent(url));
    myFinish2();
    break;



    private void cropImage(int type, int requestType, String path)

    ToastUtil.showLongToast(this, "path:"+path);
    Intent intent = MyUtil.getCropImageOptions(this, mImageUri, path, type);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    if (intent.resolveActivity(getPackageManager()) != null)
    startActivityForResult(intent, requestType);
    overridePendingTransition(0, 0);
    else
    // 不可以复制其他应用的内部文件
    // TODO: 全屏裁剪&自定义裁剪功能
    ToastUtil.showLongToast(this, getString(R.string.no_crop_action));



    @Subscribe
    public void finishMeEvent(FinishLocalAlbumActivityEvent event)
    myFinish2();


    @Override
    public void onBackPressed()
    myFinish();


    private void myFinish()
    finish();
    if (mRequestType != 2)
    overridePendingTransition(0, R.anim.zoomout);
    else
    overridePendingTransition(0, R.anim.move_out_bottom);



    private void myFinish2()
    finish();
    overridePendingTransition(0, 0);


    @Override
    protected void onDestroy()
    super.onDestroy();
    OttoAppConfig.getInstance().unregister(this);
    if (null != mBucketLoadTask && mBucketLoadTask.getStatus() == AsyncTask.Status.RUNNING)
    mBucketLoadTask.cancel(true);





    Helper Methods



    /**
    * Returns specified directory(/mnt/sdcard/...).
    * directory will be created on SD card by defined path if card
    * is mounted. Else - Android defines files directory on device's
    * files(/data/data/<application package>/files) system.
    *
    * @param context context
    * @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jp")
    * @return File @link File directory
    */
    public static File getFileDirectory(Context context, String path)
    File file = null;
    if (isHasSDCard())
    file = new File(Environment.getExternalStorageDirectory(), path);
    if (!file.getParentFile().exists())
    if (!file.getParentFile().mkdirs())
    file = null;



    if (file == null)
    // 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
    // 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
    file = new File(context.getFilesDir(), path);

    return file;


    /**
    * Returns specified directory(/mnt/sdcard/Android/data/<application package>/files/...).
    * directory will be created on SD card by defined path if card
    * is mounted. Else - Android defines files directory on device's
    * files(/data/data/<application package>/files) system.
    *
    * @param context context
    * @param path file path (e.g.: "/music/a.mp3", "/pictures/a.jpg")
    * @return File @link File directory
    */
    public static File getExternalFileDirectory(Context context, String path)
    File file = null;
    if (isHasSDCard())
    file = new File(context.getExternalFilesDir(null), path);
    if (!file.getParentFile().exists())
    if (!file.getParentFile().mkdirs())
    file = null;



    if (file == null)
    // 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
    // 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
    file = new File(context.getFilesDir(), path);

    return file;


    public static boolean isHasSDCard()
    return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());


    /**
    * Returns directory absolutePath.
    *
    * @param context context
    * @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
    * @return /mnt/sdcard/Android/data/<application package>/files/....
    */
    public static String getFilePath(Context context, String path)
    return getExternalFileDirectory(context, path).getAbsolutePath();


    /**
    * set intent options
    *
    * @param context context
    * @param uri image path uri
    * @param filePath save path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
    * @param type 0,截取壁纸/拍照;1,截取Logo
    * @return Intent
    */
    public static Intent getCropImageOptions(Context context, Uri uri, String filePath, int type)
    int width;
    int height;
    // 截取壁纸/拍照
    if (type == 0)
    width = context.getResources().getDisplayMetrics().widthPixels;
    height = context.getResources().getDisplayMetrics().heightPixels;
    else // 截取logo
    width = height = dip2px(context, 30);

    //filePath="/Internal storage/Download/a.jpg";
    LogUtil.e(LOG_TAG, " filePath:" + filePath );
    Intent intent = new Intent();
    intent.setAction("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);


    intent.putExtra("crop", "true");
    // 裁剪框比例
    intent.putExtra("aspectX", width);
    intent.putExtra("aspectY", height);
    // 保存路径


    //#ToDO: Uri.fromFile change to FileProvider.getUriForFile
    Uri mImageUri;
    //mImageUri=Uri.fromFile(getExternalFileDirectory(context, filePath));

    intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".provider",getExternalFileDirectory(context, filePath)));

    // 是否去除面部检测
    intent.putExtra("noFaceDetection", true);

    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    // 是否保留比例
    intent.putExtra("scale", true);
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    // 裁剪区的宽高
    intent.putExtra("outputX", width);
    intent.putExtra("outputY", height);

    // 是否将数据保留在Bitmap中返回
    intent.putExtra("return-data", false);
    return intent;










    share|improve this question























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I am trying to use camera and save image. Followed the steps as commonsware suggested. Constantly I am getting error -



      2018-11-12 02:10:54.588 3145-3173/com.bisw.weac E/DatabaseUtils: Writing exception to parcel
      java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri content://com.bisw.weac.provider/external_files/Android/data/com.bisw.weac/files/wallpaper/theme.jpg from pid=5566, uid=10071 requires the provider be exported, or grantUriPermission()
      at android.content.ContentProvider.enforceWritePermissionInner(ContentProvider.java:713)
      at android.content.ContentProvider$Transport.enforceWritePermission(ContentProvider.java:519)
      at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:491)
      at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:389)
      at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:251)
      at android.os.Binder.execTransact(Binder.java:682)



      I have tried almost everything like - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); but nothing helps. I am croping the image from camera.
      Activity code



      public class LocalAlbumActivity extends BaseActivity implements View.OnClickListener 

      private static final int REQUEST_IMAGE_CAPTURE_THEME = 1;
      private static final int REQUEST_IMAGE_CAPTURE_QRCODE_LOGO = 4;
      private static final int REQUEST_IMAGE_CROP_THEME = 2;
      private static final int REQUEST_IMAGE_CROP_QRCODE_LOGO = 5;
      private static final int REQUEST_ALBUM_DETAIL = 3;

      public static final String ALBUM_PATH = "album_path";
      public static final String ALBUM_NAME = "album_name";
      private LocalAlbumAdapter mLocalAlbumAdapter;
      private List<ImageBucket> mLocalAlbumList;
      private AsyncTask<Void, Void, List<ImageBucket>> mBucketLoadTask;
      private ListView mLocalAlbumListView;


      /**
      * 访问本地相册类型:0,主题;1,扫码;2,造码
      */
      private int mRequestType;

      @Override
      protected void onCreate(Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      OttoAppConfig.getInstance().register(this);

      setContentView(R.layout.activity_local_album);
      ViewGroup backGround = (ViewGroup) findViewById(R.id.background);
      MyUtil.setBackgroundBlur(backGround, this);

      initAdapter();
      assignViews();



      private void initAdapter()

      mLocalAlbumList = new ArrayList<>();
      mLocalAlbumAdapter = new LocalAlbumAdapter(this, mLocalAlbumList);
      //trying permission



      mBucketLoadTask = new AsyncTask<Void, Void, List<ImageBucket>>()

      @Override
      protected void onPreExecute()
      super.onPreExecute();
      // showLoading();


      @Override
      protected List<ImageBucket> doInBackground(Void... params)

      return LocalAlbumImagePickerHelper.getInstance(LocalAlbumActivity.this)
      .getImagesBucketList();


      @Override
      protected void onPostExecute(List<ImageBucket> list)
      dismissLoadingDialog();

      TextView emptyView = (TextView) findViewById(R.id.local_album_lv_empty);
      mLocalAlbumListView.setEmptyView(emptyView);

      mLocalAlbumList.addAll(list);
      mLocalAlbumAdapter.notifyDataSetChanged();

      ;

      mBucketLoadTask.execute();


      private void dismissLoadingDialog()
      ViewGroup progressBarLlyt = (ViewGroup) findViewById(R.id.progress_bar_llyt);
      progressBarLlyt.setVisibility(View.GONE);


      private void assignViews()
      TextView loadingMsg = (TextView) findViewById(R.id.loading_msg);
      loadingMsg.setText(R.string.scanning);

      ImageView backBtn = (ImageView) findViewById(R.id.action_back);
      TextView captureBtn = (TextView) findViewById(R.id.action_capture);

      backBtn.setOnClickListener(this);

      mRequestType = getIntent().getIntExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, 0);
      switch (mRequestType)
      // 主题
      case 0:
      // 造码
      case 2:
      captureBtn.setOnClickListener(this);
      break;
      // 扫码
      case 1:
      // 隐藏拍照按钮
      captureBtn.setVisibility(View.GONE);
      break;


      mLocalAlbumListView = (ListView) findViewById(R.id.local_album_lv);
      mLocalAlbumListView.setAdapter(mLocalAlbumAdapter);
      mLocalAlbumListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id)
      if (MyUtil.isFastDoubleClick())
      return;

      Intent intent = new Intent(LocalAlbumActivity.this, LocalAlbumDetailActivity.class);
      intent.putParcelableArrayListExtra(ALBUM_PATH,
      mLocalAlbumAdapter.getItem(position).bucketList);
      intent.putExtra(ALBUM_NAME, mLocalAlbumAdapter.getItem(position).bucketName);
      intent.putExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, mRequestType);
      startActivityForResult(intent, REQUEST_ALBUM_DETAIL);

      );

      // OverScrollDecoratorHelper.setUpOverScroll(mLocalAlbumListView);


      private Uri mImageUri;

      @Override
      public void onClick(View v)
      switch (v.getId())
      // 返回
      case R.id.action_back:
      myFinish();
      break;
      // 拍照
      case R.id.action_capture:
      PackageManager pm = getPackageManager();
      // FEATURE_CAMERA - 后置相机
      // FEATURE_CAMERA_FRONT - 前置相机
      if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) Intent.FLAG_GRANT_READ_URI_PERMISSION);

      intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
      startActivityForResult(intent, requestType);
      overridePendingTransition(0, R.anim.zoomin);
      else // 没有可用相机
      Intent intent = new Intent(this, MyDialogActivitySingle.class);
      intent.putExtra(WeacConstants.TITLE, getString(R.string.prompt));
      intent.putExtra(WeacConstants.DETAIL, getString(R.string.camera_error));
      startActivity(intent);

      break;



      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data)
      super.onActivityResult(requestCode, resultCode, data);
      if (resultCode != RESULT_OK)
      // 截图/相机返回
      overridePendingTransition(0, R.anim.zoomout);
      return;


      // 扫描二维码相册详细取消
      if (data != null)
      boolean isFinishMe = data.getBooleanExtra(LocalAlbumDetailActivity.FINISH_ACTIVITY, false);
      if (isFinishMe && !isFinishing())
      myFinish2();
      return;



      switch (requestCode)
      // 拍照(截取主题壁纸)
      case REQUEST_IMAGE_CAPTURE_THEME:
      cropImage(0, REQUEST_IMAGE_CROP_THEME, WeacConstants.DIY_WALLPAPER_PATH);
      break;
      // 拍照(截取二维码logo)
      case REQUEST_IMAGE_CAPTURE_QRCODE_LOGO:
      cropImage(1, REQUEST_IMAGE_CROP_QRCODE_LOGO, WeacConstants.DIY_QRCODE_LOGO_PATH);
      break;
      // 截图(截取主题壁纸)
      case REQUEST_IMAGE_CROP_THEME:
      String filePath = MyUtil.getFilePath(this, WeacConstants.DIY_WALLPAPER_PATH);
      // 更新壁纸信息
      MyUtil.saveWallpaper(this, WeacConstants.WALLPAPER_PATH, filePath);
      // 发送壁纸更新事件
      OttoAppConfig.getInstance().post(new WallpaperEvent());
      myFinish();
      break;
      // 截图(截取二维码logo)
      case REQUEST_IMAGE_CROP_QRCODE_LOGO:
      String logoPath = MyUtil.getFilePath(this, WeacConstants.DIY_QRCODE_LOGO_PATH);
      // 保存自定义二维码logo地址
      MyUtil.saveQRcodeLogoPath(this, logoPath);
      // 发送自定义二维码logo截取地址事件
      OttoAppConfig.getInstance().post(new QRcodeLogoEvent(logoPath));
      myFinish();
      break;
      // 相册详细图片
      case REQUEST_ALBUM_DETAIL:
      assert data != null;
      String url = data.getStringExtra(WeacConstants.IMAGE_URL);
      OttoAppConfig.getInstance().post(new ScanCodeEvent(url));
      myFinish2();
      break;



      private void cropImage(int type, int requestType, String path)

      ToastUtil.showLongToast(this, "path:"+path);
      Intent intent = MyUtil.getCropImageOptions(this, mImageUri, path, type);
      intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      if (intent.resolveActivity(getPackageManager()) != null)
      startActivityForResult(intent, requestType);
      overridePendingTransition(0, 0);
      else
      // 不可以复制其他应用的内部文件
      // TODO: 全屏裁剪&自定义裁剪功能
      ToastUtil.showLongToast(this, getString(R.string.no_crop_action));



      @Subscribe
      public void finishMeEvent(FinishLocalAlbumActivityEvent event)
      myFinish2();


      @Override
      public void onBackPressed()
      myFinish();


      private void myFinish()
      finish();
      if (mRequestType != 2)
      overridePendingTransition(0, R.anim.zoomout);
      else
      overridePendingTransition(0, R.anim.move_out_bottom);



      private void myFinish2()
      finish();
      overridePendingTransition(0, 0);


      @Override
      protected void onDestroy()
      super.onDestroy();
      OttoAppConfig.getInstance().unregister(this);
      if (null != mBucketLoadTask && mBucketLoadTask.getStatus() == AsyncTask.Status.RUNNING)
      mBucketLoadTask.cancel(true);





      Helper Methods



      /**
      * Returns specified directory(/mnt/sdcard/...).
      * directory will be created on SD card by defined path if card
      * is mounted. Else - Android defines files directory on device's
      * files(/data/data/<application package>/files) system.
      *
      * @param context context
      * @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jp")
      * @return File @link File directory
      */
      public static File getFileDirectory(Context context, String path)
      File file = null;
      if (isHasSDCard())
      file = new File(Environment.getExternalStorageDirectory(), path);
      if (!file.getParentFile().exists())
      if (!file.getParentFile().mkdirs())
      file = null;



      if (file == null)
      // 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
      // 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
      file = new File(context.getFilesDir(), path);

      return file;


      /**
      * Returns specified directory(/mnt/sdcard/Android/data/<application package>/files/...).
      * directory will be created on SD card by defined path if card
      * is mounted. Else - Android defines files directory on device's
      * files(/data/data/<application package>/files) system.
      *
      * @param context context
      * @param path file path (e.g.: "/music/a.mp3", "/pictures/a.jpg")
      * @return File @link File directory
      */
      public static File getExternalFileDirectory(Context context, String path)
      File file = null;
      if (isHasSDCard())
      file = new File(context.getExternalFilesDir(null), path);
      if (!file.getParentFile().exists())
      if (!file.getParentFile().mkdirs())
      file = null;



      if (file == null)
      // 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
      // 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
      file = new File(context.getFilesDir(), path);

      return file;


      public static boolean isHasSDCard()
      return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());


      /**
      * Returns directory absolutePath.
      *
      * @param context context
      * @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
      * @return /mnt/sdcard/Android/data/<application package>/files/....
      */
      public static String getFilePath(Context context, String path)
      return getExternalFileDirectory(context, path).getAbsolutePath();


      /**
      * set intent options
      *
      * @param context context
      * @param uri image path uri
      * @param filePath save path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
      * @param type 0,截取壁纸/拍照;1,截取Logo
      * @return Intent
      */
      public static Intent getCropImageOptions(Context context, Uri uri, String filePath, int type)
      int width;
      int height;
      // 截取壁纸/拍照
      if (type == 0)
      width = context.getResources().getDisplayMetrics().widthPixels;
      height = context.getResources().getDisplayMetrics().heightPixels;
      else // 截取logo
      width = height = dip2px(context, 30);

      //filePath="/Internal storage/Download/a.jpg";
      LogUtil.e(LOG_TAG, " filePath:" + filePath );
      Intent intent = new Intent();
      intent.setAction("com.android.camera.action.CROP");
      intent.setDataAndType(uri, "image/*");
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);


      intent.putExtra("crop", "true");
      // 裁剪框比例
      intent.putExtra("aspectX", width);
      intent.putExtra("aspectY", height);
      // 保存路径


      //#ToDO: Uri.fromFile change to FileProvider.getUriForFile
      Uri mImageUri;
      //mImageUri=Uri.fromFile(getExternalFileDirectory(context, filePath));

      intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".provider",getExternalFileDirectory(context, filePath)));

      // 是否去除面部检测
      intent.putExtra("noFaceDetection", true);

      intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
      // 是否保留比例
      intent.putExtra("scale", true);
      intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
      // 裁剪区的宽高
      intent.putExtra("outputX", width);
      intent.putExtra("outputY", height);

      // 是否将数据保留在Bitmap中返回
      intent.putExtra("return-data", false);
      return intent;










      share|improve this question













      I am trying to use camera and save image. Followed the steps as commonsware suggested. Constantly I am getting error -



      2018-11-12 02:10:54.588 3145-3173/com.bisw.weac E/DatabaseUtils: Writing exception to parcel
      java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri content://com.bisw.weac.provider/external_files/Android/data/com.bisw.weac/files/wallpaper/theme.jpg from pid=5566, uid=10071 requires the provider be exported, or grantUriPermission()
      at android.content.ContentProvider.enforceWritePermissionInner(ContentProvider.java:713)
      at android.content.ContentProvider$Transport.enforceWritePermission(ContentProvider.java:519)
      at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:491)
      at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:389)
      at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:251)
      at android.os.Binder.execTransact(Binder.java:682)



      I have tried almost everything like - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); but nothing helps. I am croping the image from camera.
      Activity code



      public class LocalAlbumActivity extends BaseActivity implements View.OnClickListener 

      private static final int REQUEST_IMAGE_CAPTURE_THEME = 1;
      private static final int REQUEST_IMAGE_CAPTURE_QRCODE_LOGO = 4;
      private static final int REQUEST_IMAGE_CROP_THEME = 2;
      private static final int REQUEST_IMAGE_CROP_QRCODE_LOGO = 5;
      private static final int REQUEST_ALBUM_DETAIL = 3;

      public static final String ALBUM_PATH = "album_path";
      public static final String ALBUM_NAME = "album_name";
      private LocalAlbumAdapter mLocalAlbumAdapter;
      private List<ImageBucket> mLocalAlbumList;
      private AsyncTask<Void, Void, List<ImageBucket>> mBucketLoadTask;
      private ListView mLocalAlbumListView;


      /**
      * 访问本地相册类型:0,主题;1,扫码;2,造码
      */
      private int mRequestType;

      @Override
      protected void onCreate(Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      OttoAppConfig.getInstance().register(this);

      setContentView(R.layout.activity_local_album);
      ViewGroup backGround = (ViewGroup) findViewById(R.id.background);
      MyUtil.setBackgroundBlur(backGround, this);

      initAdapter();
      assignViews();



      private void initAdapter()

      mLocalAlbumList = new ArrayList<>();
      mLocalAlbumAdapter = new LocalAlbumAdapter(this, mLocalAlbumList);
      //trying permission



      mBucketLoadTask = new AsyncTask<Void, Void, List<ImageBucket>>()

      @Override
      protected void onPreExecute()
      super.onPreExecute();
      // showLoading();


      @Override
      protected List<ImageBucket> doInBackground(Void... params)

      return LocalAlbumImagePickerHelper.getInstance(LocalAlbumActivity.this)
      .getImagesBucketList();


      @Override
      protected void onPostExecute(List<ImageBucket> list)
      dismissLoadingDialog();

      TextView emptyView = (TextView) findViewById(R.id.local_album_lv_empty);
      mLocalAlbumListView.setEmptyView(emptyView);

      mLocalAlbumList.addAll(list);
      mLocalAlbumAdapter.notifyDataSetChanged();

      ;

      mBucketLoadTask.execute();


      private void dismissLoadingDialog()
      ViewGroup progressBarLlyt = (ViewGroup) findViewById(R.id.progress_bar_llyt);
      progressBarLlyt.setVisibility(View.GONE);


      private void assignViews()
      TextView loadingMsg = (TextView) findViewById(R.id.loading_msg);
      loadingMsg.setText(R.string.scanning);

      ImageView backBtn = (ImageView) findViewById(R.id.action_back);
      TextView captureBtn = (TextView) findViewById(R.id.action_capture);

      backBtn.setOnClickListener(this);

      mRequestType = getIntent().getIntExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, 0);
      switch (mRequestType)
      // 主题
      case 0:
      // 造码
      case 2:
      captureBtn.setOnClickListener(this);
      break;
      // 扫码
      case 1:
      // 隐藏拍照按钮
      captureBtn.setVisibility(View.GONE);
      break;


      mLocalAlbumListView = (ListView) findViewById(R.id.local_album_lv);
      mLocalAlbumListView.setAdapter(mLocalAlbumAdapter);
      mLocalAlbumListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id)
      if (MyUtil.isFastDoubleClick())
      return;

      Intent intent = new Intent(LocalAlbumActivity.this, LocalAlbumDetailActivity.class);
      intent.putParcelableArrayListExtra(ALBUM_PATH,
      mLocalAlbumAdapter.getItem(position).bucketList);
      intent.putExtra(ALBUM_NAME, mLocalAlbumAdapter.getItem(position).bucketName);
      intent.putExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, mRequestType);
      startActivityForResult(intent, REQUEST_ALBUM_DETAIL);

      );

      // OverScrollDecoratorHelper.setUpOverScroll(mLocalAlbumListView);


      private Uri mImageUri;

      @Override
      public void onClick(View v)
      switch (v.getId())
      // 返回
      case R.id.action_back:
      myFinish();
      break;
      // 拍照
      case R.id.action_capture:
      PackageManager pm = getPackageManager();
      // FEATURE_CAMERA - 后置相机
      // FEATURE_CAMERA_FRONT - 前置相机
      if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) Intent.FLAG_GRANT_READ_URI_PERMISSION);

      intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
      startActivityForResult(intent, requestType);
      overridePendingTransition(0, R.anim.zoomin);
      else // 没有可用相机
      Intent intent = new Intent(this, MyDialogActivitySingle.class);
      intent.putExtra(WeacConstants.TITLE, getString(R.string.prompt));
      intent.putExtra(WeacConstants.DETAIL, getString(R.string.camera_error));
      startActivity(intent);

      break;



      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data)
      super.onActivityResult(requestCode, resultCode, data);
      if (resultCode != RESULT_OK)
      // 截图/相机返回
      overridePendingTransition(0, R.anim.zoomout);
      return;


      // 扫描二维码相册详细取消
      if (data != null)
      boolean isFinishMe = data.getBooleanExtra(LocalAlbumDetailActivity.FINISH_ACTIVITY, false);
      if (isFinishMe && !isFinishing())
      myFinish2();
      return;



      switch (requestCode)
      // 拍照(截取主题壁纸)
      case REQUEST_IMAGE_CAPTURE_THEME:
      cropImage(0, REQUEST_IMAGE_CROP_THEME, WeacConstants.DIY_WALLPAPER_PATH);
      break;
      // 拍照(截取二维码logo)
      case REQUEST_IMAGE_CAPTURE_QRCODE_LOGO:
      cropImage(1, REQUEST_IMAGE_CROP_QRCODE_LOGO, WeacConstants.DIY_QRCODE_LOGO_PATH);
      break;
      // 截图(截取主题壁纸)
      case REQUEST_IMAGE_CROP_THEME:
      String filePath = MyUtil.getFilePath(this, WeacConstants.DIY_WALLPAPER_PATH);
      // 更新壁纸信息
      MyUtil.saveWallpaper(this, WeacConstants.WALLPAPER_PATH, filePath);
      // 发送壁纸更新事件
      OttoAppConfig.getInstance().post(new WallpaperEvent());
      myFinish();
      break;
      // 截图(截取二维码logo)
      case REQUEST_IMAGE_CROP_QRCODE_LOGO:
      String logoPath = MyUtil.getFilePath(this, WeacConstants.DIY_QRCODE_LOGO_PATH);
      // 保存自定义二维码logo地址
      MyUtil.saveQRcodeLogoPath(this, logoPath);
      // 发送自定义二维码logo截取地址事件
      OttoAppConfig.getInstance().post(new QRcodeLogoEvent(logoPath));
      myFinish();
      break;
      // 相册详细图片
      case REQUEST_ALBUM_DETAIL:
      assert data != null;
      String url = data.getStringExtra(WeacConstants.IMAGE_URL);
      OttoAppConfig.getInstance().post(new ScanCodeEvent(url));
      myFinish2();
      break;



      private void cropImage(int type, int requestType, String path)

      ToastUtil.showLongToast(this, "path:"+path);
      Intent intent = MyUtil.getCropImageOptions(this, mImageUri, path, type);
      intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      if (intent.resolveActivity(getPackageManager()) != null)
      startActivityForResult(intent, requestType);
      overridePendingTransition(0, 0);
      else
      // 不可以复制其他应用的内部文件
      // TODO: 全屏裁剪&自定义裁剪功能
      ToastUtil.showLongToast(this, getString(R.string.no_crop_action));



      @Subscribe
      public void finishMeEvent(FinishLocalAlbumActivityEvent event)
      myFinish2();


      @Override
      public void onBackPressed()
      myFinish();


      private void myFinish()
      finish();
      if (mRequestType != 2)
      overridePendingTransition(0, R.anim.zoomout);
      else
      overridePendingTransition(0, R.anim.move_out_bottom);



      private void myFinish2()
      finish();
      overridePendingTransition(0, 0);


      @Override
      protected void onDestroy()
      super.onDestroy();
      OttoAppConfig.getInstance().unregister(this);
      if (null != mBucketLoadTask && mBucketLoadTask.getStatus() == AsyncTask.Status.RUNNING)
      mBucketLoadTask.cancel(true);





      Helper Methods



      /**
      * Returns specified directory(/mnt/sdcard/...).
      * directory will be created on SD card by defined path if card
      * is mounted. Else - Android defines files directory on device's
      * files(/data/data/<application package>/files) system.
      *
      * @param context context
      * @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jp")
      * @return File @link File directory
      */
      public static File getFileDirectory(Context context, String path)
      File file = null;
      if (isHasSDCard())
      file = new File(Environment.getExternalStorageDirectory(), path);
      if (!file.getParentFile().exists())
      if (!file.getParentFile().mkdirs())
      file = null;



      if (file == null)
      // 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
      // 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
      file = new File(context.getFilesDir(), path);

      return file;


      /**
      * Returns specified directory(/mnt/sdcard/Android/data/<application package>/files/...).
      * directory will be created on SD card by defined path if card
      * is mounted. Else - Android defines files directory on device's
      * files(/data/data/<application package>/files) system.
      *
      * @param context context
      * @param path file path (e.g.: "/music/a.mp3", "/pictures/a.jpg")
      * @return File @link File directory
      */
      public static File getExternalFileDirectory(Context context, String path)
      File file = null;
      if (isHasSDCard())
      file = new File(context.getExternalFilesDir(null), path);
      if (!file.getParentFile().exists())
      if (!file.getParentFile().mkdirs())
      file = null;



      if (file == null)
      // 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
      // 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
      file = new File(context.getFilesDir(), path);

      return file;


      public static boolean isHasSDCard()
      return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());


      /**
      * Returns directory absolutePath.
      *
      * @param context context
      * @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
      * @return /mnt/sdcard/Android/data/<application package>/files/....
      */
      public static String getFilePath(Context context, String path)
      return getExternalFileDirectory(context, path).getAbsolutePath();


      /**
      * set intent options
      *
      * @param context context
      * @param uri image path uri
      * @param filePath save path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
      * @param type 0,截取壁纸/拍照;1,截取Logo
      * @return Intent
      */
      public static Intent getCropImageOptions(Context context, Uri uri, String filePath, int type)
      int width;
      int height;
      // 截取壁纸/拍照
      if (type == 0)
      width = context.getResources().getDisplayMetrics().widthPixels;
      height = context.getResources().getDisplayMetrics().heightPixels;
      else // 截取logo
      width = height = dip2px(context, 30);

      //filePath="/Internal storage/Download/a.jpg";
      LogUtil.e(LOG_TAG, " filePath:" + filePath );
      Intent intent = new Intent();
      intent.setAction("com.android.camera.action.CROP");
      intent.setDataAndType(uri, "image/*");
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);


      intent.putExtra("crop", "true");
      // 裁剪框比例
      intent.putExtra("aspectX", width);
      intent.putExtra("aspectY", height);
      // 保存路径


      //#ToDO: Uri.fromFile change to FileProvider.getUriForFile
      Uri mImageUri;
      //mImageUri=Uri.fromFile(getExternalFileDirectory(context, filePath));

      intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".provider",getExternalFileDirectory(context, filePath)));

      // 是否去除面部检测
      intent.putExtra("noFaceDetection", true);

      intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
      // 是否保留比例
      intent.putExtra("scale", true);
      intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
      // 裁剪区的宽高
      intent.putExtra("outputX", width);
      intent.putExtra("outputY", height);

      // 是否将数据保留在Bitmap中返回
      intent.putExtra("return-data", false);
      return intent;







      android android-intent android-camera android-manifest






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 12 at 2:31









      Biswajit Das

      317418




      317418






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          You need to add the following in provider declaration in your manifest file



           <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="<application-id>.fileprovider" // com.abc.def
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
          </provider>





          share|improve this answer




















          • I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
            – Biswajit Das
            Nov 12 at 16:52










          • You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
            – Vishal Arora
            Nov 13 at 5:59










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255297%2fjava-lang-securityexception-permission-denial-writing-android-support-v4-conte%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          You need to add the following in provider declaration in your manifest file



           <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="<application-id>.fileprovider" // com.abc.def
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
          </provider>





          share|improve this answer




















          • I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
            – Biswajit Das
            Nov 12 at 16:52










          • You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
            – Vishal Arora
            Nov 13 at 5:59














          up vote
          0
          down vote













          You need to add the following in provider declaration in your manifest file



           <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="<application-id>.fileprovider" // com.abc.def
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
          </provider>





          share|improve this answer




















          • I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
            – Biswajit Das
            Nov 12 at 16:52










          • You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
            – Vishal Arora
            Nov 13 at 5:59












          up vote
          0
          down vote










          up vote
          0
          down vote









          You need to add the following in provider declaration in your manifest file



           <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="<application-id>.fileprovider" // com.abc.def
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
          </provider>





          share|improve this answer












          You need to add the following in provider declaration in your manifest file



           <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="<application-id>.fileprovider" // com.abc.def
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
          </provider>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 12 at 6:40









          Vishal Arora

          963




          963











          • I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
            – Biswajit Das
            Nov 12 at 16:52










          • You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
            – Vishal Arora
            Nov 13 at 5:59
















          • I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
            – Biswajit Das
            Nov 12 at 16:52










          • You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
            – Vishal Arora
            Nov 13 at 5:59















          I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
          – Biswajit Das
          Nov 12 at 16:52




          I have already done the same as described link. One differance is android:authorities="<application-id>.fileprovider" with android:authorities="$applicationId.my.package.name.provider" Does it make any difference?
          – Biswajit Das
          Nov 12 at 16:52












          You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
          – Vishal Arora
          Nov 13 at 5:59




          You use this $applicationId.my.package.name.provider if you have a custom FileProvider class extending Android FileProvider class. If you dont have one then you need to use $applicationId.fileprovider
          – Vishal Arora
          Nov 13 at 5:59

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255297%2fjava-lang-securityexception-permission-denial-writing-android-support-v4-conte%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          How to read a connectionString WITH PROVIDER in .NET Core?

          Node.js Script on GitHub Pages or Amazon S3

          Museum of Modern and Contemporary Art of Trento and Rovereto