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

3

12

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.

Komsomol answered 22/4, 2019 at 14:43 Comment(4)
No one knows the solution of this ? ? ?Komsomol
I'm confused about what you're asking. I edited the question based on what I thought you were asking, but I see you've rejected that edit. Could you explain how what you're asking is different from what I asked in the edit?Misname
The problem is how to get real_path instead of content URI of file that is present inside our android device in android 29Komsomol
Is there any solution?Hanoi
K
2

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();
    }



    }
Komsomol answered 24/3, 2020 at 19:51 Comment(5)
Is it possible to get the name of the original file?Maffei
@SudhirKhanger yes its pretty simple once you will get the URI in onActivityResult () method just call getContext().getContentResolver().query() method .. in query method pass Uri and the columns array in your case just pass DISPLAY_NAME Column. And you can get the name of that file. For Coding example check how to use query method on google.Komsomol
Can you please post the header files that you have usedPsychokinesis
@AmanpreetKaur What exactly you want to check. I do not have this code now. Tell me what exactly you want to check I will try to help you.Komsomol
@Komsomol I have resolved the issue. Thank you for replying. Will definitely post here in case anyone needsPsychokinesis
H
1

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.

Hedjaz answered 15/8, 2019 at 10:36 Comment(0)
P
0

in my case I used cacheDir

val fileDescriptorPath = fileDescriptor(myUri)
//use path and then delete it
fileDescriptorPath?.delete()

private fun fileDescriptor(uri: Uri?): File? {
    if (uri == null) return null
    var input: FileInputStream? = null
    var output: FileOutputStream? = null
    val filePath: String = File(context.cacheDir, "tmp.fileExtension").absolutePath
   return try {
       val parcelFileDescriptor: ParcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, "r")!!
       val fileDescriptor = parcelFileDescriptor.fileDescriptor
        input = FileInputStream(fileDescriptor)
        output = FileOutputStream(filePath)
        var read: Int
        val bytes = ByteArray(1024)
        while (input.read(bytes).also { read = it } != -1) {
            output.write(bytes, 0, read)
        }
        parcelFileDescriptor.close()
        File(filePath)
    } catch (ignored: IOException) {
        Log.v("pathFileDescriptor", "IOException: ${ignored.message}")
       null
    } finally {
        input?.close()
        output?.close()
    }
}
Peony answered 14/10, 2023 at 11:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.