0

I have an application which tries to take pdf and save it to internal storage. But I am unable to get Pdf Path as source path correctly. How can I do achieve that real path.

Here is my getPdfPath function:

 private fun getPdfPath(data: Intent): String? {
        val pdfPath = data.data // Selected Pdfs Uri
        val file = File(pdfPath?.path)
        val split: List<String> = file.path.split(":")
        val filePath = split[1]
        return filePath
    }

Here is onActivityResult for button to select pdf:

OPERATION_CHOOSE_PDF -> {
                if (resultCode == Activity.RESULT_OK) {

                    val source = getPdfPath(data!!) //Source of pdf path to copy
                    val contextWrapper = ContextWrapper(this@MainActivity)
                    directoryPDF = contextWrapper.getDir("pdfFileDir", Context.MODE_PRIVATE)
                    val file = File("$directoryPDF/$FILE_NAME")
                    Toast.makeText(this, "$file", Toast.LENGTH_LONG).show()

                    if (source != null) {
                        copyFileUsingStream(source, file)
                    }

                }
            }

1 Answers1

1

I tried this, and it works.. Here I am giving the Kotlin version of the mentioned answer

@SuppressLint("NewApi")
    fun getPath(uri: Uri): String? {
        // check here to KITKAT or new version
        val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
        var selection: String? = null
        var selectionArgs: Array<String>? = null
        // DocumentProvider
        if (isKitKat)  {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {

                Log.d(TAG, "getPath: External Storage")

                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":").toTypedArray()
                val type = split[0]
                val fullPath = getPathFromExtSD(split)

                Log.d(TAG, "getPath: External Storage Path: $fullPath")
                return if (fullPath !== "") {
                    fullPath
                } else {
                    null
                }
            }


            // DownloadsProvider
            if (isDownloadsDocument(uri)) {

                Log.d(TAG, "getPath: From Downloads")

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    var cursor: Cursor? = null
                    try {
                        cursor = context.contentResolver.query(
                            uri,
                            arrayOf(MediaStore.MediaColumns.DISPLAY_NAME),
                            null,
                            null,
                            null
                        )
                        if (cursor != null && cursor.moveToFirst()) {
                            val fileName = cursor.getString(0)
//                            val path =
//                                Environment.getExternalStorageDirectory().absolutePath
//                                    .toString() + "/Download/" + fileName
//
//                            Log.d(TAG, "getPath: From Download Path: $path")
//
//                            if (!TextUtils.isEmpty(path)) {
//                                return path
//                            }
                        }
                    } finally {
                        cursor?.close()
                    }
                    val id: String = DocumentsContract.getDocumentId(uri)
                    Log.d(TAG, "getPath: From Download ID: $id")
                    if (!TextUtils.isEmpty(id)) {
                        if (id.startsWith("raw:")) {
                            return id.replaceFirst("raw:".toRegex(), "")
                        }
                        val contentUriPrefixesToTry =
                            arrayOf(
                                "content://downloads/public_downloads",
                                "content://downloads/my_downloads"
                            )
                        for (contentUriPrefix in contentUriPrefixesToTry) {
                            return try {
                                val contentUri = ContentUris.withAppendedId(
                                    Uri.parse(contentUriPrefix),
                                    java.lang.Long.valueOf(id)
                                )
                                getDataColumn(context, contentUri, null, null)
                            } catch (e: NumberFormatException) {
                                //In Android 8 and Android P the id is not a number
                                uri.path!!.replaceFirst("^/document/raw:".toRegex(), "")
                                    .replaceFirst("^raw:".toRegex(), "")
                            }
                        }
                    }
                }
                else {
                    val id = DocumentsContract.getDocumentId(uri)
                    if (id.startsWith("raw:")) {
                        return id.replaceFirst("raw:".toRegex(), "")
                    }
                    try {
                        contentUri = ContentUris.withAppendedId(
                            Uri.parse("content://downloads/public_downloads"),
                            java.lang.Long.valueOf(id)
                        )
                    } catch (e: NumberFormatException) {
                        e.printStackTrace()
                    }
                    if (contentUri != null) {
                        return getDataColumn(context, contentUri!!, null, null)
                    }
                }
            }


            // MediaProvider
            if (isMediaDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":").toTypedArray()
                val type = split[0]
                var contentUri: Uri? = null
                if ("image" == type) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                } else if ("video" == type) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                } else if ("audio" == type) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                }
                selection = "_id=?"
                selectionArgs = arrayOf(split[1])
                return getDataColumn(
                    context, contentUri, selection,
                    selectionArgs
                )
            }
            if (isGoogleDriveUri(uri)) {
                return getDriveFilePath(uri)
            }
            if (isWhatsAppFile(uri)) {
                return getFilePathForWhatsApp(uri)
            }
            if ("content".equals(uri.scheme, ignoreCase = true)) {
                if (isGooglePhotosUri(uri)) {
                    return uri.lastPathSegment
                }
                if (isGoogleDriveUri(uri)) {
                    return getDriveFilePath(uri)
                }
                return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

                    // return getFilePathFromURI(context,uri);

                    var path:String?=null

                    GlobalScope.launch(Dispatchers.IO) {
                        path = copyFileToInternalStorage(uri, "userfiles")
                    }

                    Thread.sleep(1000)
                    path

                    // return getRealPathFromURI(context,uri);
                } else {
                    getDataColumn(context, uri, null, null)
                }
            }
            if ("file".equals(uri.scheme, ignoreCase = true)) {
                return uri.path
            }
        }
        else {
            if (isWhatsAppFile(uri)) {
                return getFilePathForWhatsApp(uri)
            }
            if ("content".equals(uri.scheme, ignoreCase = true)) {
                val projection = arrayOf(
                    MediaStore.Images.Media.DATA
                )
                var cursor: Cursor? = null
                try {
                    cursor = context.contentResolver
                        .query(uri, projection, selection, selectionArgs, null)
                    val column_index =
                        cursor?.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
                    if (cursor!!.moveToFirst()) {
                        return cursor.getString(column_index!!)
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                } finally {
                    cursor?.close()
                }
            }
        }
        return null
    }

    private fun fileExists(filePath: String): Boolean {
        val file = File(filePath)
        return file.exists()
    }

    private fun getPathFromExtSD(pathData: Array<String>): String {
        val type = pathData[0]
        val relativePath = "/" + pathData[1]
        var fullPath = ""

        // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
        // something like "71F8-2C0A", some kind of unique id per storage
        // don't know any API that can get the root path of that storage based on its id.
        //
        // so no "primary" type, but let the check here for other devices
        if ("primary".equals(type, ignoreCase = true)) {
            fullPath =
                Environment.getExternalStorageDirectory().toString() + relativePath
            if (fileExists(fullPath)) {
                return fullPath
            }
        }

        // Environment.isExternalStorageRemovable() is `true` for external and internal storage
        // so we cannot relay on it.
        //
        // instead, for each possible path, check if file exists
        // we'll start with secondary storage as this could be our (physically) removable sd card
        fullPath = System.getenv("SECONDARY_STORAGE") + relativePath
        if (fileExists(fullPath)) {
            return fullPath
        }
        fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath
        return if (fileExists(fullPath)) {
            fullPath
        } else fullPath
    }

    private fun getDriveFilePath(uri: Uri): String? {
        val returnCursor: Cursor =
            context.contentResolver.query(uri, null, null, null, null)!!
        /*
         * Get the column indexes of the data in the Cursor,
         *     * move to the first row in the Cursor, get the data,
         *     * and display it.
         * */
        val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
        val sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE)
        returnCursor.moveToFirst()
        val name = returnCursor.getString(nameIndex)
        val size = java.lang.Long.toString(returnCursor.getLong(sizeIndex))
        val file = File(context.getCacheDir(), name)
        try {
            val inputStream: InputStream? = context.getContentResolver().openInputStream(uri)
            val outputStream = FileOutputStream(file)
            var read = 0
            val maxBufferSize = 1 * 1024 * 1024
            val bytesAvailable: Int = inputStream!!.available()

            //int bufferSize = 1024;
            val bufferSize = Math.min(bytesAvailable, maxBufferSize)
            val buffers = ByteArray(bufferSize)
            while (inputStream?.read(buffers).also { read = it!! } != -1) {
                outputStream.write(buffers, 0, read)
            }
            Log.e("File Size", "Size " + file.length())
            inputStream?.close()
            outputStream.close()
            Log.e("File Path", "Path " + file.path)
            Log.e("File Size", "Size " + file.length())
        } catch (e: Exception) {
            Log.e("Exception", e.message!!)
        }
        return file.path
    }

    /***
     * Used for Android Q+
     * @param uri
     * @param newDirName if you want to create a directory, you can set this variable
     * @return
     */
    private suspend fun copyFileToInternalStorage(
        uri: Uri,
        newDirName: String
    ): String? {

        var returnCursor:Cursor?=null
        var path:String?=null

        Log.d(TAG, "copyFileToInternalStorage: Triggered")

        try {

            withContext(Dispatchers.IO) {
                returnCursor = context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE), null, null, null)!!
                /*
                 * Get the column indexes of the data in the Cursor,
                 *     * move to the first row in the Cursor, get the data,
                 *     * and display it.
                 * */
                val nameIndex = returnCursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                val sizeIndex = returnCursor?.getColumnIndex(OpenableColumns.SIZE)
                returnCursor?.moveToFirst()
                val name = returnCursor?.getString(nameIndex!!)
                val size = returnCursor?.getLong(sizeIndex!!).toString()
                val output: File
                if (newDirName != "") {
                    val dir = File(context.filesDir.toString() + "/" + newDirName)
                    if (!dir.exists()) {
                        dir.mkdir()
                    }
                    output = File(context.filesDir.toString() + "/" + newDirName + "/" + name)
                    Log.d(TAG, "copyFileToInternalStorage: ${output.absolutePath}")
                } else {
                    output = File(context.filesDir.toString() + "/" + name)
                    Log.d(TAG, "copyFileToInternalStorage: Else: ${output.absolutePath}")
                }
                try {
                    val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
                    val outputStream = FileOutputStream(output)
                    var read = 0
                    val bufferSize = 1024
                    val buffers = ByteArray(bufferSize)
                    while (inputStream?.read(buffers).also { read = it!! } != -1) {
                        outputStream.write(buffers, 0, read)
                    }
                    inputStream?.close()
                    outputStream.close()
                } catch (e: Exception) {
                    Log.e("Exception", e.message!!)
                }
                path = output.path
            }

            Log.d(TAG, "copyFileToInternalStorage: Path: $path")
            return path
        } finally {
            returnCursor?.close()
        }
    }

    private fun getFilePathForWhatsApp(uri: Uri): String? {
        var path:String?=null
        GlobalScope.launch(Dispatchers.IO) {
            path = copyFileToInternalStorage(uri, "whatsapp")
        }
        return path
    }

    private fun getDataColumn(
        context: Context,
        uri: Uri?,
        selection: String?,
        selectionArgs: Array<String>?
    ): String? {
        var cursor: Cursor? = null
        val column = "_data"
        val projection = arrayOf(column)
        try {
            cursor = context.contentResolver.query(
                uri!!, projection,
                selection, selectionArgs, null
            )
            if (cursor != null && cursor.moveToFirst()) {
                val index = cursor.getColumnIndexOrThrow(column)
                return cursor.getString(index)
            }
        } finally {
            cursor?.close()
        }
        return null
    }

    private fun isExternalStorageDocument(uri: Uri): Boolean {
        return "com.android.externalstorage.documents" == uri.authority
    }

    private fun isDownloadsDocument(uri: Uri): Boolean {
        return "com.android.providers.downloads.documents" == uri.authority
    }

    private fun isMediaDocument(uri: Uri): Boolean {
        return "com.android.providers.media.documents" == uri.authority
    }

    private fun isGooglePhotosUri(uri: Uri): Boolean {
        return "com.google.android.apps.photos.content" == uri.authority
    }

    fun isWhatsAppFile(uri: Uri): Boolean {
        return "com.whatsapp.provider.media" == uri.authority
    }

    private fun isGoogleDriveUri(uri: Uri): Boolean {
        return "com.google.android.apps.docs.storage" == uri.authority || "com.google.android.apps.docs.storage.legacy" == uri.authority
    }