diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d344203e..fffbe7094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt index 0c3a508ef..bd8622910 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/DetailChatRoomFragment.kt @@ -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 + 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, { diff --git a/app/src/main/java/org/linphone/activities/main/chat/receivers/RichContentReceiver.kt b/app/src/main/java/org/linphone/activities/main/chat/receivers/RichContentReceiver.kt new file mode 100644 index 000000000..e8dfeaee0 --- /dev/null +++ b/app/src/main/java/org/linphone/activities/main/chat/receivers/RichContentReceiver.kt @@ -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 . + */ +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 + } +} diff --git a/app/src/main/java/org/linphone/activities/main/chat/views/RichEditText.kt b/app/src/main/java/org/linphone/activities/main/chat/views/RichEditText.kt index b1280c6ab..f69a750c8 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/views/RichEditText.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/views/RichEditText.kt @@ -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? = null - - interface RichInputListener { - fun onCommitContent( - inputContentInfo: InputContentInfoCompat, - flags: Int, - opts: Bundle?, - contentMimeTypes: Array? - ): 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 + ) } } diff --git a/app/src/main/java/org/linphone/activities/main/viewmodels/SharedMainViewModel.kt b/app/src/main/java/org/linphone/activities/main/viewmodels/SharedMainViewModel.kt index e4abe554f..762d39d2f 100644 --- a/app/src/main/java/org/linphone/activities/main/viewmodels/SharedMainViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/viewmodels/SharedMainViewModel.kt @@ -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>() + /* Contacts */ val contactFragmentOpenedEvent: MutableLiveData> by lazy {