ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

防止AlertDialog在另一个DialogFragment的暗号后面显示

2019-11-18 06:27:58  阅读:210  来源: 互联网

标签:android-dialog bottom-sheet android-dialogfragment runtime-permissions android


我正在创建一个BottomSheetDialogFragment,允许用户拍摄照片或从图库中选择一张照片.要访问这两个功能,需要WRITE_EXTERNAL_STORAGE权限.

因此,我想从BottomSheetDialogFragment寻求许可,以防止用户在授予许可之前单击任何其他内容.如果我在onViewCreated中请求权限,则权限对话框显示良好:

Permission Request

但是,如果权限被拒绝并且用户再次尝试,我将尝试在AlertDialog中显示基本原理,但对话框将被阻止;大概是由于BottomSheetDialogFragment的暗淡:

Permission Rationale

我认为这是由BottomSheetDialogFragment的动画引起的,该动画在片段完成其动画之前不会显示背景暗淡.这恰巧发生在onViewCreated之后.有谁知道有没有办法在不关闭或关闭BottomSheetDialogFragment的情况下将AlertDialog强制到最前面?还是有办法监听BottomSheetDialogFragment动画完成?

我知道我可以在添加BottomSheetDialogFragment之前请求权限,但是我宁愿在对话框中请求它,以为用户提供一些上下文.

这是片段:

public class ImageChooserDialogFragment extends BottomSheetDialogFragment {

    public interface OnImageChosenListener {
        void onImageChosen(Uri data);
    }

    private static final String PREFIX_IMAGE_CAPTURE = "IMG_";

    private static final int REQUEST_PERMISSION_CAMERA  = 0;
    private static final int REQUEST_PERMISSION_STORAGE = 1;

    private static final int REQUEST_IMAGE_CAPTURE      = 2;
    private static final int REQUEST_IMAGE_SELECTION    = 3;

    private static final String[] PERMISSIONS_CAMERA = new String[] {
            Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA
    };

    private static final String[] PERMISSIONS_STORAGE = new String[] {
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    private boolean hasFeatureCamera;

    private Uri mCurrentPhotoResource;

    private View mView;

    private OnImageChosenListener mOnImageChosenListener;

    public static ImageChooserDialogFragment newInstance() {
        return new ImageChooserDialogFragment();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Timber.d("onAttach");

        if(context instanceof OnImageChosenListener) {
            mOnImageChosenListener = (OnImageChosenListener) context;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Fragment parent = getParentFragment();

        if(parent != null) {
            onAttachToFragment(parent);
        }

        PackageManager manager = getContext().getPackageManager();
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            hasFeatureCamera = manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
        } else {
            hasFeatureCamera = manager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
                    || manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
        }
    }

    public void onAttachToFragment(Fragment fragment) {
        if(fragment instanceof OnImageChosenListener) {
            mOnImageChosenListener = (OnImageChosenListener) fragment;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mView = inflater.inflate(R.layout.dialog_image_chooser, container, false);
        ButterKnife.bind(this, mView);

        if(!hasFeatureCamera) {
            mView.setVisibility(View.GONE);
        }

        return mView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if(!PermissionUtil.checkPermissions(getContext(), PERMISSIONS_STORAGE)) {
            requestPermissionsWithRationale(REQUEST_PERMISSION_STORAGE, PERMISSIONS_STORAGE);
        } else if(!hasFeatureCamera) {
            dispatchImageSelectionIntent();
        } else {
            displayRequestPermissionsAlert(R.string.msg_snackbar_permissions_storage);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        switch(requestCode) {
            case REQUEST_PERMISSION_CAMERA:
                if(PermissionUtil.verifyPermissions(grantResults)) {
                    dispatchImageCaptureIntent();
                } else {
                    displayRequestPermissionsAlert(R.string.msg_snackbar_permissions_camera);
                } break;
            case REQUEST_PERMISSION_STORAGE:
                if(PermissionUtil.verifyPermissions(grantResults)) {
                    if(!hasFeatureCamera) {
                        dispatchImageSelectionIntent();
                    }
                } else {
                    displayRequestPermissionsAlert(R.string.msg_snackbar_permissions_storage);
                } break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_IMAGE_CAPTURE:
                if(resultCode == Activity.RESULT_OK) {
                    handleImageCaptureResult(data);
                } else {
                    destroyTemporaryFile();
                } break;
            case REQUEST_IMAGE_SELECTION:
                if(resultCode == Activity.RESULT_OK) {
                    handleImageSelectionResult(data);
                } break;
            default:
                super.onActivityResult(requestCode, resultCode, data);
        }
    }

    @OnClick(R.id.photo_take)
    public void onClickCapture() {
        if(!PermissionUtil.checkPermissions(getContext(), PERMISSIONS_CAMERA)) {
            requestPermissionsWithRationale(REQUEST_PERMISSION_CAMERA, PERMISSIONS_CAMERA);
        } else {
            dispatchImageCaptureIntent();
        }
    }

    @OnClick(R.id.photo_choose)
    public void onClickChoose() {
        if(!PermissionUtil.checkPermissions(getContext(), PERMISSIONS_STORAGE)) {
            requestPermissionsWithRationale(REQUEST_PERMISSION_STORAGE, PERMISSIONS_STORAGE);
        } else {
            dispatchImageSelectionIntent();
        }
    }

    private void dispatchImageCaptureIntent() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        if(intent.resolveActivity(getContext().getPackageManager()) != null) {
            try {
                File image = createTemporaryFile();
                Uri data = FileProvider.getUriForFile(getContext(), "com.example.app.fileprovider", image);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, data);
                startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
            } catch (IOException exception) {
                Timber.w(exception, "Error occurred while creating image file");
            }
        } else {
            // TODO: handle no application to handle intent
        }
    }

    private void dispatchImageSelectionIntent() {
        final Intent intent = new Intent(Intent.ACTION_PICK,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        if(intent.resolveActivity(getContext().getPackageManager()) != null) {
            startActivityForResult(intent, REQUEST_IMAGE_SELECTION);
        } else {
            // TODO: handle no application to handle intent
        } dismiss();
    }

    private void dispatchDetailSettingsIntent() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                Uri.fromParts("package", getContext().getPackageName(), null));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        if(intent.resolveActivity(getContext().getPackageManager()) != null) {
            startActivity(intent);
        } else {
            // TODO: handle no application to handle intent
        } dismiss();
    }

    private void dispatchMediaScanIntent(Uri data) {
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data);
        getContext().sendBroadcast(intent);
    }

    private void displayPermissionsRationale(int requestCode) {
        switch (requestCode) {
            case REQUEST_PERMISSION_CAMERA:
                Timber.d("Request Image capture rationale");
                DialogFactory.createRationaleAlert(getContext(),
                        R.string.title_dialog_rationale_camera,
                        R.string.msg_dialog_rationale_camera).show();
                break;
            case REQUEST_PERMISSION_STORAGE:
                Timber.d("Request Image selection rationale");
                DialogFactory.createRationaleAlert(getContext(),
                        R.string.title_dialog_rationale_storage,
                        R.string.msg_dialog_rationale_storage).show();
                break;
            default:
                Timber.d("No rationale");
        }
    }

    private void displayRequestPermissionsAlert(@StringRes int message) {
        Snackbar.make(mView, message, Snackbar.LENGTH_LONG)
                .setAction(R.string.action_settings, view -> dispatchDetailSettingsIntent()).show();
        dismiss();
    }

    private void requestPermissionsWithRationale(int requestCode, @NonNull String[] permissions) {
        Timber.d("Request permissions with rationale");
        if(PermissionUtil.shouldShowRequestPermissionsRationale(this, permissions)) {
            Timber.d("Display rationale");
            displayPermissionsRationale(requestCode);
        } else {
            Timber.d("Request Permissions");
            requestPermissions(permissions, requestCode);
        }
    }

    private File createTemporaryFile() throws IOException {
        String fileName = PREFIX_IMAGE_CAPTURE /*+ TimeUtil.getTimeStamp()*/;

        File directory = getContext().getExternalFilesDir(Environment.DIRECTORY_DCIM);
        File file = File.createTempFile(fileName, ".jpeg", directory);

        mCurrentPhotoResource = Uri.fromFile(file);

        return file;
    }

    private void destroyTemporaryFile() {
        File file = new File(mCurrentPhotoResource.getPath());

        if(file.delete()) {
            Timber.i("Temporary file deleted");
        } else {
            Timber.w("Failed to delete temporary file: " + file);
        }
    }

    private void handleImageCaptureResult(Intent intent) {
        if(mCurrentPhotoResource != null) {
            dispatchMediaScanIntent(mCurrentPhotoResource);

            if (mOnImageChosenListener != null) {
                mOnImageChosenListener.onImageChosen(mCurrentPhotoResource);
            } else {
                Timber.w("Parent Activity or Fragment does not implement OnImageChosenListener; captured result cannot be used");
            }
        }
    }

    private void handleImageSelectionResult(Intent intent) {
        Timber.d("Selection: " + intent.getData());
        if(mOnImageChosenListener != null) {
            mOnImageChosenListener.onImageChosen(intent.getData());
        } else {
            Timber.w("Parent Activity or Fragment does not implement OnImageChosenListener; selected result cannot be used");
        }
    }

}

和DialogFactory类:

public final class DialogFactory {

    public static AlertDialog createRationaleAlert(
            Context context, @StringRes int title, @StringRes int message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context)
                .setTitle(title).setMessage(message);
        return createRationaleAlert(context, builder);
    }

    public static AlertDialog createRationaleAlert(
            Context context, CharSequence title, CharSequence message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context)
                .setTitle(title).setMessage(message);
        return createRationaleAlert(context, builder);
    }

    private static AlertDialog createRationaleAlert(
            Context context, AlertDialog.Builder builder) {
        builder.setPositiveButton(R.string.btn_try, (dialog, which) -> {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            context.startActivity(intent);
        }).setNegativeButton(R.string.btn_cancel, (dialog, which) -> {
            dialog.cancel();
        });

        return builder.create();
    }

}

当片段调用DialogFactory.createRationaleAlert().show()时,会发生此问题.

解决方法:

经过深思熟虑,我终于找到了解决方案.诀窍是实现DialogInterface.OnShowListener,并在onShow()回调中创建新的Dialog:

public class ImageChooserDialogFragment extends BottomSheetDialogFragment
        implements DialogInterface.OnShowListener {

    @Override @NonNull
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        super.onCreateDialog(savedInstanceState);
        getDialog().setOnShowListener(this);
    }

    @Override
    public void onShow(DialogInterface dialog) {
        if(!PermissionUtil.checkPermissions(getContext(), PERMISSIONS_STORAGE)) {
            requestPermissionsWithRationale(REQUEST_PERMISSION_STORAGE, PERMISSIONS_STORAGE);
        } else {
            displayRequestPermissionsAlert(R.string.msg_snackbar_permissions_storage);
        }
    }

    // ...

}

标签:android-dialog,bottom-sheet,android-dialogfragment,runtime-permissions,android
来源: https://codeday.me/bug/20191118/2026005.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有