How to get filepath for Documents from Uri in android 10 and android 11 - file-upload

I am creating an app where users will upload pdf or doc files.
I have used default file chooser which returns Uri , now i need to upload those selected files to server
Its working fine upto android 9 ,i am facing issues in android 10 and 11 (i have used android:requestLegacyExternalStorage="true" for android 10 )
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
.apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_MIME_TYPES, supportedDocumentTypes.keys.toTypedArray())
}
resultLauncher.launch(intent)
In Activity Result
if (data != null) {
var path = ""
val id = data.data?.lastPathSegment!!
val selection = "_id=?"
if (id.startsWith("msf:") && Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
path = FileHelper(requireContext()).getRealPathFromUri(data.data!!.toString()
.replace("msf:","").toUri())!!
}else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q){
path = FileHelper(requireContext()).getRealPathFromUri(data.data!!)!!
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
path = getDataColumn(context, MediaStore.Downloads.EXTERNAL_CONTENT_URI,
selection, arrayOf(getPath(data.data!!)))
} else {
data.data?.also { uri ->
path = FileHelper(requireContext()).getRealPathFromUri(uri)!!
}
}
Log.e("Doc Path ::",path)
AppUtils.CustomToast(requireActivity(),path)
uploadDocs(path)
}
For getting Document_ID
private fun getPath(uri : Uri) : String {
val contentResolver = requireActivity().applicationContext.contentResolver
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)
val cursor: Cursor? = contentResolver.query(
uri, null, null, null, null, null)
var id = ""
cursor?.use { cursor1 ->
if (cursor1.moveToFirst()) {
val displayName: String = cursor1.getString(cursor1.getColumnIndex(OpenableColumns.DISPLAY_NAME))
Log.i(TAG, "Display Name: $displayName")
val names = cursor1.columnNames.joinToString(",") { it }
Log.e("names ^^^^^",names)
val sizeIndex: Int = cursor1.getColumnIndex(OpenableColumns.SIZE)
val size: String = if (!cursor1.isNull(sizeIndex)) {
cursor1.getString(sizeIndex)
} else { "Unknown" }
Log.i(TAG, "Size: $size")
id = cursor1.getString(cursor1.getColumnIndex(cursor1.columnNames[0]))
Log.e("DocId",id)
}
}
return id
}
Uploading file to server using Retrofit
val builder = MultipartBody.Builder()
builder.setType(MultipartBody.FORM)
val file = File(docPaths)
builder.addFormDataPart("documents", file.name,
RequestBody.create("multipart/form-data".toMediaTypeOrNull(), file))
val requestBody: MultipartBody = builder.build()
I am expecting some code for getting file to upload to server
Thanks In Advance

Related

Google Places OpeningHours.getWeekdayText() is NULL for some locations

I'm using google places to retrieve information for a place such as the business name, address, OpenHours and LatLng.
This works 95% of the time, but for some places I receive the error...
"Attempt to invoke virtual method 'java.util.List com.google.android.libraries.places.api.model.OpeningHours.getWeekdayText()' on a null object reference"
Looking on Google maps, I do see these places have open hours information.
//Add a marker when a POI on map is clicked.
map.setOnPoiClickListener { poi ->
map.clear()
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
poiMarker?.showInfoWindow()
placeId = poi.placeId
Timber.i("Place ID: $placeId")
//https://developers.google.com/maps/documentation/places/android-sdk/reference/com/google/android/libraries/places/api/net/PlacesClient#fetchPlace(com.google.android.libraries.places.api.net.FetchPlaceRequest)
val placeFields = listOf(Place.Field.ID, Place.Field.NAME, Place.Field.ADDRESS, Place.Field.OPENING_HOURS, Place.Field.LAT_LNG)
val request = FetchPlaceRequest.newInstance(placeId, placeFields)
if (!Places.isInitialized()) {
Places.initialize(requireContext(), apiKey, Locale.US);
}
val placesClient = Places.createClient(requireContext())
placesClient.fetchPlace(request)
.addOnSuccessListener { response: FetchPlaceResponse ->
val place = response.place
setLiveDataPlace(place)
}.addOnFailureListener { exception: Exception ->
if (exception is ApiException) {
Timber.i( "Place not found: ${exception.message}")
}
}
binding.buttonSave.visibility = View.VISIBLE
}
}
fun setLiveDataPlace(place: Place){
placeId = place.id as String
placeName = place.name as String
placeAddress = place.address as String
try {
placeOpenMonday = place.openingHours.weekdayText[0]
placeOpenTuesday = place.openingHours.weekdayText[1]
placeOpenWednesday = place.openingHours.weekdayText[2]
placeOpenThursday = place.openingHours.weekdayText[3]
placeOpenFriday = place.openingHours.weekdayText[4]
placeOpenSaturday = place.openingHours.weekdayText[5]
placeOpenSunday = place.openingHours.weekdayText[6]
} catch(e : Exception) {
Timber.i("Open hours exception: ${e.message}")
}
placeLat = place.latLng.latitude.toString()
placeLng = place.latLng.longitude.toString()
Timber.i("Place: $place")
}

I tried to run this code and every time I run it shows this result

private fun moveMarkerAnimation(key: String, newData: AnimationModel, marker: Marker?, from: String, to: String) {
if (!newData.isRun)
{
compositeDisposable.add(
iGoogleAPI.getDirections(
"driving",
"less_driving",
from, to,
getString(R.string.google_api_key1)
)!!.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { returnResult ->
Log.d("API_RETURN",returnResult,)
try {
val jsonObject = JSONObject(returnResult)
val jsonArray = jsonObject.getJSONArray("routes")
for ( i in 0 until jsonArray.length())
{
val route = jsonArray.getJSONObject(i)
val poly = route.getJSONObject("overview_polyLine")
val polyLine = poly.getString("points")
polylineList = Common.decodePoly(polyLine) as java.util.ArrayList<LatLng?>
}
handler = Handler()
index = -1
next = 1
val runnable = object :Runnable{
override fun run() {
if (polylineList!!.size > 1)
{
if (index< polylineList!!.size)
{
index ++
next = index+1
start = polylineList!![index] !!
end = polylineList!![next]!!
}
val valueAnimator = ValueAnimator.ofInt(0,1)
valueAnimator.duration = 3000
valueAnimator.interpolator = LinearInterpolator()
valueAnimator.addUpdateListener { value ->
v = value.animatedFraction
lat = v*end !!.latitude + (1-v) * start!!.latitude
lng = v*end !!.longitude+ (1-v) * start!!.longitude
val newPos = LatLng(lat,lng)
marker!!.position = newPos
marker!!.setAnchor(0.5f,0.5f)
marker!!.rotation = Common.getBearing(start!!,newPos)
}
valueAnimator.start()
if (index < polylineList!!.size-2)
{
handler!!.postDelayed(this,1500)
}else if (index < polylineList!!.size-1)
{
newData.isRun = false
Common.driversSubscrib.put(key,newData)
}
}
}
}
handler!!.postDelayed(runnable,1500)
}
catch (e:java.lang.Exception){
Snackbar.make(requireView(),e.message!!,Snackbar.LENGTH_LONG).show()
}
When the site changes from from firebase this result appears
022-04-26 13:19:30.912 23482-23482/com.example.bustrackerriderapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.bustrackerriderapp, PID: 23482
io.reactivex.exceptions.OnErrorNotImplementedException: The exception was not handled due to missing onError handler in the subscribe() method call. Further reading
what should I do to fix this problem

Kotlin ListView IndexOutOfBoundsException

(new to kotlin) I'm making my own music app but i'm having an error that i don't understand :
in the bit of code where i try to access a random view (shuffle), i get the java.lang.IndexOutOfBoundsException: Index:96 Size:11.
96 in this example is the view in the listview that i'm trying to access.
It happens in this line : var iView = listViewMusic.get(idShuffle)
Same if i use listViewMusic[idShuffle]
EDIT : Turns out that 11 is only the 11 visible items on screen at any given moment, even if the list contains hundreds of items. When i use listViewMusic.smoothscrolltoposition(idShuffle) it works, but the size of 11 now relates to the 11 on screen after the scrolling
The function playNext() inside the activity, called when clicking on the shuffle button:
fun playNext(){
try {
// Find the order of the next song to play
var idShuffle = musicAdapter!!.getIdofItem(listMusicShuffled.get(musicNextToPlay).title)
// Find the right record in the list
//var iView = listViewMusic[idShuffle]
//toastIt(applicationContext, "adapter count ${listViewMusic.adapter.count}")
//toastIt(applicationContext, "listview count ${listViewMusic.count}")
var iView = listViewMusic.get(idShuffle) //throws the error
// Play it
playOrPause(iView)
// Prepare the next track
musicNextToPlay += 1
if (musicNextToPlay >= listMusicShuffled.size) {
musicNextToPlay = -1
}
} catch (e:Exception) {toastException(applicationContext, "playnext", e) }
}
The part of the function onCreate that fills in the listViewMusic:
// Retrieve the data
val mediaStoreUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val cursor = contentResolver.query(mediaStoreUri, null, "", null, null)
//Browse the data
listMusic = mutableListOf()
val listMusicJson = getMusicFromJson()
while (cursor!!.moveToNext()) {
val musicName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME))
val musicArtist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))
val musicUrl = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))
val musicType:String =
if (musicArtist.contains("lmdmf", true)) { "LMDMF" }
else if (musicName.contains("slack", true)) { "SLACK" }
else { "MUSIC" }
listMusic.add(
MusicTrack(
musicName,
musicPlayCount,
musicUrl,
musicType
)
)
}
cursor.close()
musicAdapter = MusicAdapter(listMusic.sortedWith(compareBy<MusicTrack>{ it.title }).filter { it.type == "MUSIC"}.toMutableList())
listViewMusic.adapter = musicAdapter

Cannot format given Object as a Number in Kotlin

An error occurred while using the ConverPrice function as follows for information about the price.
The price of the item in the recycler view adapter onBindViewHolder.
As a result of debugging, the error occurs in the following code.
priceText =
"${dec.format(priceMin)} ~ ${dec.format(priceMax)}"
Please check my code and answer.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DataViewHolder -> {
val item = dataList[position]
item.price.let {
holder.price.text = ConvertPrice(item, holder.price)
}
}
}
}
fun ConvertPrice(productDetail: ProductDetail?, tv: TextView? = null, setPrice: Boolean = false): String {
val disableColor = Color.parseColor("#aaaaaa")
val enableColor = Color.parseColor("#3692ff")
tv?.setTextColor(disableColor)
if (ProductDetail != null) {
val priceMin = productDetail.priceMin
val priceMax = productDetail.priceMax
var priceText = ""
val dec = DecimalFormat("##,###")
productDetail.enabledRetail?.let {
if (productDetail.enabledRetail == true) {
if (setPrice) {
priceText = if (priceMin == null || priceMax == null) {
"No pricing information"
} else {
"${dec.format(priceMin)} ~ ${dec.format(priceMax)}"
}
tv?.setTextColor(disableColor)
}
else {
priceText = dec.format(wineDetail.price).toString()
tv?.setTextColor(enableColor)
}
return priceText
} else if (productDetail.cntRating!! > 0) {
if ((priceMin == null && priceMax == null) || (priceMin == 0 && priceMax == 0)) {
priceText = "No pricing information"
} else {
priceText =
"${dec.format(priceMin)} ~ ${dec.format(priceMax)}"
tv?.setTextColor(disableColor)
}
return priceText
}
}
}
return "No pricing information"
}
DecimalFormat.format() only works fine with long or double. You should convert "priceMin" and "priceMax" to Long.
val priceMin = productDetail.priceMin.toLong()
val priceMax = productDetail.priceMax.toLong()
I recommend to use NumberFormat instead of DecimalFormat because it is locale-sensitive
val decFormat = NumberFormat.getInstance() // or getCurrencyInstance()
decFormat.maximumFractionDigits = 3
decFormat.format(priceMin)
decFormat.format(priceMax)

How to change encoding to a downloaded file Kotlin

I'm making an app which will download a .zip file, unzip it and finally take the .srt file (which was zipped) and put it as subtitle file in exoplayer movie.
My problem
The file has greek letters inside and when I put it as a subtitle file I only see corrupted letters
What have I tried
Below is the code to unzip the file
fun writeZipAndUnZip(subtitlesLinks: ArrayList<String>, context: Context, body: ResponseBody?) {
if (body == null) { return }
val file = File(getSubsDirectory(), subtitlesLinks.first())
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
try {
val fileReader = ByteArray(4096)
inputStream = body.byteStream()
outputStream = FileOutputStream(file)
while (true) {
var read = inputStream.read(fileReader)
if (read == -1) {
break
}
outputStream.write(fileReader, 0, read)
}
outputStream.flush()
unzip(context)
} catch (e: IOException) {
return
} finally {
inputStream?.close()
outputStream?.close()
}}
fun unzip(context: Context) {
val unzipPath = getSubsDirectory()
var count: Int
val buffer = ByteArray(4096)
val subFile = File(getSubsDirectory()).listFiles()?.first() ?: return
try {
val stream = FileInputStream(subFile.absolutePath)
ZipInputStream(stream).use { zis ->
var ze = ZipEntry("")
while (zis.nextEntry?.also { ze = it } != null) {
var fileName = ze.name
fileName = fileName.substring(fileName.indexOf("/") + 1)
val file = File(unzipPath, fileName)
val dir = if (ze.isDirectory) file else file.parentFile
if (!dir.isDirectory && !dir.mkdirs())
throw FileNotFoundException("Invalid path: " + dir.absolutePath)
if (ze.isDirectory) continue
val fileOutput = FileOutputStream(file)
try {
while (zis.read(buffer).also { count = it } != -1)
fileOutput.write(buffer, 0, count)
} catch (e: IOException) {
Timber.tag("ErrorZip").d(e.localizedMessage)
} finally {
val fileOutput = context.openFileOutput(fileName, Context.MODE_PRIVATE)
fileOutput.close()
}
}
}
} catch (e: IOException) {
Timber.tag("ErrorZip").d(e.localizedMessage)
}}
Here is the code I put subtitle in exoplayer
val subtitleFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP, Format.NO_VALUE, "el")
val subtitleSource = SingleSampleMediaSource(File(Utils.getSubsDirectory()).listFiles()!![1].toUri(), dataSourceFactory, subtitleFormat, C.TIME_UNSET)
mediaSource = MergingMediaSource(buildMediaSource(videoUrl), subtitleSource)
I also tried to resave the subtitle with Utf-8 encoding but I get some characters in greek and the most missing or incorrect using this code
fun encode() {
val charset = "UTF8"
val subFile = File(getSubsDirectory()).listFiles()!![1] ?: return
val inputStream: InputStream = subFile.absoluteFile.inputStream()
val inputString = inputStream.bufferedReader().use { it.readText() }
val writer = OutputStreamWriter(FileOutputStream(File(getSubsDirectory(), "subs.srt")), charset)
writer.write(inputString)
writer.close()
}
Probably the file you are trying to read is in a different encoding than the System default (Android uses utf-8). You need to read the file at the 'correct' encoding format (for Greek usually is Windows-1253) and then save it to utf-8.