Using new unified API for content insertion

This commit is contained in:
Sylvain Berfini 2021-09-13 17:20:44 +02:00
parent f7ba6fc87c
commit 57af8806f7
5 changed files with 101 additions and 38 deletions

View file

@ -22,6 +22,7 @@ Group changes to describe their impact on the project, as follows:
### Changed
- UI has been reworked around SlidingPane component to better handle tablets & foldable devices
- Animations have been replaced to use com.google.android.material.transition ones
- Using new [Unified Content API](https://developer.android.com/about/versions/12/features/unified-content-api) to share files from keyboard (or other sources)
- Bumped dependencies, gradle updated from 4.2.2 to 7.0.2
- Target Android SDK version set to 31 (Android 12)
- SDK updated to 5.1.0 release

View file

@ -38,7 +38,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.io.File
import java.lang.IllegalArgumentException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
@ -449,6 +451,24 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
}
}
sharedViewModel.richContentUri.observe(
viewLifecycleOwner,
{
it.consume { uri ->
Log.i("[Chat] Found rich content URI: $uri")
lifecycleScope.launch {
withContext(Dispatchers.Main) {
val path = FileUtils.getFilePath(requireContext(), uri)
Log.i("[Chat] Rich content URI: $uri matching path is: $path")
if (path != null) {
chatSendingViewModel.addAttachment(path)
}
}
}
}
}
)
sharedViewModel.messageToForwardEvent.observe(
viewLifecycleOwner,
{

View file

@ -0,0 +1,50 @@
/*
* 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.activities.main.chat.receivers
import android.content.ClipData
import android.net.Uri
import android.view.View
import androidx.core.util.component1
import androidx.core.util.component2
import androidx.core.view.ContentInfoCompat
import androidx.core.view.OnReceiveContentListener
import org.linphone.core.tools.Log
class RichContentReceiver(private val contentReceived: (uri: Uri) -> Unit) : OnReceiveContentListener {
companion object {
val MIME_TYPES = arrayOf("image/png", "image/gif", "image/jpeg")
}
override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
val (uriContent, remaining) = payload.partition { item -> item.uri != null }
if (uriContent != null) {
val clip: ClipData = uriContent.clip
for (i in 0 until clip.itemCount) {
val uri: Uri = clip.getItemAt(i).uri
Log.i("[Content Receiver] Found URI: $uri")
contentReceived(uri)
}
}
// Return anything that your app didn't handle. This preserves the default platform
// behavior for text and anything else that you aren't implementing custom handling for.
return remaining
}
}

View file

@ -19,61 +19,49 @@
*/
package org.linphone.activities.main.chat.views
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.util.AttributeSet
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.view.inputmethod.EditorInfoCompat
import androidx.core.view.inputmethod.InputConnectionCompat
import androidx.core.view.inputmethod.InputContentInfoCompat
import androidx.core.view.ViewCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import org.linphone.activities.main.chat.receivers.RichContentReceiver
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.core.tools.Log
import org.linphone.utils.Event
/**
* Allows for image input inside an EditText, usefull for keyboards with gif support for example.
*/
class RichEditText : AppCompatEditText {
private var mListener: RichInputListener? = null
private var mSupportedMimeTypes: Array<String>? = null
interface RichInputListener {
fun onCommitContent(
inputContentInfo: InputContentInfoCompat,
flags: Int,
opts: Bundle?,
contentMimeTypes: Array<String>?
): Boolean
constructor(context: Context) : super(context) {
initReceiveContentListener()
}
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initReceiveContentListener()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
fun setListener(listener: RichInputListener) {
mListener = listener
mSupportedMimeTypes = arrayOf("image/png", "image/gif", "image/jpeg")
) {
initReceiveContentListener()
}
override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection? {
val ic = super.onCreateInputConnection(editorInfo)
EditorInfoCompat.setContentMimeTypes(editorInfo, mSupportedMimeTypes)
val callback =
InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, opts ->
val listener = mListener
listener?.onCommitContent(
inputContentInfo, flags, opts, mSupportedMimeTypes
) ?: false
private fun initReceiveContentListener() {
ViewCompat.setOnReceiveContentListener(
this, RichContentReceiver.MIME_TYPES,
RichContentReceiver { uri ->
Log.i("[Rich Edit Text] Received URI: $uri")
val activity = context as Activity
val sharedViewModel = activity.run {
ViewModelProvider(activity as ViewModelStoreOwner).get(SharedMainViewModel::class.java)
}
sharedViewModel.richContentUri.value = Event(uri)
}
return if (ic != null) {
InputConnectionCompat.createWrapper(ic, editorInfo, callback)
} else null
)
}
}

View file

@ -19,6 +19,7 @@
*/
package org.linphone.activities.main.viewmodels
import android.net.Uri
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.linphone.activities.main.history.data.GroupedCallLogData
@ -66,6 +67,9 @@ class SharedMainViewModel : ViewModel() {
var chatRoomSubject: String = ""
// When using keyboard to share gif or other, see RichContentReceiver & RichEditText classes
val richContentUri = MutableLiveData<Event<Uri>>()
/* Contacts */
val contactFragmentOpenedEvent: MutableLiveData<Event<Boolean>> by lazy {