Improved file copy code by using coroutines
This commit is contained in:
parent
de389858ce
commit
e1dc8ad8c2
8 changed files with 158 additions and 119 deletions
|
@ -30,12 +30,14 @@ import android.view.inputmethod.InputMethodManager
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavDestination
|
import androidx.navigation.NavDestination
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import java.io.UnsupportedEncodingException
|
import java.io.UnsupportedEncodingException
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
|
@ -147,10 +149,14 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
|
||||||
private fun handleIntentParams(intent: Intent) {
|
private fun handleIntentParams(intent: Intent) {
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
Intent.ACTION_SEND -> {
|
Intent.ACTION_SEND -> {
|
||||||
handleSendImage(intent)
|
lifecycleScope.launch {
|
||||||
|
handleSendImage(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Intent.ACTION_SEND_MULTIPLE -> {
|
Intent.ACTION_SEND_MULTIPLE -> {
|
||||||
handleSendMultipleImages(intent)
|
lifecycleScope.launch {
|
||||||
|
handleSendMultipleImages(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Intent.ACTION_VIEW -> {
|
Intent.ACTION_VIEW -> {
|
||||||
if (intent.type == AppUtils.getString(R.string.linphone_address_mime_type)) {
|
if (intent.type == AppUtils.getString(R.string.linphone_address_mime_type)) {
|
||||||
|
@ -218,13 +224,18 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSendImage(intent: Intent) {
|
private suspend fun handleSendImage(intent: Intent) {
|
||||||
(intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri)?.let {
|
(intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri)?.let {
|
||||||
val list = arrayListOf<String>()
|
val list = arrayListOf<String>()
|
||||||
val path = FileUtils.getFilePath(this, it)
|
coroutineScope {
|
||||||
if (path != null) {
|
val deferred = async {
|
||||||
list.add(path)
|
FileUtils.getFilePath(this@MainActivity, it)
|
||||||
Log.i("[Main Activity] Found single file to share: $path")
|
}
|
||||||
|
val path = deferred.await()
|
||||||
|
if (path != null) {
|
||||||
|
list.add(path)
|
||||||
|
Log.i("[Main Activity] Found single file to share: $path")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sharedViewModel.filesToShare.value = list
|
sharedViewModel.filesToShare.value = list
|
||||||
|
|
||||||
|
@ -234,14 +245,20 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSendMultipleImages(intent: Intent) {
|
private suspend fun handleSendMultipleImages(intent: Intent) {
|
||||||
intent.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)?.let {
|
intent.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)?.let {
|
||||||
val list = arrayListOf<String>()
|
val list = arrayListOf<String>()
|
||||||
for (parcelable in it) {
|
coroutineScope {
|
||||||
val uri = parcelable as Uri
|
val deferred = arrayListOf<Deferred<String?>>()
|
||||||
val path = FileUtils.getFilePath(this, uri)
|
for (parcelable in it) {
|
||||||
Log.i("[Main Activity] Found file to share: $path")
|
val uri = parcelable as Uri
|
||||||
if (path != null) list.add(path)
|
deferred.add(async { FileUtils.getFilePath(this@MainActivity, uri) })
|
||||||
|
}
|
||||||
|
val paths = deferred.awaitAll()
|
||||||
|
for (path in paths) {
|
||||||
|
Log.i("[Main Activity] Found file to share: $path")
|
||||||
|
if (path != null) list.add(path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sharedViewModel.filesToShare.value = list
|
sharedViewModel.filesToShare.value = list
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,14 @@ import androidx.appcompat.view.menu.MenuPopupHelper
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlinx.android.synthetic.main.tabs_fragment.*
|
import kotlinx.android.synthetic.main.tabs_fragment.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
|
@ -299,40 +301,41 @@ class DetailChatRoomFragment : MasterFragment() {
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
var fileToUploadPath: String? = null
|
lifecycleScope.launch {
|
||||||
|
var fileToUploadPath: String? = null
|
||||||
val temporaryFileUploadPath = chatSendingViewModel.temporaryFileUploadPath
|
val temporaryFileUploadPath = chatSendingViewModel.temporaryFileUploadPath
|
||||||
if (temporaryFileUploadPath != null) {
|
if (temporaryFileUploadPath != null) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
val dataUri = data.data
|
val dataUri = data.data
|
||||||
if (dataUri != null) {
|
if (dataUri != null) {
|
||||||
fileToUploadPath = dataUri.toString()
|
fileToUploadPath = dataUri.toString()
|
||||||
Log.i("[Chat Room] Using data URI $fileToUploadPath")
|
Log.i("[Chat Room] Using data URI $fileToUploadPath")
|
||||||
|
} else if (temporaryFileUploadPath.exists()) {
|
||||||
|
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
||||||
|
Log.i("[Chat Room] Data URI is null, using $fileToUploadPath")
|
||||||
|
}
|
||||||
} else if (temporaryFileUploadPath.exists()) {
|
} else if (temporaryFileUploadPath.exists()) {
|
||||||
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
||||||
Log.i("[Chat Room] Data URI is null, using $fileToUploadPath")
|
Log.i("[Chat Room] Data is null, using $fileToUploadPath")
|
||||||
}
|
|
||||||
} else if (temporaryFileUploadPath.exists()) {
|
|
||||||
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
|
||||||
Log.i("[Chat Room] Data is null, using $fileToUploadPath")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileToUploadPath != null) {
|
|
||||||
if (fileToUploadPath.startsWith("content://") ||
|
|
||||||
fileToUploadPath.startsWith("file://")
|
|
||||||
) {
|
|
||||||
val uriToParse = Uri.parse(fileToUploadPath)
|
|
||||||
fileToUploadPath = FileUtils.getFilePath(requireContext(), uriToParse)
|
|
||||||
Log.i("[Chat] Path was using a content or file scheme, real path is: $fileToUploadPath")
|
|
||||||
if (fileToUploadPath == null) {
|
|
||||||
Log.e("[Chat] Failed to get access to file $uriToParse")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (fileToUploadPath != null) {
|
if (fileToUploadPath != null) {
|
||||||
chatSendingViewModel.addAttachment(fileToUploadPath)
|
if (fileToUploadPath.startsWith("content://") ||
|
||||||
|
fileToUploadPath.startsWith("file://")
|
||||||
|
) {
|
||||||
|
val uriToParse = Uri.parse(fileToUploadPath)
|
||||||
|
fileToUploadPath = FileUtils.getFilePath(requireContext(), uriToParse)
|
||||||
|
Log.i("[Chat] Path was using a content or file scheme, real path is: $fileToUploadPath")
|
||||||
|
if (fileToUploadPath == null) {
|
||||||
|
Log.e("[Chat] Failed to get access to file $uriToParse")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileToUploadPath != null) {
|
||||||
|
chatSendingViewModel.addAttachment(fileToUploadPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ package org.linphone.activities.main.chat.viewmodels
|
||||||
import android.os.CountDownTimer
|
import android.os.CountDownTimer
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
|
@ -205,30 +207,32 @@ class ChatMessageViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addContentToMediaStore(content: Content) {
|
private fun addContentToMediaStore(content: Content) {
|
||||||
when (content.type) {
|
viewModelScope.launch {
|
||||||
"image" -> {
|
when (content.type) {
|
||||||
if (Compatibility.addImageToMediaStore(coreContext.context, content)) {
|
"image" -> {
|
||||||
Log.i("[Chat Message] Adding image ${content.name} terminated")
|
if (Compatibility.addImageToMediaStore(coreContext.context, content)) {
|
||||||
} else {
|
Log.i("[Chat Message] Adding image ${content.name} terminated")
|
||||||
Log.e("[Chat Message] Something went wrong while copying file...")
|
} else {
|
||||||
|
Log.e("[Chat Message] Something went wrong while copying file...")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
"video" -> {
|
||||||
"video" -> {
|
if (Compatibility.addVideoToMediaStore(coreContext.context, content)) {
|
||||||
if (Compatibility.addVideoToMediaStore(coreContext.context, content)) {
|
Log.i("[Chat Message] Adding video ${content.name} terminated")
|
||||||
Log.i("[Chat Message] Adding video ${content.name} terminated")
|
} else {
|
||||||
} else {
|
Log.e("[Chat Message] Something went wrong while copying file...")
|
||||||
Log.e("[Chat Message] Something went wrong while copying file...")
|
}
|
||||||
}
|
}
|
||||||
}
|
"audio" -> {
|
||||||
"audio" -> {
|
if (Compatibility.addAudioToMediaStore(coreContext.context, content)) {
|
||||||
if (Compatibility.addAudioToMediaStore(coreContext.context, content)) {
|
Log.i("[Chat Message] Adding audio ${content.name} terminated")
|
||||||
Log.i("[Chat Message] Adding audio ${content.name} terminated")
|
} else {
|
||||||
} else {
|
Log.e("[Chat Message] Something went wrong while copying file...")
|
||||||
Log.e("[Chat Message] Something went wrong while copying file...")
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Log.w("[Chat Message] File ${content.name} isn't either an image, an audio file or a video, can't add it to the Media Store")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
Log.w("[Chat Message] File ${content.name} isn't either an image, an audio file or a video, can't add it to the Media Store")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,10 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.main.MainActivity
|
import org.linphone.activities.main.MainActivity
|
||||||
import org.linphone.activities.main.contact.viewmodels.*
|
import org.linphone.activities.main.contact.viewmodels.*
|
||||||
|
@ -130,40 +132,42 @@ class ContactEditorFragment : Fragment() {
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
var fileToUploadPath: String? = null
|
lifecycleScope.launch {
|
||||||
|
var fileToUploadPath: String? = null
|
||||||
|
|
||||||
val temporaryFileUploadPath = temporaryPicturePath
|
val temporaryFileUploadPath = temporaryPicturePath
|
||||||
if (temporaryFileUploadPath != null) {
|
if (temporaryFileUploadPath != null) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
val dataUri = data.data
|
val dataUri = data.data
|
||||||
if (dataUri != null) {
|
if (dataUri != null) {
|
||||||
fileToUploadPath = dataUri.toString()
|
fileToUploadPath = dataUri.toString()
|
||||||
Log.i("[Chat Room] Using data URI $fileToUploadPath")
|
Log.i("[Chat Room] Using data URI $fileToUploadPath")
|
||||||
|
} else if (temporaryFileUploadPath.exists()) {
|
||||||
|
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
||||||
|
Log.i("[Chat Room] Data URI is null, using $fileToUploadPath")
|
||||||
|
}
|
||||||
} else if (temporaryFileUploadPath.exists()) {
|
} else if (temporaryFileUploadPath.exists()) {
|
||||||
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
||||||
Log.i("[Chat Room] Data URI is null, using $fileToUploadPath")
|
Log.i("[Chat Room] Data is null, using $fileToUploadPath")
|
||||||
}
|
|
||||||
} else if (temporaryFileUploadPath.exists()) {
|
|
||||||
fileToUploadPath = temporaryFileUploadPath.absolutePath
|
|
||||||
Log.i("[Chat Room] Data is null, using $fileToUploadPath")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileToUploadPath != null) {
|
|
||||||
if (fileToUploadPath.startsWith("content://") ||
|
|
||||||
fileToUploadPath.startsWith("file://")
|
|
||||||
) {
|
|
||||||
val uriToParse = Uri.parse(fileToUploadPath)
|
|
||||||
fileToUploadPath = FileUtils.getFilePath(requireContext(), uriToParse)
|
|
||||||
Log.i("[Chat] Path was using a content or file scheme, real path is: $fileToUploadPath")
|
|
||||||
if (fileToUploadPath == null) {
|
|
||||||
Log.e("[Chat] Failed to get access to file $uriToParse")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (fileToUploadPath != null) {
|
if (fileToUploadPath != null) {
|
||||||
viewModel.setPictureFromPath(fileToUploadPath)
|
if (fileToUploadPath.startsWith("content://") ||
|
||||||
|
fileToUploadPath.startsWith("file://")
|
||||||
|
) {
|
||||||
|
val uriToParse = Uri.parse(fileToUploadPath)
|
||||||
|
fileToUploadPath = FileUtils.getFilePath(requireContext(), uriToParse)
|
||||||
|
Log.i("[Chat] Path was using a content or file scheme, real path is: $fileToUploadPath")
|
||||||
|
if (fileToUploadPath == null) {
|
||||||
|
Log.e("[Chat] Failed to get access to file $uriToParse")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileToUploadPath != null) {
|
||||||
|
viewModel.setPictureFromPath(fileToUploadPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ class Api21Compatibility {
|
||||||
vibrator.vibrate(pattern, 1)
|
vibrator.vibrate(pattern, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addImageToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
|
||||||
val filePath = content.filePath
|
val filePath = content.filePath
|
||||||
val appName = AppUtils.getString(R.string.app_name)
|
val appName = AppUtils.getString(R.string.app_name)
|
||||||
val relativePath = "${Environment.DIRECTORY_PICTURES}/$appName"
|
val relativePath = "${Environment.DIRECTORY_PICTURES}/$appName"
|
||||||
|
@ -88,7 +88,7 @@ class Api21Compatibility {
|
||||||
return copyOk
|
return copyOk
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addVideoToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
|
||||||
val filePath = content.filePath
|
val filePath = content.filePath
|
||||||
val appName = AppUtils.getString(R.string.app_name)
|
val appName = AppUtils.getString(R.string.app_name)
|
||||||
val relativePath = "${Environment.DIRECTORY_MOVIES}/$appName"
|
val relativePath = "${Environment.DIRECTORY_MOVIES}/$appName"
|
||||||
|
@ -120,7 +120,7 @@ class Api21Compatibility {
|
||||||
return copyOk
|
return copyOk
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAudioToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
|
||||||
val filePath = content.filePath
|
val filePath = content.filePath
|
||||||
val appName = AppUtils.getString(R.string.app_name)
|
val appName = AppUtils.getString(R.string.app_name)
|
||||||
val relativePath = "${Environment.DIRECTORY_MUSIC}/$appName"
|
val relativePath = "${Environment.DIRECTORY_MUSIC}/$appName"
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.linphone.utils.FileUtils
|
||||||
@TargetApi(29)
|
@TargetApi(29)
|
||||||
class Api29Compatibility {
|
class Api29Compatibility {
|
||||||
companion object {
|
companion object {
|
||||||
fun addImageToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
|
||||||
val filePath = content.filePath
|
val filePath = content.filePath
|
||||||
val appName = AppUtils.getString(R.string.app_name)
|
val appName = AppUtils.getString(R.string.app_name)
|
||||||
val relativePath = "${Environment.DIRECTORY_PICTURES}/$appName"
|
val relativePath = "${Environment.DIRECTORY_PICTURES}/$appName"
|
||||||
|
@ -70,7 +70,7 @@ class Api29Compatibility {
|
||||||
return copyOk
|
return copyOk
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addVideoToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
|
||||||
val filePath = content.filePath
|
val filePath = content.filePath
|
||||||
val appName = AppUtils.getString(R.string.app_name)
|
val appName = AppUtils.getString(R.string.app_name)
|
||||||
val relativePath = "${Environment.DIRECTORY_MOVIES}/$appName"
|
val relativePath = "${Environment.DIRECTORY_MOVIES}/$appName"
|
||||||
|
@ -108,7 +108,7 @@ class Api29Compatibility {
|
||||||
return copyOk
|
return copyOk
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAudioToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
|
||||||
val filePath = content.filePath
|
val filePath = content.filePath
|
||||||
val appName = AppUtils.getString(R.string.app_name)
|
val appName = AppUtils.getString(R.string.app_name)
|
||||||
val relativePath = "${Environment.DIRECTORY_MUSIC}/$appName"
|
val relativePath = "${Environment.DIRECTORY_MUSIC}/$appName"
|
||||||
|
|
|
@ -115,21 +115,21 @@ class Compatibility {
|
||||||
// TODO Use removeLongLivedShortcuts() starting Android R (API 30)
|
// TODO Use removeLongLivedShortcuts() starting Android R (API 30)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addImageToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
|
||||||
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
|
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
|
||||||
return Api29Compatibility.addImageToMediaStore(context, content)
|
return Api29Compatibility.addImageToMediaStore(context, content)
|
||||||
}
|
}
|
||||||
return Api21Compatibility.addImageToMediaStore(context, content)
|
return Api21Compatibility.addImageToMediaStore(context, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addVideoToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addVideoToMediaStore(context: Context, content: Content): Boolean {
|
||||||
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
|
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
|
||||||
return Api29Compatibility.addVideoToMediaStore(context, content)
|
return Api29Compatibility.addVideoToMediaStore(context, content)
|
||||||
}
|
}
|
||||||
return Api21Compatibility.addVideoToMediaStore(context, content)
|
return Api21Compatibility.addVideoToMediaStore(context, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAudioToMediaStore(context: Context, content: Content): Boolean {
|
suspend fun addAudioToMediaStore(context: Context, content: Content): Boolean {
|
||||||
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
|
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
|
||||||
return Api29Compatibility.addAudioToMediaStore(context, content)
|
return Api29Compatibility.addAudioToMediaStore(context, content)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ import android.provider.OpenableColumns
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
|
|
||||||
|
@ -109,7 +113,7 @@ class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFilePath(context: Context, uri: Uri): String? {
|
suspend fun getFilePath(context: Context, uri: Uri): String? {
|
||||||
var result: String? = null
|
var result: String? = null
|
||||||
val name: String = getNameFromUri(uri, context)
|
val name: String = getNameFromUri(uri, context)
|
||||||
|
|
||||||
|
@ -123,13 +127,16 @@ class FileUtils {
|
||||||
" to local file " +
|
" to local file " +
|
||||||
localFile.absolutePath
|
localFile.absolutePath
|
||||||
)
|
)
|
||||||
if (copyToFile(remoteFile, localFile)) {
|
coroutineScope {
|
||||||
Log.i("[File Utils] Copy successful")
|
val deferred = async { copyToFile(remoteFile, localFile) }
|
||||||
result = localFile.absolutePath
|
if (deferred.await()) {
|
||||||
} else {
|
Log.i("[File Utils] Copy successful")
|
||||||
Log.e("[File Utils] Copy failed")
|
result = localFile.absolutePath
|
||||||
|
} else {
|
||||||
|
Log.e("[File Utils] Copy failed")
|
||||||
|
}
|
||||||
|
remoteFile?.close()
|
||||||
}
|
}
|
||||||
remoteFile?.close()
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.e("[File Utils] getFilePath exception: ", e)
|
Log.e("[File Utils] getFilePath exception: ", e)
|
||||||
}
|
}
|
||||||
|
@ -158,7 +165,7 @@ class FileUtils {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyFileTo(filePath: String, outputStream: OutputStream?): Boolean {
|
suspend fun copyFileTo(filePath: String, outputStream: OutputStream?): Boolean {
|
||||||
if (outputStream == null) {
|
if (outputStream == null) {
|
||||||
Log.e("[File Utils] Can't copy file $filePath to given null output stream")
|
Log.e("[File Utils] Can't copy file $filePath to given null output stream")
|
||||||
return false
|
return false
|
||||||
|
@ -171,11 +178,13 @@ class FileUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val inputStream = FileInputStream(file)
|
withContext(Dispatchers.IO) {
|
||||||
val buffer = ByteArray(4096)
|
val inputStream = FileInputStream(file)
|
||||||
var bytesRead: Int
|
val buffer = ByteArray(4096)
|
||||||
while (inputStream.read(buffer).also { bytesRead = it } >= 0) {
|
var bytesRead: Int
|
||||||
outputStream.write(buffer, 0, bytesRead)
|
while (inputStream.read(buffer).also { bytesRead = it } >= 0) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
@ -184,14 +193,16 @@ class FileUtils {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyToFile(inputStream: InputStream?, destFile: File?): Boolean {
|
private suspend fun copyToFile(inputStream: InputStream?, destFile: File?): Boolean {
|
||||||
if (inputStream == null || destFile == null) return false
|
if (inputStream == null || destFile == null) return false
|
||||||
try {
|
try {
|
||||||
FileOutputStream(destFile).use { out ->
|
withContext(Dispatchers.IO) {
|
||||||
val buffer = ByteArray(4096)
|
FileOutputStream(destFile).use { out ->
|
||||||
var bytesRead: Int
|
val buffer = ByteArray(4096)
|
||||||
while (inputStream.read(buffer).also { bytesRead = it } >= 0) {
|
var bytesRead: Int
|
||||||
out.write(buffer, 0, bytesRead)
|
while (inputStream.read(buffer).also { bytesRead = it } >= 0) {
|
||||||
|
out.write(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
Loading…
Reference in a new issue