diff --git a/app/src/main/java/org/linphone/activities/main/settings/fragments/ContactsSettingsFragment.kt b/app/src/main/java/org/linphone/activities/main/settings/fragments/ContactsSettingsFragment.kt index 0968ed7b9..9cb313035 100644 --- a/app/src/main/java/org/linphone/activities/main/settings/fragments/ContactsSettingsFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/settings/fragments/ContactsSettingsFragment.kt @@ -19,6 +19,7 @@ */ package org.linphone.activities.main.settings.fragments +import android.content.pm.PackageManager import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -27,11 +28,14 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R import org.linphone.activities.main.settings.viewmodels.ContactsSettingsViewModel import org.linphone.compatibility.Compatibility +import org.linphone.core.tools.Log import org.linphone.databinding.SettingsContactsFragmentBinding +import org.linphone.utils.PermissionHelper class ContactsSettingsFragment : Fragment() { private lateinit var binding: SettingsContactsFragmentBinding @@ -69,5 +73,52 @@ class ContactsSettingsFragment : Fragment() { } } }) + + viewModel.askWriteContactsPermissionForPresenceStorageEvent.observe(viewLifecycleOwner, Observer { + it.consume { + Log.i("[Contacts Settings] Asking for WRITE_CONTACTS permission to be able to store presence") + requestPermissions(arrayOf(android.Manifest.permission.WRITE_CONTACTS), 1) + } + }) + + if (!PermissionHelper.required(requireContext()).hasReadContactsPermission()) { + Log.i("[Contacts Settings] Asking for READ_CONTACTS permission") + requestPermissions(arrayOf(android.Manifest.permission.READ_CONTACTS), 0) + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + when (requestCode) { + 0 -> { + val granted = grantResults[0] == PackageManager.PERMISSION_GRANTED + if (granted) { + Log.i("[Contacts Settings] READ_CONTACTS permission granted") + viewModel.readContactsPermissionGranted.value = true + coreContext.contactsManager.fetchContactsAsync() + } else { + Log.w("[Contacts Settings] READ_CONTACTS permission denied") + } + } + 1 -> { + val granted = grantResults[0] == PackageManager.PERMISSION_GRANTED + if (granted) { + Log.i("[Contacts Settings] WRITE_CONTACTS permission granted") + corePreferences.storePresenceInNativeContact = true + + if (coreContext.core.isFriendListSubscriptionEnabled) { + Log.i("[Contacts Settings] Updating subscription") + for (list in coreContext.core.friendsLists) { + list.updateSubscriptions() + } + } + } else { + Log.w("[Contacts Settings] WRITE_CONTACTS permission denied") + } + } + } } } diff --git a/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ContactsSettingsViewModel.kt b/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ContactsSettingsViewModel.kt index 38c271c6c..be6a160ae 100644 --- a/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ContactsSettingsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ContactsSettingsViewModel.kt @@ -22,8 +22,15 @@ package org.linphone.activities.main.settings.viewmodels import androidx.lifecycle.MutableLiveData import org.linphone.activities.main.settings.SettingListenerStub import org.linphone.utils.Event +import org.linphone.utils.PermissionHelper class ContactsSettingsViewModel : GenericSettingsViewModel() { + val askWriteContactsPermissionForPresenceStorageEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + + val readContactsPermissionGranted = MutableLiveData() + val friendListSubscribeListener = object : SettingListenerStub() { override fun onBoolValueChanged(newValue: Boolean) { core.enableFriendListSubscription(newValue) @@ -33,7 +40,15 @@ class ContactsSettingsViewModel : GenericSettingsViewModel() { val nativePresenceListener = object : SettingListenerStub() { override fun onBoolValueChanged(newValue: Boolean) { - prefs.storePresenceInNativeContact = newValue + if (newValue) { + if (PermissionHelper.get().hasWriteContactsPermission()) { + prefs.storePresenceInNativeContact = newValue + } else { + askWriteContactsPermissionForPresenceStorageEvent.value = Event(true) + } + } else { + prefs.storePresenceInNativeContact = newValue + } } } val nativePresence = MutableLiveData() @@ -55,6 +70,8 @@ class ContactsSettingsViewModel : GenericSettingsViewModel() { val launcherShortcutsEvent = MutableLiveData>() init { + readContactsPermissionGranted.value = PermissionHelper.get().hasReadContactsPermission() + friendListSubscribe.value = core.isFriendListSubscriptionEnabled nativePresence.value = prefs.storePresenceInNativeContact showOrganization.value = prefs.displayOrganization diff --git a/app/src/main/java/org/linphone/contact/ContactsManager.kt b/app/src/main/java/org/linphone/contact/ContactsManager.kt index 6b58e2a82..1438a5fc4 100644 --- a/app/src/main/java/org/linphone/contact/ContactsManager.kt +++ b/app/src/main/java/org/linphone/contact/ContactsManager.kt @@ -287,7 +287,7 @@ class ContactsManager(private val context: Context) { listener.onContactUpdated(contact) } - if (corePreferences.storePresenceInNativeContact) { + if (corePreferences.storePresenceInNativeContact && PermissionHelper.get().hasWriteContactsPermission()) { if (contact is NativeContact) { for (phoneNumber in contact.phoneNumbers) { val sipAddress = contact.getContactForPhoneNumberOrAddress(phoneNumber) diff --git a/app/src/main/java/org/linphone/contact/NativeContactEditor.kt b/app/src/main/java/org/linphone/contact/NativeContactEditor.kt index cd96de763..193c70c87 100644 --- a/app/src/main/java/org/linphone/contact/NativeContactEditor.kt +++ b/app/src/main/java/org/linphone/contact/NativeContactEditor.kt @@ -235,10 +235,11 @@ class NativeContactEditor( sipAddress.currentValue.isEmpty() -> { // New address to add addCount++ + val address = sipAddress.newValue.value.orEmpty() if (useLinphoneSyncAccount) { - addAddress(sipAddress.newValue.value.orEmpty()) + addAddress(address, address) } else { - addSipAddress(sipAddress.newValue.value.orEmpty()) + addSipAddress(address) } } sipAddress.toRemove.value == true -> { @@ -268,7 +269,7 @@ class NativeContactEditor( Log.i("[Native Contact Editor] Trying to add presence information to contact as ${if (useLinphoneSyncAccount) "phone number" else "SIP address"}") if (useLinphoneSyncAccount) { - setPresencePhoneNumber(phoneNumber) + setPresence(sipAddress, phoneNumber) } else { setPresenceSipAddress(sipAddress) } @@ -359,7 +360,7 @@ class NativeContactEditor( addChanges(delete) } - private fun addAddress(address: String) { + private fun addAddress(address: String, detail: String) { val insert = ContentProviderOperation.newInsert(contactUri) .withValue(ContactsContract.Data.RAW_CONTACT_ID, linphoneRawId) .withValue( @@ -368,7 +369,7 @@ class NativeContactEditor( ) .withValue("data1", address) // value .withValue("data2", AppUtils.getString(R.string.app_name)) // summary - .withValue("data3", address) // detail + .withValue("data3", detail) // detail .build() addChanges(insert) } @@ -422,13 +423,13 @@ class NativeContactEditor( addChanges(delete) } - private fun setPresencePhoneNumber(phoneNumber: String) { + private fun setPresence(sipAddress: String, phoneNumber: String) { val contentResolver = coreContext.context.contentResolver val cursor = contentResolver.query( ContactsContract.Data.CONTENT_URI, arrayOf("data1"), - "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? AND data1 = ?", - arrayOf(linphoneRawId, AppUtils.getString(R.string.linphone_address_mime_type), phoneNumber), + "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? AND data1 = ? AND data3 = ?", + arrayOf(linphoneRawId, AppUtils.getString(R.string.linphone_address_mime_type), sipAddress, phoneNumber), null ) val count = cursor?.count ?: 0 @@ -436,7 +437,7 @@ class NativeContactEditor( if (count == 0) { Log.i("[Native Contact Editor] No existing presence information found for this phone number, let's add it") - addAddress(phoneNumber) + addAddress(sipAddress, phoneNumber) } else { Log.i("[Native Contact Editor] There is already an entry for this, skipping") } diff --git a/app/src/main/res/layout/settings_contacts_fragment.xml b/app/src/main/res/layout/settings_contacts_fragment.xml index 48f98b65a..9c1b6810b 100644 --- a/app/src/main/res/layout/settings_contacts_fragment.xml +++ b/app/src/main/res/layout/settings_contacts_fragment.xml @@ -69,28 +69,32 @@ linphone:title="@{@string/contacts_settings_friendlist_subscribe_title}" linphone:subtitle="@{@string/contacts_settings_friendlist_subscribe_summary}" linphone:listener="@{viewModel.friendListSubscribeListener}" - linphone:checked="@={viewModel.friendListSubscribe}"/> + linphone:checked="@={viewModel.friendListSubscribe}" + linphone:enabled="@{viewModel.readContactsPermissionGranted}"/> + linphone:checked="@={viewModel.nativePresence}" + linphone:enabled="@{viewModel.readContactsPermissionGranted && viewModel.friendListSubscribe}"/> + linphone:checked="@={viewModel.showOrganization}" + linphone:enabled="@{viewModel.readContactsPermissionGranted}"/> + linphone:checked="@={viewModel.launcherShortcuts}" + linphone:enabled="@{viewModel.readContactsPermissionGranted}"/>