Fixed contact sharing in chat + reworked how file picker is created
This commit is contained in:
parent
beb9d0db45
commit
2a2315e944
6 changed files with 171 additions and 112 deletions
|
@ -464,7 +464,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
lifecycleScope.launch {
|
||||
for (fileToUploadPath in ImageUtils.getFilesPathFromPickerIntent(
|
||||
for (fileToUploadPath in FileUtils.getFilesPathFromPickerIntent(
|
||||
data,
|
||||
chatSendingViewModel.temporaryFileUploadPath
|
||||
)) {
|
||||
|
@ -617,13 +617,11 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
}
|
||||
|
||||
private fun pickFile() {
|
||||
val cameraIntents = ArrayList<Intent>()
|
||||
val intentsList = ArrayList<Intent>()
|
||||
|
||||
// Handles image & video picking
|
||||
val galleryIntent = Intent(Intent.ACTION_PICK)
|
||||
galleryIntent.type = "*/*"
|
||||
galleryIntent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*", "video/*"))
|
||||
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
val pickerIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
pickerIntent.type = "*/*"
|
||||
pickerIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
|
||||
if (PermissionHelper.get().hasCameraPermission()) {
|
||||
// Allows to capture directly from the camera
|
||||
|
@ -639,25 +637,17 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
capturePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, publicUri)
|
||||
capturePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
capturePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
cameraIntents.add(capturePictureIntent)
|
||||
intentsList.add(capturePictureIntent)
|
||||
|
||||
val captureVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
|
||||
cameraIntents.add(captureVideoIntent)
|
||||
}
|
||||
|
||||
if (PermissionHelper.get().hasReadExternalStorage()) {
|
||||
// Finally allow any kind of file
|
||||
val fileIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
fileIntent.type = "*/*"
|
||||
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
cameraIntents.add(fileIntent)
|
||||
intentsList.add(captureVideoIntent)
|
||||
}
|
||||
|
||||
val chooserIntent =
|
||||
Intent.createChooser(galleryIntent, getString(R.string.chat_message_pick_file_dialog))
|
||||
Intent.createChooser(pickerIntent, getString(R.string.chat_message_pick_file_dialog))
|
||||
chooserIntent.putExtra(
|
||||
Intent.EXTRA_INITIAL_INTENTS,
|
||||
cameraIntents.toArray(arrayOf<Parcelable>())
|
||||
intentsList.toArray(arrayOf<Parcelable>())
|
||||
)
|
||||
|
||||
startActivityForResult(chooserIntent, 0)
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.linphone.core.tools.Log
|
|||
import org.linphone.databinding.ContactEditorFragmentBinding
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.FileUtils
|
||||
import org.linphone.utils.ImageUtils
|
||||
import org.linphone.utils.PermissionHelper
|
||||
|
||||
class ContactEditorFragment : GenericFragment<ContactEditorFragmentBinding>(), SyncAccountPickerFragment.SyncAccountPickedListener {
|
||||
|
@ -146,7 +145,7 @@ class ContactEditorFragment : GenericFragment<ContactEditorFragmentBinding>(), S
|
|||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
lifecycleScope.launch {
|
||||
val contactImageFilePath = ImageUtils.getFilePathFromPickerIntent(data, temporaryPicturePath)
|
||||
val contactImageFilePath = FileUtils.getFilePathFromPickerIntent(data, temporaryPicturePath)
|
||||
if (contactImageFilePath != null) {
|
||||
viewModel.setPictureFromPath(contactImageFilePath)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.linphone.core.tools.Log
|
|||
import org.linphone.databinding.SideMenuFragmentBinding
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.FileUtils
|
||||
import org.linphone.utils.ImageUtils
|
||||
import org.linphone.utils.PermissionHelper
|
||||
|
||||
class SideMenuFragment : GenericFragment<SideMenuFragmentBinding>() {
|
||||
|
@ -121,7 +120,7 @@ class SideMenuFragment : GenericFragment<SideMenuFragmentBinding>() {
|
|||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
lifecycleScope.launch {
|
||||
val contactImageFilePath = ImageUtils.getFilePathFromPickerIntent(data, temporaryPicturePath)
|
||||
val contactImageFilePath = FileUtils.getFilePathFromPickerIntent(data, temporaryPicturePath)
|
||||
if (contactImageFilePath != null) {
|
||||
viewModel.setPictureFromPath(contactImageFilePath)
|
||||
}
|
||||
|
|
71
app/src/main/java/org/linphone/utils/ContactUtils.kt
Normal file
71
app/src/main/java/org/linphone/utils/ContactUtils.kt
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-android
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.linphone.utils
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import java.io.*
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.core.tools.Log
|
||||
|
||||
class ContactUtils {
|
||||
companion object {
|
||||
fun getContactVcardFilePath(contactUri: Uri): String? {
|
||||
val contentResolver: ContentResolver = coreContext.context.contentResolver
|
||||
val lookupUri = ContactsContract.Contacts.getLookupUri(contentResolver, contactUri)
|
||||
Log.i("[Contact Utils] Contact lookup URI is $lookupUri")
|
||||
|
||||
val contactID = FileUtils.getNameFromFilePath(lookupUri.toString())
|
||||
Log.i("[Contact Utils] Contact ID is $contactID")
|
||||
|
||||
val contact = coreContext.contactsManager.findContactById(contactID)
|
||||
if (contact == null) {
|
||||
Log.e("[Contact Utils] Failed to find contact with ID $contactID")
|
||||
return null
|
||||
}
|
||||
|
||||
val vcard = contact.friend?.vcard?.asVcard4String()
|
||||
if (vcard == null) {
|
||||
Log.e("[Contact Utils] Failed to get vCard from contact $contactID")
|
||||
return null
|
||||
}
|
||||
|
||||
val contactName = contact.fullName?.replace(" ", "_") ?: contactID
|
||||
val vcardPath = FileUtils.getFileStoragePath("$contactName.vcf")
|
||||
val inputStream = ByteArrayInputStream(vcard.toByteArray())
|
||||
try {
|
||||
FileOutputStream(vcardPath).use { out ->
|
||||
val buffer = ByteArray(4096)
|
||||
var bytesRead: Int
|
||||
while (inputStream.read(buffer).also { bytesRead = it } >= 0) {
|
||||
out.write(buffer, 0, bytesRead)
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e("[Contact Utils] creating vcard file exception: $e")
|
||||
return null
|
||||
}
|
||||
|
||||
Log.i("[Contact Utils] Contact vCard path is $vcardPath")
|
||||
return vcardPath.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
|
@ -149,6 +149,95 @@ class FileUtils {
|
|||
return file
|
||||
}
|
||||
|
||||
suspend fun getFilesPathFromPickerIntent(data: Intent?, temporaryImageFilePath: File?): List<String> {
|
||||
var filePath: String? = null
|
||||
if (data != null) {
|
||||
val clipData = data.clipData
|
||||
if (clipData != null && clipData.itemCount > 1) { // Multiple selection
|
||||
Log.i("[File Utils] Found ${clipData.itemCount} elements")
|
||||
val list = arrayListOf<String>()
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
val dataUri = clipData.getItemAt(i).uri
|
||||
if (dataUri != null) {
|
||||
filePath = dataUri.toString()
|
||||
Log.i("[File Utils] Using data URI $filePath")
|
||||
}
|
||||
filePath = cleanFilePath(filePath)
|
||||
if (filePath != null) list.add(filePath)
|
||||
}
|
||||
return list
|
||||
} else { // Single selection
|
||||
val dataUri = if (clipData != null && clipData.itemCount == 1) {
|
||||
clipData.getItemAt(0).uri
|
||||
} else {
|
||||
data.data
|
||||
}
|
||||
if (dataUri != null) {
|
||||
filePath = dataUri.toString()
|
||||
Log.i("[File Utils] Using data URI $filePath")
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
filePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[File Utils] Data URI is null, using $filePath")
|
||||
}
|
||||
filePath = cleanFilePath(filePath)
|
||||
if (filePath != null) return arrayListOf(filePath)
|
||||
}
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
filePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[File Utils] Data is null, using $filePath")
|
||||
filePath = cleanFilePath(filePath)
|
||||
if (filePath != null) return arrayListOf(filePath)
|
||||
}
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
suspend fun getFilePathFromPickerIntent(data: Intent?, temporaryImageFilePath: File?): String? {
|
||||
var filePath: String? = null
|
||||
if (data != null) {
|
||||
val clipData = data.clipData
|
||||
if (clipData != null && clipData.itemCount > 1) { // Multiple selection
|
||||
Log.e("[File Utils] Expecting only one file, got ${clipData.itemCount}")
|
||||
} else { // Single selection
|
||||
val dataUri = if (clipData != null && clipData.itemCount == 1) {
|
||||
clipData.getItemAt(0).uri
|
||||
} else {
|
||||
data.data
|
||||
}
|
||||
if (dataUri != null) {
|
||||
filePath = dataUri.toString()
|
||||
Log.i("[File Utils] Using data URI $filePath")
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
filePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[File Utils] Data URI is null, using $filePath")
|
||||
}
|
||||
}
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
filePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[File Utils] Data is null, using $filePath")
|
||||
}
|
||||
return cleanFilePath(filePath)
|
||||
}
|
||||
|
||||
private suspend fun cleanFilePath(filePath: String?): String? {
|
||||
if (filePath != null) {
|
||||
val uriToParse = Uri.parse(filePath)
|
||||
if (filePath.startsWith("content://com.android.contacts/contacts/lookup/")) {
|
||||
Log.i("[File Utils] Contact sharing URI detected")
|
||||
return ContactUtils.getContactVcardFilePath(uriToParse)
|
||||
} else if (filePath.startsWith("content://") ||
|
||||
filePath.startsWith("file://")
|
||||
) {
|
||||
val result = getFilePath(coreContext.context, uriToParse)
|
||||
Log.i("[File Utils] Path was using a content or file scheme, real path is: $result")
|
||||
if (result == null) {
|
||||
Log.e("[File Utils] Failed to get access to file $uriToParse")
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
|
||||
fun deleteFile(filePath: String) {
|
||||
val file = File(filePath)
|
||||
if (file.exists()) {
|
||||
|
|
|
@ -20,13 +20,10 @@
|
|||
package org.linphone.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.*
|
||||
import android.media.ThumbnailUtils
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import java.io.File
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.compatibility.Compatibility
|
||||
import org.linphone.core.tools.Log
|
||||
|
||||
|
@ -70,92 +67,6 @@ class ImageUtils {
|
|||
return ThumbnailUtils.createVideoThumbnail(path, MediaStore.Images.Thumbnails.MINI_KIND)
|
||||
}
|
||||
|
||||
suspend fun getFilesPathFromPickerIntent(data: Intent?, temporaryImageFilePath: File?): List<String> {
|
||||
var imageFilePath: String? = null
|
||||
if (data != null) {
|
||||
val clipData = data.clipData
|
||||
if (clipData != null && clipData.itemCount > 1) { // Multiple selection
|
||||
Log.i("[Image Utils] Found ${clipData.itemCount} elements")
|
||||
val list = arrayListOf<String>()
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
val dataUri = clipData.getItemAt(i).uri
|
||||
if (dataUri != null) {
|
||||
imageFilePath = dataUri.toString()
|
||||
Log.i("[Image Utils] Using data URI $imageFilePath")
|
||||
}
|
||||
imageFilePath = cleanFilePath(imageFilePath)
|
||||
if (imageFilePath != null) list.add(imageFilePath)
|
||||
}
|
||||
return list
|
||||
} else { // Single selection
|
||||
val dataUri = if (clipData != null && clipData.itemCount == 1) {
|
||||
clipData.getItemAt(0).uri
|
||||
} else {
|
||||
data.data
|
||||
}
|
||||
if (dataUri != null) {
|
||||
imageFilePath = dataUri.toString()
|
||||
Log.i("[Image Utils] Using data URI $imageFilePath")
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
imageFilePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[Image Utils] Data URI is null, using $imageFilePath")
|
||||
}
|
||||
imageFilePath = cleanFilePath(imageFilePath)
|
||||
if (imageFilePath != null) return arrayListOf(imageFilePath)
|
||||
}
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
imageFilePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[Image Utils] Data is null, using $imageFilePath")
|
||||
imageFilePath = cleanFilePath(imageFilePath)
|
||||
if (imageFilePath != null) return arrayListOf(imageFilePath)
|
||||
}
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
suspend fun getFilePathFromPickerIntent(data: Intent?, temporaryImageFilePath: File?): String? {
|
||||
var imageFilePath: String? = null
|
||||
if (data != null) {
|
||||
val clipData = data.clipData
|
||||
if (clipData != null && clipData.itemCount > 1) { // Multiple selection
|
||||
Log.e("[Image Utils] Expecting only one file, got ${clipData.itemCount}")
|
||||
} else { // Single selection
|
||||
val dataUri = if (clipData != null && clipData.itemCount == 1) {
|
||||
clipData.getItemAt(0).uri
|
||||
} else {
|
||||
data.data
|
||||
}
|
||||
if (dataUri != null) {
|
||||
imageFilePath = dataUri.toString()
|
||||
Log.i("[Image Utils] Using data URI $imageFilePath")
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
imageFilePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[Image Utils] Data URI is null, using $imageFilePath")
|
||||
}
|
||||
}
|
||||
} else if (temporaryImageFilePath?.exists() == true) {
|
||||
imageFilePath = temporaryImageFilePath.absolutePath
|
||||
Log.i("[Image Utils] Data is null, using $imageFilePath")
|
||||
}
|
||||
return cleanFilePath(imageFilePath)
|
||||
}
|
||||
|
||||
private suspend fun cleanFilePath(filePath: String?): String? {
|
||||
if (filePath != null) {
|
||||
if (filePath.startsWith("content://") ||
|
||||
filePath.startsWith("file://")
|
||||
) {
|
||||
val uriToParse = Uri.parse(filePath)
|
||||
val result = FileUtils.getFilePath(coreContext.context, uriToParse)
|
||||
Log.i("[Image Utils] Path was using a content or file scheme, real path is: $filePath")
|
||||
if (result == null) {
|
||||
Log.e("[Image Utils] Failed to get access to file $uriToParse")
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
|
||||
private fun getRoundBitmap(bitmap: Bitmap): Bitmap? {
|
||||
val output =
|
||||
Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
|
||||
|
|
Loading…
Reference in a new issue