Added export to PDF file received by chat to Android public storage

This commit is contained in:
Sylvain Berfini 2023-12-06 18:01:14 +01:00
parent 80b887c874
commit b32007b1ca
4 changed files with 110 additions and 17 deletions

View file

@ -1,5 +1,7 @@
package org.linphone.ui.main.viewer.fragment
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
@ -21,6 +23,8 @@ import org.linphone.ui.main.viewer.viewmodel.FileViewModel
class FileViewerFragment : GenericFragment() {
companion object {
private const val TAG = "[File Viewer Fragment]"
private const val EXPORT_PDF = 10
}
private lateinit var binding: FileViewerFragmentBinding
@ -73,6 +77,17 @@ class FileViewerFragment : GenericFragment() {
}
}
viewModel.exportPdfEvent.observe(viewLifecycleOwner) {
it.consume { name ->
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/pdf"
putExtra(Intent.EXTRA_TITLE, name)
}
startActivityForResult(intent, EXPORT_PDF)
}
}
viewModel.isVideo.observe(viewLifecycleOwner) { isVideo ->
if (isVideo) {
binding.videoPlayer.setVideoPath(path)
@ -134,6 +149,17 @@ class FileViewerFragment : GenericFragment() {
super.onDestroyView()
}
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == EXPORT_PDF && resultCode == Activity.RESULT_OK) {
data?.data?.also { documentUri ->
Log.i("$TAG Exported PDF should be stored in URI [$documentUri]")
viewModel.copyPdfToUri(documentUri)
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun updateScreenSize() {
val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)

View file

@ -48,6 +48,10 @@ class FileViewModel @UiThread constructor() : ViewModel() {
MutableLiveData<Event<Boolean>>()
}
val exportPdfEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}
val toggleVideoPlayPauseEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>()
}
@ -67,7 +71,7 @@ class FileViewModel @UiThread constructor() : ViewModel() {
var screenWidth: Int = 0
var screenHeight: Int = 0
var currentPdfPage: PdfRenderer.Page? = null
private var currentPdfPage: PdfRenderer.Page? = null
// End of PDF viewer required variables
override fun onCleared() {
@ -180,22 +184,29 @@ class FileViewModel @UiThread constructor() : ViewModel() {
@UiThread
fun exportToMediaStore() {
if (::filePath.isInitialized) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
Log.i("$TAG Export file [$filePath] to Android's MediaStore")
val mediaStorePath = addContentToMediaStore(filePath)
if (mediaStorePath.isNotEmpty()) {
Log.i("$TAG File [$filePath] has been successfully exported to MediaStore")
val message = AppUtils.getString(
R.string.toast_file_successfully_exported_to_media_store
)
showGreenToastEvent.postValue(Event(Pair(message, R.drawable.check)))
} else {
Log.e("$TAG Failed to export file [$filePath] to MediaStore!")
val message = AppUtils.getString(
R.string.toast_export_file_to_media_store_error
)
showRedToastEvent.postValue(Event(Pair(message, R.drawable.x)))
if (isPdf.value == true) {
Log.i("$TAG Exporting PDF as document")
exportPdfEvent.postValue(Event(fileName.value.orEmpty()))
} else {
viewModelScope.launch {
withContext(Dispatchers.IO) {
Log.i("$TAG Export file [$filePath] to Android's MediaStore")
val mediaStorePath = addContentToMediaStore(filePath)
if (mediaStorePath.isNotEmpty()) {
Log.i(
"$TAG File [$filePath] has been successfully exported to MediaStore"
)
val message = AppUtils.getString(
R.string.toast_file_successfully_exported_to_media_store
)
showGreenToastEvent.postValue(Event(Pair(message, R.drawable.check)))
} else {
Log.e("$TAG Failed to export file [$filePath] to MediaStore!")
val message = AppUtils.getString(
R.string.toast_export_file_to_media_store_error
)
showRedToastEvent.postValue(Event(Pair(message, R.drawable.x)))
}
}
}
}
@ -204,6 +215,32 @@ class FileViewModel @UiThread constructor() : ViewModel() {
}
}
@UiThread
fun copyPdfToUri(dest: Uri) {
val source = Uri.parse(FileUtils.getProperFilePath(filePath))
Log.i("$TAG Copying file URI [$source] to [$dest]")
viewModelScope.launch {
withContext(Dispatchers.IO) {
val result = FileUtils.copyFile(source, dest)
if (result) {
Log.i(
"$TAG File [$filePath] has been successfully exported to documents"
)
val message = AppUtils.getString(
R.string.toast_file_successfully_exported_to_documents
)
showGreenToastEvent.postValue(Event(Pair(message, R.drawable.check)))
} else {
Log.e("$TAG Failed to export file [$filePath] to documents!")
val message = AppUtils.getString(
R.string.toast_export_file_to_documents_error
)
showRedToastEvent.postValue(Event(Pair(message, R.drawable.x)))
}
}
}
}
@UiThread
private suspend fun addContentToMediaStore(
path: String

View file

@ -33,6 +33,7 @@ import androidx.annotation.AnyThread
import androidx.core.content.FileProvider
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
@ -259,6 +260,33 @@ class FileUtils {
return false
}
@AnyThread
fun copyFile(from: Uri, to: Uri): Boolean {
try {
coreContext.context.contentResolver.openFileDescriptor(to, "w")?.use { fd ->
FileOutputStream(fd.fileDescriptor).use { outputStream ->
val fileDescriptor = coreContext.context.contentResolver.openFileDescriptor(
from,
"r"
)
val inputStream = FileInputStream(fileDescriptor?.fileDescriptor)
val buffer = ByteArray(4096)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } >= 0) {
outputStream.write(buffer, 0, bytesRead)
}
fileDescriptor?.close()
}
}
return true
} catch (e: FileNotFoundException) {
Log.e("$TAG Failed to find dest file: $e")
} catch (e: IOException) {
Log.e("$TAG Error copying file: $e")
}
return false
}
suspend fun copyFileTo(filePath: String, outputStream: OutputStream?): Boolean {
if (outputStream == null) {
Log.e("$TAG Can't copy file $filePath to given null output stream")

View file

@ -136,6 +136,8 @@
<string name="toast_default_account_connection_state_error">Connection error!</string>
<string name="toast_file_successfully_exported_to_media_store">File has been exported to native gallery</string>
<string name="toast_export_file_to_media_store_error">Error trying to export file to native gallery</string>
<string name="toast_file_successfully_exported_to_documents">File has been exported to documents</string>
<string name="toast_export_file_to_documents_error">Error trying to export file to documents</string>
<string name="toast_participant_added_to_conversation">Someone joined the conversation</string>
<string name="toast_participant_removed_from_conversation">Someone left the conversation</string>
<string name="toast_participant_has_been_granted_admin_rights">Someone is now admin</string>