Skip to content

Instantly share code, notes, and snippets.

@hitesh-dhamshaniya
Created June 22, 2020 07:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hitesh-dhamshaniya/9569317b8e9f878392466e21f81c220a to your computer and use it in GitHub Desktop.
Save hitesh-dhamshaniya/9569317b8e9f878392466e21f81c220a to your computer and use it in GitHub Desktop.
File URI Utils. kt is used full get exact path of selected file from intent
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
/**
* This file was taken from
* https://gist.github.com/HBiSoft/15899990b8cd0723c3a894c1636550a8
*
* Later on it was modified from the below resource:
* https://raw.githubusercontent.com/iPaulPro/aFileChooser/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
* https://raw.githubusercontent.com/iPaulPro/aFileChooser/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
*/
object FileUriUtils {
fun getRealPath(context: Context, uri: Uri): String? {
var path = getPathFromLocalUri(context, uri)
if (path == null) {
path = getPathFromRemoteUri(context, uri)
}
return path
}
private fun getPathFromLocalUri(context: Context, uri: Uri): String? {
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true)) {
if (split.size > 1) {
Environment.getExternalStorageDirectory().toString() + "/" + split[1]
} else {
Environment.getExternalStorageDirectory().toString() + "/"
}
// This is for checking SD Card
} else {
val path = "storage" + "/" + docId.replace(":", "/")
if (File(path).exists()) {
path
} else {
"/storage/sdcard/" + split[1]
}
}
} else if (isDownloadsDocument(uri)) {
val fileName = getFilePath(context, uri)
if (fileName != null) {
return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
}
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)
)
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.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
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
} // MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
// Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
return uri.path
} // File
// MediaStore (and general)
return null
}
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)
}
} catch (ex: Exception) {
} finally {
cursor?.close()
}
return null
}
private fun getFilePath(context: Context, uri: Uri): String? {
var cursor: Cursor? = null
val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
try {
cursor = context.contentResolver.query(uri, projection, null, null, null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}
private fun getPathFromRemoteUri(context: Context, uri: Uri): String? {
// The code below is why Java now has try-with-resources and the Files utility.
var file: File? = null
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
var success = false
try {
val extension = getImageExtension(uri)
inputStream = context.contentResolver.openInputStream(uri)
file = FileUtil.getImageFile(context.cacheDir, extension)
if (file == null) return null
outputStream = FileOutputStream(file)
if (inputStream != null) {
inputStream.copyTo(outputStream, bufferSize = 4 * 1024)
success = true
}
} catch (ignored: IOException) {
} finally {
try {
inputStream?.close()
} catch (ignored: IOException) {
}
try {
outputStream?.close()
} catch (ignored: IOException) {
// If closing the output stream fails, we cannot be sure that the
// target file was written in full. Flushing the stream merely moves
// the bytes into the OS, not necessarily to the file.
success = false
}
}
return if (success) file!!.path else null
}
/** @return extension of image with dot, or default .jpg if it none.
*/
private fun getImageExtension(uriImage: Uri): String {
var extension: String? = null
try {
val imagePath = uriImage.path
if (imagePath != null && imagePath.lastIndexOf(".") != -1) {
extension = imagePath.substring(imagePath.lastIndexOf(".") + 1)
}
} catch (e: Exception) {
extension = null
}
if (extension == null || extension.isEmpty()) {
// default extension for matches the previous behavior of the plugin
extension = "jpg"
}
return ".$extension"
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment