Added use of LocusId to conversations notifications & shortcuts

This commit is contained in:
Sylvain Berfini 2021-02-02 11:55:48 +01:00
parent 98fdb56f45
commit a757b097fa
10 changed files with 86 additions and 12 deletions

View file

@ -185,7 +185,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.media:media:1.2.0' implementation 'androidx.media:media:1.2.0'
implementation 'androidx.fragment:fragment-ktx:1.2.5' implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.core:core-ktx:1.5.0-beta01'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.2' implementation 'androidx.navigation:navigation-ui-ktx:2.3.2'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
@ -199,8 +199,8 @@ dependencies {
implementation 'androidx.emoji:emoji:1.1.0' implementation 'androidx.emoji:emoji:1.1.0'
implementation 'androidx.emoji:emoji-bundled:1.1.0' implementation 'androidx.emoji:emoji-bundled:1.1.0'
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0' kapt 'com.github.bumptech.glide:compiler:4.12.0'
if (firebaseEnabled()) { if (firebaseEnabled()) {
implementation 'com.google.firebase:firebase-messaging:19.0.1' implementation 'com.google.firebase:firebase-messaging:19.0.1'

View file

@ -52,6 +52,10 @@
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<nav-graph android:value="@navigation/main_nav_graph" /> <nav-graph android:value="@navigation/main_nav_graph" />
<intent-filter>
<action android:name="android.intent.action.VIEW_LOCUS" />
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />

View file

@ -211,6 +211,11 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
handleTelOrSipUri(uri) handleTelOrSipUri(uri)
} }
} }
Intent.ACTION_VIEW_LOCUS -> {
if (corePreferences.disableChat) return
val locus = Compatibility.extractLocusIdFromIntent(intent)
if (locus != null) handleLocus(locus)
}
else -> { else -> {
when { when {
intent.hasExtra("ContactId") -> { intent.hasExtra("ContactId") -> {
@ -365,4 +370,17 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
findNavController(R.id.nav_host_fragment).navigate(Uri.parse(deepLink)) findNavController(R.id.nav_host_fragment).navigate(Uri.parse(deepLink))
} }
} }
private fun handleLocus(id: String) {
Log.i("[Main Activity] Found chat room locus intent extra: $id")
val split = id.split("~")
if (split.size == 2) {
val localAddress = split[0]
val peerAddress = split[1]
val deepLink = "linphone-android://chat-room/$localAddress/$peerAddress"
findNavController(R.id.nav_host_fragment).navigate(Uri.parse(deepLink))
} else {
Log.e("[Main Activity] Failed to parse locus id: $id")
}
}
} }

View file

@ -50,6 +50,7 @@ import org.linphone.activities.main.chat.viewmodels.*
import org.linphone.activities.main.fragments.MasterFragment import org.linphone.activities.main.fragments.MasterFragment
import org.linphone.activities.main.viewmodels.DialogViewModel import org.linphone.activities.main.viewmodels.DialogViewModel
import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.compatibility.Compatibility
import org.linphone.core.* import org.linphone.core.*
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.databinding.ChatRoomDetailFragmentBinding import org.linphone.databinding.ChatRoomDetailFragmentBinding
@ -118,6 +119,8 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
val chatRoom = sharedViewModel.selectedChatRoom.value val chatRoom = sharedViewModel.selectedChatRoom.value
chatRoom ?: return chatRoom ?: return
Compatibility.setLocusIdInContentCaptureSession(binding.root, chatRoom)
chatRoomAddress = chatRoom.peerAddress.asStringUriOnly() chatRoomAddress = chatRoom.peerAddress.asStringUriOnly()
isSecure = chatRoom.currentParams.encryptionEnabled() isSecure = chatRoom.currentParams.encryptionEnabled()
@ -337,7 +340,10 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
lifecycleScope.launch { lifecycleScope.launch {
for (fileToUploadPath in ImageUtils.getFilesPathFromPickerIntent(data, chatSendingViewModel.temporaryFileUploadPath)) { for (fileToUploadPath in ImageUtils.getFilesPathFromPickerIntent(
data,
chatSendingViewModel.temporaryFileUploadPath
)) {
if (fileToUploadPath != null) { if (fileToUploadPath != null) {
chatSendingViewModel.addAttachment(fileToUploadPath) chatSendingViewModel.addAttachment(fileToUploadPath)
} }

View file

@ -22,17 +22,37 @@ package org.linphone.compatibility
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.view.View
import android.view.contentcapture.ContentCaptureContext
import android.view.contentcapture.ContentCaptureSession
import org.linphone.R import org.linphone.R
import org.linphone.core.ChatRoom
import org.linphone.core.Content import org.linphone.core.Content
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.utils.AppUtils import org.linphone.utils.AppUtils
import org.linphone.utils.FileUtils import org.linphone.utils.FileUtils
import org.linphone.utils.LinphoneUtils
@TargetApi(29) @TargetApi(29)
class Api29Compatibility { class Api29Compatibility {
companion object { companion object {
fun extractLocusIdFromIntent(intent: Intent): String? {
return intent.getStringExtra(Intent.EXTRA_LOCUS_ID)
}
fun setLocusIdInContentCaptureSession(root: View, chatRoom: ChatRoom) {
val session: ContentCaptureSession? = root.contentCaptureSession
if (session != null) {
val localAddress = chatRoom.localAddress.asStringUriOnly()
val peerAddress = chatRoom.peerAddress.asStringUriOnly()
val id = LinphoneUtils.getChatRoomId(localAddress, peerAddress)
session.contentCaptureContext = ContentCaptureContext.forLocusId(id)
}
}
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean { suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
val filePath = content.filePath val filePath = content.filePath
if (filePath == null) { if (filePath == null) {

View file

@ -23,6 +23,7 @@ import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.content.pm.ShortcutManager import android.content.pm.ShortcutManager
import org.linphone.core.ChatRoom import org.linphone.core.ChatRoom
import org.linphone.utils.LinphoneUtils
@TargetApi(30) @TargetApi(30)
class Api30Compatibility { class Api30Compatibility {
@ -32,7 +33,8 @@ class Api30Compatibility {
val localAddress = chatRoom.localAddress.asStringUriOnly() val localAddress = chatRoom.localAddress.asStringUriOnly()
val shortcutManager = context.getSystemService(ShortcutManager::class.java) val shortcutManager = context.getSystemService(ShortcutManager::class.java)
val shortcutsToRemoveList = arrayListOf("$localAddress#$peerAddress") val id = LinphoneUtils.getChatRoomId(localAddress, peerAddress)
val shortcutsToRemoveList = arrayListOf(id)
shortcutManager.removeLongLivedShortcuts(shortcutsToRemoveList) shortcutManager.removeLongLivedShortcuts(shortcutsToRemoveList)
} }
} }

View file

@ -21,8 +21,10 @@ package org.linphone.compatibility
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Vibrator import android.os.Vibrator
import android.view.View
import android.view.WindowManager import android.view.WindowManager
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import org.linphone.core.ChatRoom import org.linphone.core.ChatRoom
@ -152,6 +154,19 @@ class Compatibility {
} }
} }
fun extractLocusIdFromIntent(intent: Intent): String? {
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
return Api29Compatibility.extractLocusIdFromIntent(intent)
}
return null
}
fun setLocusIdInContentCaptureSession(root: View, chatRoom: ChatRoom) {
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
return Api29Compatibility.setLocusIdInContentCaptureSession(root, chatRoom)
}
}
suspend fun addImageToMediaStore(context: Context, content: Content): Boolean { suspend fun addImageToMediaStore(context: Context, content: Content): Boolean {
if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) { if (Version.sdkAboveOrEqual(Version.API29_ANDROID_10)) {
return Api29Compatibility.addImageToMediaStore(context, content) return Api29Compatibility.addImageToMediaStore(context, content)

View file

@ -33,6 +33,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person import androidx.core.app.Person
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.LocusIdCompat
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import androidx.navigation.NavDeepLinkBuilder import androidx.navigation.NavDeepLinkBuilder
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
@ -528,8 +529,9 @@ class NotificationsManager(private val context: Context) {
.setArguments(args) .setArguments(args)
.createPendingIntent() .createPendingIntent()
val notification = createMessageNotification(notifiable, pendingIntent, "$localAddress#$peerAddress") val id = LinphoneUtils.getChatRoomId(localAddress, peerAddress)
if (notification != null) notify(notifiable.notificationId, notification) val notification = createMessageNotification(notifiable, pendingIntent, id)
notify(notifiable.notificationId, notification)
} }
private fun displayIncomingChatNotification(room: ChatRoom, message: ChatMessage) { private fun displayIncomingChatNotification(room: ChatRoom, message: ChatMessage) {
@ -621,8 +623,8 @@ class NotificationsManager(private val context: Context) {
private fun createMessageNotification( private fun createMessageNotification(
notifiable: Notifiable, notifiable: Notifiable,
pendingIntent: PendingIntent, pendingIntent: PendingIntent,
shortcutId: String id: String
): Notification? { ): Notification {
val me = Person.Builder().setName(notifiable.myself).build() val me = Person.Builder().setName(notifiable.myself).build()
val style = NotificationCompat.MessagingStyle(me) val style = NotificationCompat.MessagingStyle(me)
val largeIcon: Bitmap? = notifiable.messages.last().senderAvatar val largeIcon: Bitmap? = notifiable.messages.last().senderAvatar
@ -676,7 +678,8 @@ class NotificationsManager(private val context: Context) {
.setColor(ContextCompat.getColor(context, R.color.primary_color)) .setColor(ContextCompat.getColor(context, R.color.primary_color))
.addAction(getReplyMessageAction(notifiable)) .addAction(getReplyMessageAction(notifiable))
.addAction(getMarkMessageAsReadAction(notifiable)) .addAction(getMarkMessageAsReadAction(notifiable))
.setShortcutId(shortcutId) .setShortcutId(id)
.setLocusId(LocusIdCompat(id))
if (corePreferences.markAsReadUponChatMessageNotificationDismissal) { if (corePreferences.markAsReadUponChatMessageNotificationDismissal) {
Log.i("[Notifications Manager] Chat room will be marked as read when notification will be dismissed") Log.i("[Notifications Manager] Chat room will be marked as read when notification will be dismissed")
notificationBuilder notificationBuilder

View file

@ -23,7 +23,6 @@ import android.content.Context
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.NetworkInfo import android.net.NetworkInfo
import android.telephony.TelephonyManager.* import android.telephony.TelephonyManager.*
import androidx.core.content.ContextCompat.getSystemService
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -136,5 +135,9 @@ class LinphoneUtils {
callLog.status == Call.Status.Aborted || callLog.status == Call.Status.Aborted ||
callLog.status == Call.Status.EarlyAborted)) callLog.status == Call.Status.EarlyAborted))
} }
fun getChatRoomId(localAddress: String, remoteAddress: String): String {
return "$localAddress~$remoteAddress"
}
} }
} }

View file

@ -27,6 +27,7 @@ import android.content.pm.ShortcutManager
import android.os.Bundle import android.os.Bundle
import androidx.collection.ArraySet import androidx.collection.ArraySet
import androidx.core.app.Person import androidx.core.app.Person
import androidx.core.content.LocusIdCompat
import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
@ -201,13 +202,15 @@ class ShortcutsHelper(val context: Context) {
intent.putExtra("RemoteSipUri", peerAddress) intent.putExtra("RemoteSipUri", peerAddress)
intent.putExtra("LocalSipUri", localAddress) intent.putExtra("LocalSipUri", localAddress)
return ShortcutInfoCompat.Builder(context, "$localAddress#$peerAddress") val id = LinphoneUtils.getChatRoomId(localAddress, peerAddress)
return ShortcutInfoCompat.Builder(context, id)
.setShortLabel(subject) .setShortLabel(subject)
.setIcon(icon) .setIcon(icon)
.setPersons(persons) .setPersons(persons)
.setCategories(categories) .setCategories(categories)
.setIntent(intent) .setIntent(intent)
.setLongLived(Version.sdkAboveOrEqual(Version.API30_ANDROID_11)) .setLongLived(Version.sdkAboveOrEqual(Version.API30_ANDROID_11))
.setLocusId(LocusIdCompat(id))
.build().toShortcutInfo() .build().toShortcutInfo()
} catch (e: Exception) { } catch (e: Exception) {
Log.e("[Shortcuts Helper] ShortcutInfo.Builder exception: $e") Log.e("[Shortcuts Helper] ShortcutInfo.Builder exception: $e")