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
object SelectedFilePath {
fun getPath(context: Context, uri: Uri): String? {
//check here to KITKAT or new version
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(":").toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://<span id=\"IL_AD1\" class=\"IL_AD\">downloads</span>/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(":").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)
}
} 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
}
return null
}
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
}
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
}
Now onActivityResult use this class
MY_RESULT_CODE_FILECHOOSER -> if (resultCode == Activity.RESULT_OK) {
if (data != null) {
val fileUri: Uri? = data.data
Log.d(LOG_TAG, "Uri: $fileUri")
var filePath: String? = null
try {
filePath = fileUri?.let { SelectedFilePath.getPath(this, it) }
uploadFile(filePath)
} catch (e: Exception) {
Log.e(LOG_TAG, "Error: $e")
showToast("Error: $e")
}
if (filePath != null) {
Log.e(LOG_TAG, filePath)
}
}
}
Full code is:
private fun askPermissionAndBrowseFile() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Level 23
// Check if we have Call permission
val permisson: Int = ActivityCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
)
if (permisson != PackageManager.PERMISSION_GRANTED) {
requestPermissions(
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
MY_REQUEST_CODE_PERMISSION
)
return
}
}
browseFiles()
}
private fun browseFiles() {
var chooseFileIntent = Intent(Intent.ACTION_GET_CONTENT)
chooseFileIntent.type = "*/*"
chooseFileIntent.addCategory(Intent.CATEGORY_OPENABLE)
chooseFileIntent = Intent.createChooser(chooseFileIntent, "Choose a file")
startActivityForResult(chooseFileIntent, MY_RESULT_CODE_FILECHOOSER)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
MY_REQUEST_CODE_PERMISSION -> {
// Note: If request is cancelled, the result arrays are empty.
// Permissions granted (CALL_PHONE).
if (grantResults.size > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
Log.d(LOG_TAG, "Permission granted!")
showToast("Permission granted!")
browseFiles()
} else {
Log.i(LOG_TAG, "Permission denied!")
showToast("Permission denied!")
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
MY_RESULT_CODE_FILECHOOSER -> if (resultCode == Activity.RESULT_OK) {
if (data != null) {
val fileUri: Uri? = data.data
Log.d(LOG_TAG, "Uri: $fileUri")
var filePath: String? = null
try {
filePath = fileUri?.let { SelectedFilePath.getPath(this, it) }
uploadFile(filePath)
} catch (e: Exception) {
Log.e(LOG_TAG, "Error: $e")
showToast("Error: $e")
}
if (filePath != null) {
Log.e(LOG_TAG, filePath)
}
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun uploadFile(filePath: String?) {
val myData = Data.Builder().putString(AppConstants.FILE_TO_UPLOAD, filePath).build()
val oneTimeWorkRequest = OneTimeWorkRequest.Builder(UploadFileWorker::class.java)
.setInputData(myData)
.build()
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
Toast.makeText(this, resources.getString(R.string.file_will_be_uploaded), Toast.LENGTH_SHORT).show()
}
enter code here
Upload worker class :
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.thirdeyegen.mr_workspace.R
import com.thirdeyegen.mr_workspace.constants.AppConstants
import com.thirdeyegen.mr_workspace.network.ProgressRequestBody
import com.thirdeyegen.mr_workspace.network.RestClient
import okhttp3.MultipartBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File
infix fun Int.hasReached(limit: Int): Boolean {
return this == limit
}
class UploadFileWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
private var isSuccess = true
private val TAG = "UPLOAD_FILE_WORKER==>"
val PROGRESS_MAX = 100
var PROGRESS_CURRENT = 0
val mContext = context
private lateinit var builder: NotificationCompat.Builder
private lateinit var notificationManager: NotificationManager
override fun doWork(): Result {
Log.d(TAG, "DO_WORK")
createNotificationChannel()
return startUploading()
}
private fun startUploading(): Result {
val filePath = inputData.getString(AppConstants.FILE_TO_UPLOAD)
if (filePath != null) {
val file = File(filePath)
val fileBody = ProgressRequestBody(file, "*", object : ProgressRequestBody.UploadCallbacks {
override fun onFinish() {
if (PROGRESS_CURRENT hasReached 100) {
notificationManager.cancel(1)
}
}
override fun onProgressUpdate(percentage: Int) {
PROGRESS_CURRENT = percentage
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false)
notificationManager.notify(1, builder.build());
if (percentage hasReached 100) {
notificationManager.cancel(1)
}
Log.d(TAG, "UPLOAD_PROGRESS====> $percentage")
}
override fun onError() {
notificationManager.cancel(1)
Log.d(TAG, "UPLOAD_ERROR===>")
}
})
val filePart: MultipartBody.Part = MultipartBody.Part.createFormData("file", file.name, fileBody)
RestClient.apiInterfaceForUploader.uploadVideo(filePart, "record").enqueue(object : Callback<Any?> {
override fun onResponse(call: Call<Any?>, response: Response<Any?>) {
Toast.makeText(applicationContext, R.string.msg_file_uploaded_successfully, Toast.LENGTH_LONG).show()
isSuccess = true
}
override fun onFailure(call: Call<Any?>, t: Throwable) {
Toast.makeText(applicationContext, R.string.msg_error_while_uploading_file, Toast.LENGTH_SHORT).show()
isSuccess = false
}
})
}
return if (isSuccess) {
Result.success()
} else {
Result.failure()
}
}
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name: CharSequence = "My Channel"
val description = mContext.getString(R.string.upload_file_text)
val importance: Int = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel("upload_worker", name, importance)
channel.description = description
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
val notificationManager: NotificationManager = mContext.getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(channel)
}
setupNotification(mContext)
}
private fun setupNotification(context: Context) {
builder = NotificationCompat.Builder(context, "upload_worker").apply {
setContentTitle(context.getString(R.string.file_upload_text))
setOngoing(false)
setAutoCancel(true)
setContentText(context.getString(R.string.upload_in_progress))
setSmallIcon(R.drawable.ic_files)
setSound(null)
setNotificationSilent()
priority = NotificationCompat.PRIORITY_LOW
}
notificationManager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(1, builder.build())
builder.setOngoing(true)
}
}