From 0d31bfe3c3f0bb7fec18352d21f6e46b80f725cf Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 21 Nov 2023 14:21:19 +0100 Subject: [PATCH] Updated layout for default/interop mode selection + added logs to contacts manager --- .../org/linphone/contacts/ContactsManager.kt | 38 +++++++++++--- .../assistant/fragment/ProfileModeFragment.kt | 7 +++ .../viewmodel/AccountLoginViewModel.kt | 14 ++++++ .../res/drawable/profile_interop_logo.xml | 41 +++++++++++++++ .../main/res/drawable/profile_secure_logo.xml | 35 +++++++++++++ ..._squircle_white_background_blue_border.xml | 6 +++ ...quircle_white_background_orange_border.xml | 6 +++ .../account_profile_secure_mode_fragment.xml | 50 +++++++++++++++---- .../layout/assistant_secure_mode_fragment.xml | 22 ++++++-- app/src/main/res/values/strings.xml | 8 +-- 10 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 app/src/main/res/drawable/profile_interop_logo.xml create mode 100644 app/src/main/res/drawable/profile_secure_logo.xml create mode 100644 app/src/main/res/drawable/shape_squircle_white_background_blue_border.xml create mode 100644 app/src/main/res/drawable/shape_squircle_white_background_orange_border.xml diff --git a/app/src/main/java/org/linphone/contacts/ContactsManager.kt b/app/src/main/java/org/linphone/contacts/ContactsManager.kt index 818feb683..12a786b93 100644 --- a/app/src/main/java/org/linphone/contacts/ContactsManager.kt +++ b/app/src/main/java/org/linphone/contacts/ContactsManager.kt @@ -66,7 +66,7 @@ class ContactsManager @UiThread constructor() { @WorkerThread override fun onPresenceReceived(list: FriendList, friends: Array) { Log.i( - "$TAG Presence received for list [${list.displayName}] and [${friends.size}] friends" + "$TAG Presence received for list [${list.displayName}] and [${friends.size}] friends, cleaning avatars map" ) avatarsMap.values.forEach(ContactAvatarModel::destroy) @@ -127,6 +127,7 @@ class ContactsManager @UiThread constructor() { @WorkerThread fun onNativeContactsLoaded() { nativeContactsLoaded = true + Log.i("$TAG Native contacts have been loaded, cleaning avatars map") avatarsMap.values.forEach(ContactAvatarModel::destroy) avatarsMap.clear() @@ -143,10 +144,15 @@ class ContactsManager @UiThread constructor() { @WorkerThread fun findContactById(id: String): Friend? { + Log.i("$TAG Looking for a friend with ref key [$id]") for (friendList in coreContext.core.friendsLists) { val found = friendList.findFriendByRefKey(id) - if (found != null) return found + if (found != null) { + Log.i("$TAG Found friend [${found.name}] matching ref key [$id]") + return found + } } + Log.i("$TAG No friend matching ref key [$id] has been found") return null } @@ -156,7 +162,7 @@ class ContactsManager @UiThread constructor() { clonedAddress.clean() val sipUri = clonedAddress.asStringUriOnly() - Log.d("$TAG Looking for friend with SIP URI [$sipUri]") + Log.i("$TAG Looking for friend with SIP URI [$sipUri]") val username = clonedAddress.username val found = coreContext.core.findFriend(clonedAddress) return if (found != null) { @@ -194,6 +200,7 @@ class ContactsManager @UiThread constructor() { @WorkerThread fun getContactAvatarModelForAddress(address: Address?): ContactAvatarModel { if (address == null) { + Log.w("$TAG Address is null, generic model will be used") val fakeFriend = coreContext.core.createFriend() return ContactAvatarModel(fakeFriend) } @@ -203,22 +210,29 @@ class ContactsManager @UiThread constructor() { val key = clone.asStringUriOnly() val foundInMap = if (avatarsMap.keys.contains(key)) avatarsMap[key] else null - if (foundInMap != null) return foundInMap + if (foundInMap != null) { + Log.i("$TAG Avatar model found in map for SIP URI [$key]") + return foundInMap + } val localAccount = coreContext.core.accountList.find { it.params.identityAddress?.weakEqual(clone) == true } val avatar = if (localAccount != null) { + Log.i("$TAG [$key] SIP URI matches one of the local account") val fakeFriend = coreContext.core.createFriend() fakeFriend.address = clone fakeFriend.name = LinphoneUtils.getDisplayName(localAccount.params.identityAddress) fakeFriend.photo = localAccount.params.pictureUri ContactAvatarModel(fakeFriend) } else { + Log.i("$TAG Looking for friend matching SIP URI [$key]") val friend = coreContext.contactsManager.findContactByAddress(clone) if (friend != null) { + Log.i("$TAG Matching friend [${friend.name}] found for SIP URI [$key]") ContactAvatarModel(friend) } else { + Log.i("$TAG No matching friend found for SIP URI [$key]...") val fakeFriend = coreContext.core.createFriend() fakeFriend.name = LinphoneUtils.getDisplayName(address) fakeFriend.address = clone @@ -234,20 +248,28 @@ class ContactsManager @UiThread constructor() { @WorkerThread fun getContactAvatarModelForFriend(friend: Friend?): ContactAvatarModel { if (friend == null) { + Log.w("$TAG Friend is null, using generic avatar model") val fakeFriend = coreContext.core.createFriend() return ContactAvatarModel(fakeFriend) } val address = friend.address ?: friend.addresses.firstOrNull() ?: return ContactAvatarModel(friend) + Log.i( + "$TAG Looking for avatar model for friend [${friend.name}] using SIP URI [${address.asStringUriOnly()}]" + ) val clone = address.clone() clone.clean() val key = clone.asStringUriOnly() val foundInMap = if (avatarsMap.keys.contains(key)) avatarsMap[key] else null - if (foundInMap != null) return foundInMap + if (foundInMap != null) { + Log.i("$TAG Found avatar model in map using SIP URI [$key]") + return foundInMap + } + Log.w("$TAG Avatar model not found in map with SIP URI [$key]") val avatar = ContactAvatarModel(friend) avatarsMap[key] = avatar @@ -291,7 +313,7 @@ class ContactsManager @UiThread constructor() { @WorkerThread fun findNativeContact(address: String, searchAsPhoneNumber: Boolean, number: String = ""): Friend? { if (nativeContactsLoaded) { - Log.d( + Log.i( "$TAG Native contacts already loaded, no need to search further, no native contact matches address [$address]" ) return null @@ -303,7 +325,7 @@ class ContactsManager @UiThread constructor() { Manifest.permission.READ_CONTACTS ) == PackageManager.PERMISSION_GRANTED ) { - Log.d( + Log.i( "$TAG Looking for native contact with address [$address] ${if (searchAsPhoneNumber) "or phone number [$number]" else ""}" ) @@ -376,7 +398,7 @@ class ContactsManager @UiThread constructor() { friend.done() - Log.d("$TAG Found native contact [${friend.name}] with address [$address]") + Log.i("$TAG Found native contact [${friend.name}] with address [$address]") cursor.close() return friend } diff --git a/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt b/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt index fc3ab2afa..3c30410c9 100644 --- a/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt +++ b/app/src/main/java/org/linphone/ui/assistant/fragment/ProfileModeFragment.kt @@ -26,7 +26,10 @@ import android.view.ViewGroup import androidx.annotation.UiThread import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController +import androidx.navigation.navGraphViewModels +import org.linphone.R import org.linphone.databinding.AssistantSecureModeFragmentBinding +import org.linphone.ui.assistant.viewmodel.AccountLoginViewModel import org.linphone.utils.DialogUtils @UiThread @@ -37,6 +40,10 @@ class ProfileModeFragment : Fragment() { private lateinit var binding: AssistantSecureModeFragmentBinding + private val viewModel: AccountLoginViewModel by navGraphViewModels( + R.id.assistant_nav_graph + ) + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt b/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt index d616d323d..5ceaebd16 100644 --- a/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt +++ b/app/src/main/java/org/linphone/ui/assistant/viewmodel/AccountLoginViewModel.kt @@ -57,6 +57,8 @@ class AccountLoginViewModel @UiThread constructor() : ViewModel() { val registrationInProgress = MutableLiveData() + val isCurrentlySelectedModeSecure = MutableLiveData() + val accountLoggedInEvent: MutableLiveData> by lazy { MutableLiveData>() } @@ -129,6 +131,8 @@ class AccountLoginViewModel @UiThread constructor() : ViewModel() { loginEnabled.addSource(password) { loginEnabled.value = isLoginButtonEnabled() } + + isCurrentlySelectedModeSecure.value = true } @UiThread @@ -179,6 +183,16 @@ class AccountLoginViewModel @UiThread constructor() : ViewModel() { showPassword.value = showPassword.value == false } + @UiThread + fun switchToSecureMode() { + isCurrentlySelectedModeSecure.value = true + } + + @UiThread + fun switchToInteropMode() { + isCurrentlySelectedModeSecure.value = false + } + @UiThread private fun isLoginButtonEnabled(): Boolean { return username.value.orEmpty().isNotEmpty() && password.value.orEmpty().isNotEmpty() diff --git a/app/src/main/res/drawable/profile_interop_logo.xml b/app/src/main/res/drawable/profile_interop_logo.xml new file mode 100644 index 000000000..cc68607c4 --- /dev/null +++ b/app/src/main/res/drawable/profile_interop_logo.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/profile_secure_logo.xml b/app/src/main/res/drawable/profile_secure_logo.xml new file mode 100644 index 000000000..91485bda4 --- /dev/null +++ b/app/src/main/res/drawable/profile_secure_logo.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/shape_squircle_white_background_blue_border.xml b/app/src/main/res/drawable/shape_squircle_white_background_blue_border.xml new file mode 100644 index 000000000..b3ddaf751 --- /dev/null +++ b/app/src/main/res/drawable/shape_squircle_white_background_blue_border.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_squircle_white_background_orange_border.xml b/app/src/main/res/drawable/shape_squircle_white_background_orange_border.xml new file mode 100644 index 000000000..c124c16d6 --- /dev/null +++ b/app/src/main/res/drawable/shape_squircle_white_background_orange_border.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/account_profile_secure_mode_fragment.xml b/app/src/main/res/layout/account_profile_secure_mode_fragment.xml index 912f3b959..a1b1a076b 100644 --- a/app/src/main/res/layout/account_profile_secure_mode_fragment.xml +++ b/app/src/main/res/layout/account_profile_secure_mode_fragment.xml @@ -67,20 +67,30 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp"> + + @@ -99,19 +109,20 @@ @@ -122,7 +133,8 @@ android:layout_width="@dimen/avatar_list_cell_size" android:layout_height="@dimen/avatar_list_cell_size" android:layout_marginEnd="16dp" - android:layout_marginTop="20dp" + android:layout_marginTop="10dp" + android:visibility="gone" coilAvatarNoTrust="@{viewModel.accountModel}" app:strokeWidth="0dp" app:strokeColor="@color/transparent_color" @@ -139,6 +151,7 @@ android:background="@drawable/led_background" android:padding="@dimen/avatar_presence_badge_padding" android:src="@drawable/led_online" + android:visibility="gone" app:layout_constraintEnd_toEndOf="@id/image1" app:layout_constraintBottom_toBottomOf="@id/image1"/> @@ -149,6 +162,7 @@ android:layout_marginEnd="16dp" android:src="@drawable/arrow_right_fill" app:tint="@color/black" + android:visibility="gone" app:layout_constraintStart_toEndOf="@id/image1" app:layout_constraintEnd_toStartOf="@id/image2" app:layout_constraintTop_toTopOf="@id/image1" @@ -159,6 +173,7 @@ android:id="@+id/image2" android:layout_width="@dimen/avatar_list_cell_size" android:layout_height="@dimen/avatar_list_cell_size" + android:visibility="gone" coilAvatarNoTrust="@{viewModel.accountModel}" app:strokeWidth="@dimen/avatar_trust_border_width" app:strokeColor="@color/blue_info_500" @@ -172,6 +187,7 @@ android:layout_width="@dimen/avatar_presence_badge_size" android:layout_height="@dimen/avatar_presence_badge_size" android:src="@drawable/trusted" + android:visibility="gone" app:layout_constraintStart_toStartOf="@id/image2" app:layout_constraintBottom_toBottomOf="@id/image2"/> @@ -183,9 +199,20 @@ android:background="@drawable/led_background" android:padding="@dimen/avatar_presence_badge_padding" android:src="@drawable/led_online" + android:visibility="gone" app:layout_constraintEnd_toEndOf="@id/image2" app:layout_constraintBottom_toBottomOf="@id/image2"/> + + diff --git a/app/src/main/res/layout/assistant_secure_mode_fragment.xml b/app/src/main/res/layout/assistant_secure_mode_fragment.xml index 7d1ca3d3d..94e3b9aed 100644 --- a/app/src/main/res/layout/assistant_secure_mode_fragment.xml +++ b/app/src/main/res/layout/assistant_secure_mode_fragment.xml @@ -17,6 +17,9 @@ + @@ -121,7 +126,9 @@ android:paddingEnd="16dp" android:text="@string/manage_account_secure_mode_default_summary" android:textSize="14sp" - android:gravity="center" + android:gravity="start" + android:drawableEnd="@drawable/profile_secure_logo" + android:drawablePadding="10dp" app:layout_constraintTop_toBottomOf="@id/default_mode" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> @@ -132,7 +139,7 @@ android:layout_height="@dimen/avatar_list_cell_size" android:adjustViewBounds="true" android:layout_marginEnd="16dp" - android:layout_marginTop="20dp" + android:layout_marginTop="10dp" android:background="@drawable/shape_circle_light_blue_background" android:src="@drawable/user_circle" coilInitials="@{`JD`}" @@ -201,6 +208,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3a8cdebe1..ea292cbc0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -152,7 +152,7 @@ I understand Personalize your profile mode You may change that mode later - Default + End-to-end encrypted Interoperable Continue Push notifications not available, account creation disabled @@ -176,7 +176,7 @@ Wrong username or password Failed to login: error code is %i Grant permissions - Grant all + OK Do it later To fully enjoy &appName; we need you to grant us the following permissions : @@ -262,8 +262,8 @@ Apply Default mode Interoperable mode - End-to-end encryption of your communications - Allows to communicate with other SIP services, point to point encryption + This mode guarantee your data confidentiality. Our end-to-end encryption technology provide the highest level or security for your communications. + This mode allows you to enjoy all &appName; features while staying interoperable with any SIP service through point-to-point encryption. Remove Last connection: