Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get media item real_Path from contentResolver.openFileDescriptor(Uri uri, String s) in Android Q?

MediaStore.MediaColumns.DATA constant was deprecated in API level Q.

Apps may not have filesystem permissions to directly access this path. Instead of trying to open this path directly, apps should use ContentResolver#openFileDescriptor(Uri, String) to gain access. This value will always be NULL for apps targeting Build.VERSION_CODES.Q or higher.

like image 279
Paranoid Avatar asked Apr 22 '19 14:04

Paranoid


2 Answers

This is true we can't get the real path. Just Simple method open stream with contentResolver() and copy the whole content of file into new file and for getting file information we need to call a query() method of a getContentResolver().query() then we can get DISPLAY_NAME of the file and some more info like FILE_SIZE.

Simple code Example for those who upvoted the question:

public class MainFragment extends Fragment {

    private Button openGallery;
    private File selectedFile;
    private Context context;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        context = container.getContext();
        return inflater.inflate(R.layout.fragment_question, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        openGallery = view.findViewById(R.id.openGallery);
        openGallery.setOnClickListener(v->browseFile());
    }


    private void browseFile() {

        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            openFiles();
        } else {
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 786);
        }
    }

    private void openFiles() {

        deleteFileFromCacheDir();

        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);

        if (intent.resolveActivity(context.getPackageManager()) != null) {
            startActivityForResult(intent, 786);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 786 && resultCode == -1 && data != null) {

            Uri uri = data.getData();
            openStreamAndCopyContent(uri); // Here i am just copy the content of file and paste it into my new file. You can check the type of the file image/video/audio & do it whatever you want

            // Now here is your file

            if (selectedFile != null && selectedFile.exists()){
                // Do it whatever you want Or send it to server 
            } 

        }

    }

    private void openStreamAndCopyContent(Uri uri) {

        try {

            String fileName = "temp" + System.currentTimeMillis() + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(context.getContentResolver().getType(uri));
            selectedFile = new File(context.getCacheDir().getAbsolutePath() + File.separator + fileName);

            InputStream inputStream = context.getContentResolver().openInputStream(uri);

            if (inputStream != null) {
                Utility.copy(inputStream, selectedFile);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == 786) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                openFiles();
            } else if (grantResults[0] == PackageManager.PERMISSION_DENIED && getActivity() != null) {

                if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) {

                    new AlertDialog.Builder(context).setTitle(R.string.permission_required).setMessage(R.string.permission_message)
                            .setPositiveButton(R.string.open_settings, (dialog, which) ->
                                    context.startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                            Uri.parse("package:" + BuildConfig.APPLICATION_ID)))).setNegativeButton(R.string.close, null).show();
                }
            }
        }
    }


    private void deleteFileFromCacheDir() {

        if (selectedFile != null && selectedFile.exists()) {
            if (selectedFile.delete()) {
                selectedFile = null;
            }
        }
    }

    @Override
    public void onDestroyView() {

        deleteFileFromCacheDir();

        super.onDestroyView();
    }



    }
like image 130
Paranoid Avatar answered Nov 20 '22 11:11

Paranoid


I believe it is not possible, as you simply don't need that path from a programming stand point.

You cannot read/change/delete the file with the real path. You should use a ContentResolver for these operations as stated in your question.

If you just want to show the path to the user, then I would suggest to either give an option to open/share the file with an Intent.createChooser or just show the MediaColumns.RELATIVE_PATH.

like image 28
cuzi Avatar answered Nov 20 '22 11:11

cuzi