Added shortcuts to chat rooms if contacts shortcuts are disabled

This commit is contained in:
Sylvain Berfini 2020-04-06 12:41:36 +02:00
parent 339e30a75e
commit 0710256695
12 changed files with 173 additions and 16 deletions

View file

@ -57,9 +57,11 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
private val listener = object : ContactsUpdatedListenerStub() { private val listener = object : ContactsUpdatedListenerStub() {
override fun onContactsUpdated() { override fun onContactsUpdated() {
Log.i("[Main Activity] Contact(s) updated, update shortcuts")
if (corePreferences.contactsShortcuts) { if (corePreferences.contactsShortcuts) {
Log.i("[Main Activity] Contact(s) updated, update shortcuts")
Compatibility.createShortcutsToContacts(this@MainActivity) Compatibility.createShortcutsToContacts(this@MainActivity)
} else if (corePreferences.chatRoomShortcuts) {
Compatibility.createShortcutsToChatRooms(this@MainActivity)
} }
} }
} }
@ -89,8 +91,6 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
startActivity(intent) startActivity(intent)
} }
if (intent != null) handleIntentParams(intent)
if (coreContext.core.proxyConfigList.isEmpty()) { if (coreContext.core.proxyConfigList.isEmpty()) {
if (corePreferences.firstStart) { if (corePreferences.firstStart) {
corePreferences.firstStart = false corePreferences.firstStart = false
@ -122,6 +122,8 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
override fun onPostCreate(savedInstanceState: Bundle?) { override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState) super.onPostCreate(savedInstanceState)
findNavController(R.id.nav_host_fragment).addOnDestinationChangedListener(this) findNavController(R.id.nav_host_fragment).addOnDestinationChangedListener(this)
if (intent != null) handleIntentParams(intent)
} }
override fun onDestroy() { override fun onDestroy() {
@ -194,8 +196,16 @@ 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))
} }
intent.hasExtra("Chat") -> { intent.hasExtra("Chat") -> {
Log.i("[Main Activity] Found chat intent extra, go to chat rooms list") val deepLink = if (intent.hasExtra("RemoteSipUri") && intent.hasExtra("LocalSipUri")) {
findNavController(R.id.nav_host_fragment).navigate(R.id.action_global_masterChatRoomsFragment) val peerAddress = intent.getStringExtra("RemoteSipUri")
val localAddress = intent.getStringExtra("LocalSipUri")
Log.i("[Main Activity] Found chat room intent extra: local SIP URI=[$localAddress], peer SIP URI=[$peerAddress]")
"linphone-android://chat-room/$localAddress/$peerAddress"
} else {
Log.i("[Main Activity] Found chat intent extra, go to chat rooms list")
"linphone-android://chat/"
}
findNavController(R.id.nav_host_fragment).navigate(Uri.parse(deepLink))
} }
intent.hasExtra("Dialer") -> { intent.hasExtra("Dialer") -> {
Log.i("[Main Activity] Found dialer intent extra, go to dialer") Log.i("[Main Activity] Found dialer intent extra, go to dialer")

View file

@ -196,7 +196,7 @@ class MasterChatRoomsFragment : MasterFragment() {
val localSipUri = arguments?.getString("LocalSipUri") val localSipUri = arguments?.getString("LocalSipUri")
val remoteSipUri = arguments?.getString("RemoteSipUri") val remoteSipUri = arguments?.getString("RemoteSipUri")
if (localSipUri != null && remoteSipUri != null) { if (localSipUri != null && remoteSipUri != null) {
Log.i("[Chat] Found local ($localSipUri) & remote addresses ($remoteSipUri) in arguments") Log.i("[Chat] Found local [$localSipUri] & remote [$remoteSipUri] addresses in arguments")
arguments?.clear() arguments?.clear()
val localAddress = Factory.instance().createAddress(localSipUri) val localAddress = Factory.instance().createAddress(localSipUri)
val remoteSipAddress = Factory.instance().createAddress(remoteSipUri) val remoteSipAddress = Factory.instance().createAddress(remoteSipUri)

View file

@ -24,10 +24,12 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.linphone.R import org.linphone.R
import org.linphone.activities.main.settings.viewmodels.ChatSettingsViewModel import org.linphone.activities.main.settings.viewmodels.ChatSettingsViewModel
import org.linphone.compatibility.Compatibility
import org.linphone.databinding.SettingsChatFragmentBinding import org.linphone.databinding.SettingsChatFragmentBinding
class ChatSettingsFragment : Fragment() { class ChatSettingsFragment : Fragment() {
@ -53,5 +55,15 @@ class ChatSettingsFragment : Fragment() {
binding.setBackClickListener { findNavController().popBackStack() } binding.setBackClickListener { findNavController().popBackStack() }
binding.back.visibility = if (resources.getBoolean(R.bool.isTablet)) View.INVISIBLE else View.VISIBLE binding.back.visibility = if (resources.getBoolean(R.bool.isTablet)) View.INVISIBLE else View.VISIBLE
viewModel.launcherShortcutsEvent.observe(viewLifecycleOwner, Observer {
it.consume { newValue ->
if (newValue) {
Compatibility.createShortcutsToChatRooms(requireContext())
} else {
Compatibility.removeShortcuts(requireContext())
}
}
})
} }
} }

View file

@ -27,6 +27,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R import org.linphone.R
import org.linphone.activities.main.settings.viewmodels.ContactsSettingsViewModel import org.linphone.activities.main.settings.viewmodels.ContactsSettingsViewModel
import org.linphone.compatibility.Compatibility import org.linphone.compatibility.Compatibility
@ -61,7 +62,10 @@ class ContactsSettingsFragment : Fragment() {
if (newValue) { if (newValue) {
Compatibility.createShortcutsToContacts(requireContext()) Compatibility.createShortcutsToContacts(requireContext())
} else { } else {
Compatibility.removeShortcutsToContacts(requireContext()) Compatibility.removeShortcuts(requireContext())
if (corePreferences.chatRoomShortcuts) {
Compatibility.createShortcutsToChatRooms(requireContext())
}
} }
} }
}) })

View file

@ -21,6 +21,7 @@ package org.linphone.activities.main.settings.viewmodels
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import org.linphone.activities.main.settings.SettingListenerStub import org.linphone.activities.main.settings.SettingListenerStub
import org.linphone.utils.Event
class ChatSettingsViewModel : GenericSettingsViewModel() { class ChatSettingsViewModel : GenericSettingsViewModel() {
val fileSharingUrlListener = object : SettingListenerStub() { val fileSharingUrlListener = object : SettingListenerStub() {
@ -37,6 +38,15 @@ class ChatSettingsViewModel : GenericSettingsViewModel() {
} }
val downloadedImagesPublic = MutableLiveData<Boolean>() val downloadedImagesPublic = MutableLiveData<Boolean>()
val launcherShortcutsListener = object : SettingListenerStub() {
override fun onBoolValueChanged(newValue: Boolean) {
prefs.chatRoomShortcuts = newValue
launcherShortcutsEvent.value = Event(newValue)
}
}
val launcherShortcuts = MutableLiveData<Boolean>()
val launcherShortcutsEvent = MutableLiveData<Event<Boolean>>()
val hideEmptyRoomsListener = object : SettingListenerStub() { val hideEmptyRoomsListener = object : SettingListenerStub() {
override fun onBoolValueChanged(newValue: Boolean) { override fun onBoolValueChanged(newValue: Boolean) {
prefs.hideEmptyRooms = newValue prefs.hideEmptyRooms = newValue
@ -53,6 +63,7 @@ class ChatSettingsViewModel : GenericSettingsViewModel() {
init { init {
downloadedImagesPublic.value = prefs.makePublicDownloadedImages downloadedImagesPublic.value = prefs.makePublicDownloadedImages
launcherShortcuts.value = prefs.chatRoomShortcuts
hideEmptyRooms.value = prefs.hideEmptyRooms hideEmptyRooms.value = prefs.hideEmptyRooms
hideRoomsRemovedProxies.value = prefs.hideRoomsFromRemovedProxies hideRoomsRemovedProxies.value = prefs.hideRoomsFromRemovedProxies
fileSharingUrl.value = core.fileTransferServer fileSharingUrl.value = core.fileTransferServer

View file

@ -24,7 +24,7 @@ import android.bluetooth.BluetoothAdapter
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.provider.Settings import android.provider.Settings
import org.linphone.contact.ShortcutsHelper import org.linphone.utils.ShortcutsHelper
@TargetApi(25) @TargetApi(25)
class Api25Compatibility { class Api25Compatibility {
@ -52,7 +52,11 @@ class Api25Compatibility {
ShortcutsHelper.createShortcutsToContacts(context) ShortcutsHelper.createShortcutsToContacts(context)
} }
fun removeShortcutsToContacts(context: Context) { fun createShortcutsToChatRooms(context: Context) {
ShortcutsHelper.createShortcutsToChatRooms(context)
}
fun removeShortcuts(context: Context) {
ShortcutsHelper.removeShortcuts(context) ShortcutsHelper.removeShortcuts(context)
} }
} }

View file

@ -95,14 +95,20 @@ class Compatibility {
} }
} }
fun removeShortcutsToContacts(context: Context) { fun removeShortcuts(context: Context) {
if (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) { if (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) {
Api25Compatibility.removeShortcutsToContacts(context) Api25Compatibility.removeShortcuts(context)
} }
} }
/* Chat */ /* Chat */
fun createShortcutsToChatRooms(context: Context) {
if (Version.sdkAboveOrEqual(Version.API25_NOUGAT_71)) {
Api25Compatibility.createShortcutsToChatRooms(context)
}
}
fun addImageToMediaStore(context: Context, content: Content): Boolean { 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

@ -108,6 +108,12 @@ class CorePreferences constructor(private val context: Context) {
get() = config.getString("app", "device_name", Compatibility.getDeviceName(context)) get() = config.getString("app", "device_name", Compatibility.getDeviceName(context))
set(value) = config.setString("app", "device_name", value) set(value) = config.setString("app", "device_name", value)
var chatRoomShortcuts: Boolean
get() = config.getBool("app", "chat_room_shortcuts", true)
set(value) {
config.setBool("app", "chat_room_shortcuts", value)
}
/* Contacts */ /* Contacts */
// TODO: use it // TODO: use it
@ -124,9 +130,9 @@ class CorePreferences constructor(private val context: Context) {
} }
var contactsShortcuts: Boolean var contactsShortcuts: Boolean
get() = config.getBool("app", "shortcuts", true) get() = config.getBool("app", "contact_shortcuts", false)
set(value) { set(value) {
config.setBool("app", "shortcuts", value) config.setBool("app", "contact_shortcuts", value)
} }
/* Call */ /* Call */

View file

@ -17,18 +17,25 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.linphone.contact package org.linphone.utils
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager import android.content.pm.ShortcutManager
import android.os.Bundle
import androidx.collection.ArraySet import androidx.collection.ArraySet
import androidx.core.app.Person
import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.graphics.drawable.IconCompat
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.activities.main.MainActivity import org.linphone.activities.main.MainActivity
import org.linphone.contact.Contact
import org.linphone.contact.NativeContact
import org.linphone.core.Address import org.linphone.core.Address
import org.linphone.core.ChatRoom
import org.linphone.core.ChatRoomCapabilities import org.linphone.core.ChatRoomCapabilities
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
@ -114,6 +121,90 @@ class ShortcutsHelper(val context: Context) {
return null return null
} }
fun createShortcutsToChatRooms(context: Context) {
val shortcuts = ArrayList<ShortcutInfo>()
val shortcutManager = context.getSystemService(ShortcutManager::class.java)
if (shortcutManager.isRateLimitingActive) {
Log.e("[Shortcut Helper] Rate limiting is active, aborting")
return
}
val maxShortcuts = shortcutManager.maxShortcutCountPerActivity
var count = 0
for (room in coreContext.core.chatRooms) {
// Android can usually only have around 4-5 shortcuts at a time
if (count >= maxShortcuts) {
Log.w("[Shortcut Helper] Max amount of shortcuts reached ($count)")
break
}
val shortcut: ShortcutInfo? = createChatRoomShortcut(context, room)
if (shortcut != null) {
Log.i("[Shortcut Helper] Creating launcher shortcut for ${shortcut.shortLabel}")
shortcuts.add(shortcut)
count += 1
}
}
shortcutManager.dynamicShortcuts = shortcuts
}
private fun createChatRoomShortcut(context: Context, chatRoom: ChatRoom): ShortcutInfo? {
try {
val categories: ArraySet<String> = ArraySet()
categories.add(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION)
val peerAddress = chatRoom.peerAddress.asStringUriOnly()
val localAddress = chatRoom.localAddress.asStringUriOnly()
val personsList = arrayListOf<Person>()
var subject = ""
var icon: IconCompat
if (chatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) {
val contact =
coreContext.contactsManager.findContactByAddress(chatRoom.peerAddress)
if (contact != null) {
personsList.add(contact.getPerson())
}
subject = contact?.fullName ?: LinphoneUtils.getDisplayName(chatRoom.peerAddress)
icon = contact?.getPerson()?.icon ?: IconCompat.createWithResource(context, R.drawable.avatar)
} else {
for (participant in chatRoom.participants) {
val contact =
coreContext.contactsManager.findContactByAddress(participant.address)
if (contact != null) {
personsList.add(contact.getPerson())
}
}
subject = chatRoom.subject
icon = IconCompat.createWithResource(context, R.drawable.chat_group_avatar)
}
val persons = arrayOfNulls<Person>(personsList.size)
personsList.toArray(persons)
val args = Bundle()
args.putString("RemoteSipUri", peerAddress)
args.putString("LocalSipUri", localAddress)
val intent = Intent(Intent.ACTION_MAIN)
intent.setClass(context, MainActivity::class.java)
intent.putExtra("Chat", true)
intent.putExtra("RemoteSipUri", peerAddress)
intent.putExtra("LocalSipUri", localAddress)
return ShortcutInfoCompat.Builder(context, "$localAddress#$peerAddress")
.setShortLabel(subject)
.setIcon(icon)
.setPersons(persons)
.setCategories(categories)
.setIntent(intent)
.build().toShortcutInfo()
} catch (e: Exception) {
Log.e("[Shortcuts Helper] ShortcutInfo.Builder exception: $e")
}
return null
}
fun removeShortcuts(context: Context) { fun removeShortcuts(context: Context) {
Log.w("[Shortcut Helper] Removing all contacts shortcuts") Log.w("[Shortcut Helper] Removing all contacts shortcuts")
val shortcutManager = context.getSystemService(ShortcutManager::class.java) val shortcutManager = context.getSystemService(ShortcutManager::class.java)

View file

@ -80,6 +80,13 @@
linphone:listener="@{viewModel.downloadedImagesPublicListener}" linphone:listener="@{viewModel.downloadedImagesPublicListener}"
linphone:checked="@={viewModel.downloadedImagesPublic}"/> linphone:checked="@={viewModel.downloadedImagesPublic}"/>
<include
layout="@layout/settings_widget_switch"
linphone:title="@{@string/chat_settings_launcher_shortcuts_title}"
linphone:subtitle="@{@string/chat_settings_launcher_shortcuts_summary}"
linphone:listener="@{viewModel.launcherShortcutsListener}"
linphone:checked="@={viewModel.launcherShortcuts}"/>
<include <include
layout="@layout/settings_widget_switch" layout="@layout/settings_widget_switch"
linphone:title="@{@string/chat_settings_hide_empty_rooms_title}" linphone:title="@{@string/chat_settings_hide_empty_rooms_title}"

View file

@ -44,6 +44,10 @@
android:id="@+id/chatsDeepLink" android:id="@+id/chatsDeepLink"
app:uri="linphone-android://chat/" app:uri="linphone-android://chat/"
android:autoVerify="true" /> android:autoVerify="true" />
<deepLink
android:id="@+id/chatRoomDeepLink"
app:uri="linphone-android://chat-room/{LocalSipUri}/{RemoteSipUri}"
android:autoVerify="true" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/masterContactsFragment" android:id="@+id/masterContactsFragment"

View file

@ -347,6 +347,8 @@
<string name="chat_settings_file_sharing_url_summary">Do not edit unless you know what you are doing!</string> <string name="chat_settings_file_sharing_url_summary">Do not edit unless you know what you are doing!</string>
<string name="chat_settings_downloaded_images_public_title">Make downloaded images visible in native gallery</string> <string name="chat_settings_downloaded_images_public_title">Make downloaded images visible in native gallery</string>
<string name="chat_settings_downloaded_images_public_summary">Images in ephemeral messages won\'t be</string> <string name="chat_settings_downloaded_images_public_summary">Images in ephemeral messages won\'t be</string>
<string name="chat_settings_launcher_shortcuts_title">Create shortcuts to chat rooms in launcher</string>
<string name="chat_settings_launcher_shortcuts_summary">Will be replaced by contacts shortcuts if enabled</string>
<string name="chat_settings_hide_empty_rooms_title">Hide empty chat rooms</string> <string name="chat_settings_hide_empty_rooms_title">Hide empty chat rooms</string>
<string name="chat_settings_hide_empty_rooms_summary"></string> <string name="chat_settings_hide_empty_rooms_summary"></string>
<string name="chat_settings_hide_rooms_removed_proxies_title">Hide chat rooms from removed proxy configs</string> <string name="chat_settings_hide_rooms_removed_proxies_title">Hide chat rooms from removed proxy configs</string>
@ -371,8 +373,8 @@
<string name="contacts_settings_native_presence_summary">Inserting information shortcuts from the &appName; contact into native Android contacts</string> <string name="contacts_settings_native_presence_summary">Inserting information shortcuts from the &appName; contact into native Android contacts</string>
<string name="contacts_settings_show_organization_title">Display contact organization</string> <string name="contacts_settings_show_organization_title">Display contact organization</string>
<string name="contacts_settings_show_organization_summary"></string> <string name="contacts_settings_show_organization_summary"></string>
<string name="contacts_settings_launcher_shortcuts_title">Create shortcuts in launcher</string> <string name="contacts_settings_launcher_shortcuts_title">Create shortcuts to contacts in launcher</string>
<string name="contacts_settings_launcher_shortcuts_summary"></string> <string name="contacts_settings_launcher_shortcuts_summary">Will replace chat room shortcuts if any</string>
<!-- Advanced settings --> <!-- Advanced settings -->
<string name="advanced_settings_debug_mode_title">Debug logs</string> <string name="advanced_settings_debug_mode_title">Debug logs</string>