Factorized code related to copying data into clipboard, added exception catch

This commit is contained in:
Sylvain Berfini 2026-01-14 11:53:06 +01:00
parent 5ad7b5da14
commit d467699388
13 changed files with 83 additions and 118 deletions

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.call.conference.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.os.SystemClock
import android.view.LayoutInflater
@ -43,6 +40,7 @@ import org.linphone.ui.call.CallActivity
import org.linphone.ui.call.fragment.GenericCallFragment
import org.linphone.ui.call.viewmodel.CallsViewModel
import org.linphone.ui.call.viewmodel.CurrentCallViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
import org.linphone.utils.startAnimatedDrawable
@ -272,14 +270,12 @@ class ActiveConferenceCallFragment : GenericCallFragment() {
}
}
binding.setShareConferenceClickListener {
binding.setCopyConferenceUriToClipboardClickListener {
val sipUri = callViewModel.conferenceModel.sipUri.value.orEmpty()
if (sipUri.isNotEmpty()) {
Log.i("$TAG Sharing conference SIP URI [$sipUri]")
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
Log.i("$TAG Copying conference SIP URI [$sipUri] into clipboard")
val label = "Conference SIP address"
clipboard.setPrimaryClip(ClipData.newPlainText(label, sipUri))
AppUtils.copyToClipboard(requireContext(), label, sipUri)
}
}

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.call.conference.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
@ -45,6 +42,7 @@ import org.linphone.ui.GenericActivity
import org.linphone.ui.call.adapter.ConferenceParticipantsListAdapter
import org.linphone.ui.call.fragment.GenericCallFragment
import org.linphone.ui.call.viewmodel.CurrentCallViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.ConfirmationDialogModel
import org.linphone.utils.DialogUtils
@ -207,10 +205,8 @@ class ConferenceParticipantsListFragment : GenericCallFragment() {
val sipUri = viewModel.conferenceModel.sipUri.value.orEmpty()
if (sipUri.isNotEmpty()) {
Log.i("$TAG Sharing conference SIP URI [$sipUri]")
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = "Conference SIP address"
clipboard.setPrimaryClip(ClipData.newPlainText(label, sipUri))
AppUtils.copyToClipboard(requireContext(), label, sipUri)
}
popupWindow.dismiss()

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.main.chat.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
@ -46,6 +43,7 @@ import org.linphone.ui.main.chat.viewmodel.ConversationInfoViewModel
import org.linphone.ui.main.fragment.SlidingPaneChildFragment
import org.linphone.utils.ConfirmationDialogModel
import org.linphone.ui.main.model.GroupSetOrEditSubjectDialogModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
@ -428,14 +426,13 @@ class ConversationInfoFragment : SlidingPaneChildFragment() {
popupView.setCopySipUriClickListener {
val sipUri = participantModel.sipUri
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText("SIP address", sipUri))
val message = getString(R.string.sip_address_copied_to_clipboard_toast)
(requireActivity() as GenericActivity).showGreenToast(
message,
R.drawable.check
)
if (AppUtils.copyToClipboard(requireContext(), "SIP address", sipUri)) {
val message = getString(R.string.sip_address_copied_to_clipboard_toast)
(requireActivity() as GenericActivity).showGreenToast(
message,
R.drawable.check
)
}
}
// Elevation is for showing a shadow around the popup
@ -490,12 +487,9 @@ class ConversationInfoFragment : SlidingPaneChildFragment() {
}
private fun copyAddressToClipboard(value: String) {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText("SIP address", value))
val message = getString(R.string.sip_address_copied_to_clipboard_toast)
(requireActivity() as GenericActivity).showGreenToast(
message,
R.drawable.check
)
if (AppUtils.copyToClipboard(requireContext(), "SIP address", value)) {
val message = getString(R.string.sip_address_copied_to_clipboard_toast)
(requireActivity() as GenericActivity).showGreenToast(message, R.drawable.check)
}
}
}

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.main.chat.viewmodel
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.view.View
import androidx.annotation.UiThread
import androidx.lifecycle.MutableLiveData
@ -31,6 +28,7 @@ import org.linphone.core.tools.Log
import org.linphone.databinding.ChatBubbleEmojiPickerBottomSheetBinding
import org.linphone.ui.GenericViewModel
import org.linphone.ui.main.chat.model.MessageModel
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
class ChatMessageLongPressViewModel : GenericViewModel() {
@ -148,12 +146,12 @@ class ChatMessageLongPressViewModel : GenericViewModel() {
@UiThread
fun copyClickListener() {
Log.i("$TAG Copying message text into clipboard")
val text = messageModel.value?.getRawTextContent()
val clipboard = coreContext.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = "Message"
clipboard.setPrimaryClip(ClipData.newPlainText(label, text))
val text = messageModel.value?.getRawTextContent().orEmpty()
if (text.isNotEmpty()) {
Log.i("$TAG Copying message text into clipboard")
val label = "Message"
AppUtils.copyToClipboard(coreContext.context, label, text)
}
dismiss()
}

View file

@ -21,9 +21,6 @@ package org.linphone.ui.main.contacts.fragment
import android.app.Dialog
import android.content.ActivityNotFoundException
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.provider.ContactsContract
@ -252,19 +249,15 @@ class ContactFragment : SlidingPaneChildFragment() {
}
private fun copyNumberOrAddressToClipboard(value: String, isSip: Boolean) {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = if (isSip) "SIP address" else "Phone number"
clipboard.setPrimaryClip(ClipData.newPlainText(label, value))
val message = if (isSip) {
getString(R.string.sip_address_copied_to_clipboard_toast)
} else {
getString(R.string.contact_details_phone_number_copied_to_clipboard_toast)
if (AppUtils.copyToClipboard(requireContext(), label, value)) {
val message = if (isSip) {
getString(R.string.sip_address_copied_to_clipboard_toast)
} else {
getString(R.string.contact_details_phone_number_copied_to_clipboard_toast)
}
(requireActivity() as GenericActivity).showGreenToast(message, R.drawable.check)
}
(requireActivity() as GenericActivity).showGreenToast(
message,
R.drawable.check
)
}
private fun shareContact(name: String, file: File) {

View file

@ -20,9 +20,6 @@
package org.linphone.ui.main.help.fragment
import android.content.ActivityNotFoundException
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
@ -39,6 +36,7 @@ import org.linphone.ui.fileviewer.FileViewerActivity
import org.linphone.ui.main.MainActivity
import org.linphone.ui.main.fragment.GenericMainFragment
import org.linphone.ui.main.help.viewmodel.HelpViewModel
import org.linphone.utils.AppUtils
class DebugFragment : GenericMainFragment() {
private lateinit var binding: HelpDebugFragmentBinding
@ -69,19 +67,15 @@ class DebugFragment : GenericMainFragment() {
}
binding.setAppVersionClickListener {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = getString(R.string.help_troubleshooting_app_version_title)
clipboard.setPrimaryClip(
ClipData.newPlainText(label, viewModel.appVersion.value.orEmpty())
)
val value = viewModel.appVersion.value.orEmpty()
AppUtils.copyToClipboard(requireContext(), label, value)
}
binding.setSdkVersionClickListener {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = getString(R.string.help_troubleshooting_sdk_version_title)
clipboard.setPrimaryClip(
ClipData.newPlainText(label, viewModel.sdkVersion.value.orEmpty())
)
val value = viewModel.sdkVersion.value.orEmpty()
AppUtils.copyToClipboard(requireContext(), label, value)
}
viewModel.debugLogsCleanedEvent.observe(viewLifecycleOwner) {
@ -96,9 +90,7 @@ class DebugFragment : GenericMainFragment() {
viewModel.uploadDebugLogsFinishedEvent.observe(viewLifecycleOwner) {
it.consume { url ->
if (requireActivity() is AssistantActivity) {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = "Logs upload URL"
clipboard.setPrimaryClip(ClipData.newPlainText(label, url))
AppUtils.copyToClipboard(requireContext(), "Logs upload URL", url)
return@consume
}

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.main.history.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
@ -44,6 +41,7 @@ import org.linphone.ui.main.fragment.SlidingPaneChildFragment
import org.linphone.ui.main.history.adapter.ContactHistoryListAdapter
import org.linphone.utils.ConfirmationDialogModel
import org.linphone.ui.main.history.viewmodel.HistoryViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
@ -190,14 +188,12 @@ class HistoryFragment : SlidingPaneChildFragment() {
}
private fun copyNumberOrAddressToClipboard(value: String) {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = "SIP address"
clipboard.setPrimaryClip(ClipData.newPlainText(label, value))
(requireActivity() as GenericActivity).showGreenToast(
getString(R.string.sip_address_copied_to_clipboard_toast),
R.drawable.check
)
if (AppUtils.copyToClipboard(requireContext(), "SIP address", value)) {
(requireActivity() as GenericActivity).showGreenToast(
getString(R.string.sip_address_copied_to_clipboard_toast),
R.drawable.check
)
}
}
private fun showPopupMenu() {

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.main.history.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
@ -47,6 +44,7 @@ import org.linphone.ui.main.fragment.AbstractMainFragment
import org.linphone.ui.main.history.adapter.HistoryListAdapter
import org.linphone.utils.ConfirmationDialogModel
import org.linphone.ui.main.history.viewmodel.HistoryListViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
@ -283,14 +281,12 @@ class HistoryListFragment : AbstractMainFragment() {
}
private fun copyNumberOrAddressToClipboard(value: String) {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = "SIP address"
clipboard.setPrimaryClip(ClipData.newPlainText(label, value))
(requireActivity() as GenericActivity).showGreenToast(
getString(R.string.sip_address_copied_to_clipboard_toast),
R.drawable.check
)
if (AppUtils.copyToClipboard(requireContext(), "SIP address", value)) {
(requireActivity() as GenericActivity).showGreenToast(
getString(R.string.sip_address_copied_to_clipboard_toast),
R.drawable.check
)
}
}
private fun showPopupMenu() {

View file

@ -20,9 +20,6 @@
package org.linphone.ui.main.meetings.fragment
import android.content.ActivityNotFoundException
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.provider.CalendarContract
@ -47,6 +44,7 @@ import org.linphone.ui.main.fragment.SlidingPaneChildFragment
import org.linphone.utils.ConfirmationDialogModel
import org.linphone.ui.main.meetings.adapter.MeetingParticipantsAdapter
import org.linphone.ui.main.meetings.viewmodel.MeetingViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
@ -136,7 +134,7 @@ class MeetingFragment : SlidingPaneChildFragment() {
}
}
binding.setShareClickListener {
binding.setCopyUriToClipboardClickListener {
copyMeetingAddressIntoClipboard(uri)
}
@ -249,15 +247,12 @@ class MeetingFragment : SlidingPaneChildFragment() {
private fun copyMeetingAddressIntoClipboard(meetingSipUri: String) {
Log.i("$TAG Copying conference SIP URI [$meetingSipUri] into clipboard")
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val label = "Meeting SIP address"
clipboard.setPrimaryClip(ClipData.newPlainText(label, meetingSipUri))
(requireActivity() as GenericActivity).showGreenToast(
getString(R.string.meeting_address_copied_to_clipboard_toast),
R.drawable.check
)
if (AppUtils.copyToClipboard(requireContext(), "Meeting SIP address", meetingSipUri)) {
(requireActivity() as GenericActivity).showGreenToast(
getString(R.string.meeting_address_copied_to_clipboard_toast),
R.drawable.check
)
}
}
private fun shareMeetingInfoAsCalendarEvent() {

View file

@ -19,9 +19,6 @@
*/
package org.linphone.ui.main.settings.fragment
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -43,6 +40,7 @@ import org.linphone.ui.GenericActivity
import org.linphone.ui.main.fragment.GenericMainFragment
import org.linphone.utils.ConfirmationDialogModel
import org.linphone.ui.main.settings.viewmodel.AccountProfileViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
import org.linphone.utils.FileUtils
@ -229,13 +227,10 @@ class AccountProfileFragment : GenericMainFragment() {
}
private fun copyAddressToClipboard(value: String) {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText("SIP address", value))
val message = getString(R.string.sip_address_copied_to_clipboard_toast)
(requireActivity() as GenericActivity).showGreenToast(
message,
R.drawable.check
)
if (AppUtils.copyToClipboard(requireContext(), "SIP address", value)) {
val message = getString(R.string.sip_address_copied_to_clipboard_toast)
(requireActivity() as GenericActivity).showGreenToast(message, R.drawable.check)
}
}
private fun setupDialPlanPicker() {

View file

@ -20,6 +20,8 @@
package org.linphone.utils
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.provider.Settings
@ -205,6 +207,18 @@ class AppUtils {
return name
}
@AnyThread
fun copyToClipboard(context: Context, label: String, value: String): Boolean {
try {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText(label, value))
return true
} catch (e: Exception) {
Log.e("$TAG Failed to copy text [$value] with label [$label] to clipboard: $e")
}
return false
}
@AnyThread
private fun extractFirstSymbol(text: String): String {
val sequence = StringBuilder(text.length)

View file

@ -10,7 +10,7 @@
name="backClickListener"
type="View.OnClickListener" />
<variable
name="shareConferenceClickListener"
name="copyConferenceUriToClipboardClickListener"
type="View.OnClickListener" />
<variable
name="callsListClickListener"
@ -219,7 +219,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_600"
android:id="@+id/share_conference_link"
android:onClick="@{shareConferenceClickListener}"
android:onClick="@{copyConferenceUriToClipboardClickListener}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"

View file

@ -15,7 +15,7 @@
name="menuClickListener"
type="View.OnClickListener" />
<variable
name="shareClickListener"
name="copyUriToClipboardClickListener"
type="View.OnClickListener" />
<variable
name="joinClickListener"
@ -139,7 +139,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style"
android:id="@+id/sip_uri"
android:onClick="@{shareClickListener}"
android:onClick="@{copyUriToClipboardClickListener}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"