Hide contact's devices & trust for third party accounts

This commit is contained in:
Sylvain Berfini 2024-04-24 11:38:06 +02:00
parent 1578e76700
commit 498b8435bf
19 changed files with 59 additions and 49 deletions

View file

@ -57,7 +57,7 @@ import org.linphone.ui.main.MainActivity
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener
import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
@ -139,7 +139,7 @@ class ContactsManager @UiThread constructor() {
@WorkerThread
override fun onDefaultAccountChanged(core: Core, account: Account?) {
Log.i("$TAG Default account changed, update all contact models showTrust value")
val showTrust = account?.isInSecureMode()
val showTrust = account?.isEndToEndEncryptionMandatory()
knownContactsAvatarsMap.forEach { (_, contactAvatarModel) ->
contactAvatarModel.showTrust.postValue(showTrust)
}
@ -741,7 +741,7 @@ fun Friend.getListOfSipAddressesAndPhoneNumbers(listener: ContactNumberOrAddress
// phone numbers are disabled is secure mode unless linked to a SIP address
val defaultAccount = LinphoneUtils.getDefaultAccount()
val enablePhoneNumbers = hasPresenceInfo || defaultAccount?.isInSecureMode() == false
val enablePhoneNumbers = hasPresenceInfo || defaultAccount?.isEndToEndEncryptionMandatory() == false
val address = presenceAddress ?: core.interpretUrl(
number.phoneNumber,
LinphoneUtils.applyInternationalPrefix(defaultAccount)

View file

@ -69,7 +69,7 @@ import org.linphone.core.MediaDirection
import org.linphone.core.tools.Log
import org.linphone.ui.call.CallActivity
import org.linphone.ui.main.MainActivity
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.FileUtils
import org.linphone.utils.LinphoneUtils
@ -1088,7 +1088,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val account = coreContext.core.accountList.find {
it.params.identityAddress?.asStringUriOnly() == notifiable.localIdentity
}
if (account != null && !account.isInSecureMode()) {
if (account != null && !account.isEndToEndEncryptionMandatory()) {
notificationBuilder.addAction(getReplyMessageAction(notifiable))
}
}

View file

@ -43,7 +43,7 @@ import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel
import org.linphone.ui.main.history.adapter.ContactsAndSuggestionsListAdapter
import org.linphone.ui.main.history.model.ContactOrSuggestionModel
import org.linphone.ui.main.history.viewmodel.StartCallViewModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.DialogUtils
import org.linphone.utils.LinphoneUtils
import org.linphone.utils.RecyclerViewHeaderDecoration
@ -224,7 +224,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() {
val numbersCount = friend.phoneNumbers.size
// Do not consider phone numbers if default account is in secure mode
val enablePhoneNumbers = core.defaultAccount?.isInSecureMode() != true
val enablePhoneNumbers = core.defaultAccount?.isEndToEndEncryptionMandatory() != true
if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) {
Log.i(

View file

@ -57,7 +57,7 @@ import org.linphone.ui.call.model.CallMediaEncryptionModel
import org.linphone.ui.call.model.CallStatsModel
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.history.model.NumpadModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.AudioUtils
import org.linphone.utils.Event
@ -743,13 +743,13 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
val sameDomain =
remote.domain == corePreferences.defaultDomain && remote.domain == account.params.domain
if (account.isInSecureMode() && sameDomain) {
if (account.isEndToEndEncryptionMandatory() && sameDomain) {
Log.i(
"$TAG Account is in secure mode & domain matches, creating a E2E conversation"
)
params.backend = ChatRoom.Backend.FlexisipChat
params.isEncryptionEnabled = true
} else if (!account.isInSecureMode()) {
} else if (!account.isEndToEndEncryptionMandatory()) {
if (LinphoneUtils.isEndToEndEncryptedChatAvailable(core)) {
Log.i(
"$TAG Account is in interop mode but LIME is available, creating a E2E conversation"

View file

@ -52,7 +52,7 @@ import org.linphone.core.Player
import org.linphone.core.PlayerListener
import org.linphone.core.tools.Log
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.AudioUtils
import org.linphone.utils.Event
@ -100,7 +100,7 @@ class MessageModel @WorkerThread constructor(
val time = TimestampUtils.toString(timestamp)
val chatRoomIsReadOnly = chatMessage.chatRoom.isReadOnly ||
(!chatMessage.chatRoom.hasCapability(ChatRoom.Capabilities.Encrypted.toInt()) && LinphoneUtils.getDefaultAccount()?.isInSecureMode() == true)
(!chatMessage.chatRoom.hasCapability(ChatRoom.Capabilities.Encrypted.toInt()) && LinphoneUtils.getDefaultAccount()?.isEndToEndEncryptionMandatory() == true)
val groupedWithNextMessage = MutableLiveData<Boolean>()

View file

@ -40,7 +40,7 @@ import org.linphone.core.tools.Log
import org.linphone.ui.main.chat.model.EventLogModel
import org.linphone.ui.main.chat.model.MessageModel
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
import org.linphone.utils.ImageUtils
@ -510,7 +510,7 @@ class ConversationViewModel @UiThread constructor() : AbstractConversationViewMo
if (!chatRoom.hasCapability(ChatRoom.Capabilities.Encrypted.toInt())) {
val account = LinphoneUtils.getDefaultAccount()
if (account?.isInSecureMode() == true) {
if (account?.isEndToEndEncryptionMandatory() == true) {
Log.w(
"$TAG Conversation with subject [${chatRoom.subject}] has been disabled because it isn't encrypted and default account is in secure mode"
)

View file

@ -32,7 +32,7 @@ import org.linphone.core.Core
import org.linphone.core.CoreListenerStub
import org.linphone.core.tools.Log
import org.linphone.ui.main.chat.model.ConversationModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.ui.main.viewmodel.AbstractMainViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
@ -147,7 +147,7 @@ class ConversationsListViewModel @UiThread constructor() : AbstractMainViewModel
val account = LinphoneUtils.getDefaultAccount()
val chatRooms = account?.chatRooms ?: coreContext.core.chatRooms
for (chatRoom in chatRooms) {
val disabledBecauseNotSecured = account?.isInSecureMode() == true && !chatRoom.hasCapability(
val disabledBecauseNotSecured = account?.isEndToEndEncryptionMandatory() == true && !chatRoom.hasCapability(
Capabilities.Encrypted.toInt()
)
if (filter.isEmpty()) {

View file

@ -31,7 +31,7 @@ import org.linphone.core.ChatRoom
import org.linphone.core.ChatRoomListenerStub
import org.linphone.core.ChatRoomParams
import org.linphone.core.tools.Log
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.ui.main.viewmodel.AddressSelectionViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
@ -189,11 +189,11 @@ class StartConversationViewModel @UiThread constructor() : AddressSelectionViewM
params.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default
val sameDomain = remote.domain == corePreferences.defaultDomain && remote.domain == account.params.domain
if (account.isInSecureMode() && sameDomain) {
if (account.isEndToEndEncryptionMandatory() && sameDomain) {
Log.i("$TAG Account is in secure mode & domain matches, creating a E2E conversation")
params.backend = ChatRoom.Backend.FlexisipChat
params.isEncryptionEnabled = true
} else if (!account.isInSecureMode()) {
} else if (!account.isEndToEndEncryptionMandatory()) {
if (LinphoneUtils.isEndToEndEncryptedChatAvailable(core)) {
Log.i(
"$TAG Account is in interop mode but LIME is available, creating a E2E conversation"

View file

@ -31,7 +31,7 @@ import org.linphone.core.ConsolidatedPresence
import org.linphone.core.Friend
import org.linphone.core.FriendListenerStub
import org.linphone.core.tools.Log
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.TimestampUtils
@ -87,7 +87,7 @@ class ContactAvatarModel @WorkerThread constructor(val friend: Friend, val addre
isFavourite.postValue(friend.starred)
initials.postValue(AppUtils.getInitials(friend.name.orEmpty()))
showTrust.postValue(coreContext.core.defaultAccount?.isInSecureMode())
showTrust.postValue(coreContext.core.defaultAccount?.isEndToEndEncryptionMandatory())
images.postValue(arrayListOf(getAvatarUri(friend).toString()))
name.postValue(friend.name)

View file

@ -46,7 +46,7 @@ import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.contacts.model.ContactDeviceModel
import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener
import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
import org.linphone.utils.FileUtils
@ -80,6 +80,8 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
val expandNumbersAndAddresses = MutableLiveData<Boolean>()
val showContactTrustAndDevices = MutableLiveData<Boolean>()
val expandDevicesTrust = MutableLiveData<Boolean>()
val contactFoundEvent = MutableLiveData<Event<Boolean>>()
@ -239,8 +241,14 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
core.addListener(coreListener)
chatDisabled.postValue(corePreferences.disableChat)
videoCallDisabled.postValue(!core.isVideoEnabled)
// Only show contact's devices for Linphone accounts
showContactTrustAndDevices.postValue(
LinphoneUtils.getDefaultAccount()?.params?.domain == corePreferences.defaultDomain
)
// Only expand contacts' devices & trust by default if in E2E encrypted mode
expandDevicesTrust.postValue(
LinphoneUtils.getDefaultAccount()?.isInSecureMode() == true
LinphoneUtils.getDefaultAccount()?.isEndToEndEncryptionMandatory() == true
)
coreContext.contactsManager.addListener(contactsListener)
}
@ -417,7 +425,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
val numbersCount = friend.phoneNumbers.size
// Do not consider phone numbers if default account is in secure mode
val enablePhoneNumbers = core.defaultAccount?.isInSecureMode() != true
val enablePhoneNumbers = core.defaultAccount?.isEndToEndEncryptionMandatory() != true
if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) {
Log.i(
@ -454,7 +462,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
val numbersCount = friend.phoneNumbers.size
// Do not consider phone numbers if default account is in secure mode
val enablePhoneNumbers = core.defaultAccount?.isInSecureMode() != true
val enablePhoneNumbers = core.defaultAccount?.isEndToEndEncryptionMandatory() != true
if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) {
Log.i(
@ -491,7 +499,7 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
val numbersCount = friend.phoneNumbers.size
// Do not consider phone numbers if default account is in secure mode
val enablePhoneNumbers = core.defaultAccount?.isInSecureMode() != true
val enablePhoneNumbers = core.defaultAccount?.isEndToEndEncryptionMandatory() != true
if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) {
Log.i(
@ -537,13 +545,13 @@ class ContactViewModel @UiThread constructor() : ViewModel() {
params.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default
val sameDomain = remote.domain == corePreferences.defaultDomain && remote.domain == account.params.domain
if (account.isInSecureMode() && sameDomain) {
if (account.isEndToEndEncryptionMandatory() && sameDomain) {
Log.i(
"$TAG Account is in secure mode & domain matches, creating a E2E conversation"
)
params.backend = ChatRoom.Backend.FlexisipChat
params.isEncryptionEnabled = true
} else if (!account.isInSecureMode()) {
} else if (!account.isEndToEndEncryptionMandatory()) {
if (LinphoneUtils.isEndToEndEncryptedChatAvailable(core)) {
Log.i(
"$TAG Account is in interop mode but LIME is available, creating a E2E conversation"

View file

@ -37,7 +37,7 @@ import org.linphone.core.MagicSearchListenerStub
import org.linphone.core.SearchResult
import org.linphone.core.tools.Log
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.ui.main.viewmodel.AbstractMainViewModel
import org.linphone.utils.Event
import org.linphone.utils.FileUtils
@ -161,9 +161,9 @@ class ContactsListViewModel @UiThread constructor() : AbstractMainViewModel() {
private fun updateDomainFilter() {
val defaultAccount = coreContext.core.defaultAccount
isDefaultAccountLinphone.postValue(
defaultAccount?.isInSecureMode() == true && defaultAccount.params.domain == corePreferences.defaultDomain
defaultAccount?.isEndToEndEncryptionMandatory() == true && defaultAccount.params.domain == corePreferences.defaultDomain
)
domainFilter = if (defaultAccount?.isInSecureMode() == true) {
domainFilter = if (defaultAccount?.isEndToEndEncryptionMandatory() == true) {
corePreferences.defaultDomain
} else {
"*"

View file

@ -37,7 +37,7 @@ import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel
import org.linphone.ui.main.history.adapter.ContactsAndSuggestionsListAdapter
import org.linphone.ui.main.history.model.ContactOrSuggestionModel
import org.linphone.ui.main.model.SelectedAddressModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.ui.main.viewmodel.AddressSelectionViewModel
import org.linphone.utils.DialogUtils
import org.linphone.utils.LinphoneUtils
@ -162,7 +162,7 @@ abstract class GenericAddressPickerFragment : GenericFragment() {
val numbersCount = friend.phoneNumbers.size
// Do not consider phone numbers if default account is in secure mode
val enablePhoneNumbers = core.defaultAccount?.isInSecureMode() != true
val enablePhoneNumbers = core.defaultAccount?.isEndToEndEncryptionMandatory() != true
if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) {
val address = friend.addresses.first()

View file

@ -33,7 +33,7 @@ import org.linphone.core.ChatRoomParams
import org.linphone.core.tools.Log
import org.linphone.ui.main.history.model.CallLogHistoryModel
import org.linphone.ui.main.history.model.CallLogModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.Event
import org.linphone.utils.LinphoneUtils
@ -187,13 +187,13 @@ class HistoryViewModel @UiThread constructor() : ViewModel() {
params.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default
val sameDomain = remote.domain == corePreferences.defaultDomain && remote.domain == account.params.domain
if (account.isInSecureMode() && sameDomain) {
if (account.isEndToEndEncryptionMandatory() && sameDomain) {
Log.i(
"$TAG Account is in secure mode & domain matches, creating a E2E conversation"
)
params.backend = ChatRoom.Backend.FlexisipChat
params.isEncryptionEnabled = true
} else if (!account.isInSecureMode()) {
} else if (!account.isEndToEndEncryptionMandatory()) {
if (LinphoneUtils.isEndToEndEncryptedChatAvailable(core)) {
Log.i(
"$TAG Account is in interop mode but LIME is available, creating a E2E conversation"

View file

@ -114,7 +114,7 @@ class AccountModel @WorkerThread constructor(
coreContext.core.addListener(coreListener)
trust.postValue(SecurityLevel.EndToEndEncryptedAndVerified)
showTrust.postValue(account.isInSecureMode())
showTrust.postValue(account.isEndToEndEncryptionMandatory())
presenceStatus.postValue(ConsolidatedPresence.Offline)
update()
@ -233,7 +233,7 @@ class AccountModel @WorkerThread constructor(
}
}
fun Account.isInSecureMode(): Boolean {
fun Account.isEndToEndEncryptionMandatory(): Boolean {
// TODO FIXME: use real API when available
return params.identityAddress?.domain == "sip.linphone.org"
}

View file

@ -29,7 +29,7 @@ import org.linphone.core.DialPlan
import org.linphone.core.Factory
import org.linphone.core.tools.Log
import org.linphone.ui.main.model.AccountModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.ui.main.settings.model.AccountDeviceModel
import org.linphone.utils.Event
@ -111,7 +111,7 @@ class AccountProfileViewModel @UiThread constructor() : ViewModel() {
Log.i("$TAG Found matching account [$found]")
account = found
accountModel.postValue(AccountModel(account))
isCurrentlySelectedModeSecure.postValue(account.isInSecureMode())
isCurrentlySelectedModeSecure.postValue(account.isEndToEndEncryptionMandatory())
registerEnabled.postValue(account.params.isRegisterEnabled)
pushNotificationsEnabled.postValue(account.params.pushNotificationAllowed)

View file

@ -29,7 +29,7 @@ import org.linphone.core.Account
import org.linphone.core.NatPolicy
import org.linphone.core.TransportType
import org.linphone.core.tools.Log
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.Event
class AccountSettingsViewModel @UiThread constructor() : ViewModel() {
@ -86,7 +86,7 @@ class AccountSettingsViewModel @UiThread constructor() : ViewModel() {
Log.i("$TAG Found matching account [$found]")
account = found
isAccountInSecureMode.postValue(account.isInSecureMode())
isAccountInSecureMode.postValue(account.isEndToEndEncryptionMandatory())
val params = account.params

View file

@ -34,7 +34,7 @@ import org.linphone.core.SearchResult
import org.linphone.mediastream.Log
import org.linphone.ui.main.history.model.ContactOrSuggestionModel
import org.linphone.ui.main.model.SelectedAddressModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccountChangedViewModel() {
@ -86,7 +86,7 @@ abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccoun
coreContext.postOnCoreThread { core ->
val defaultAccount = core.defaultAccount
limitSearchToLinphoneAccounts = defaultAccount?.isInSecureMode() ?: false
limitSearchToLinphoneAccounts = defaultAccount?.isEndToEndEncryptionMandatory() ?: false
coreContext.contactsManager.addListener(contactsListener)
magicSearch = core.createMagicSearch()

View file

@ -38,7 +38,7 @@ import org.linphone.core.ChatRoom
import org.linphone.core.tools.Log
import org.linphone.mediastream.Version
import org.linphone.ui.main.MainActivity
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
class ShortcutUtils {
companion object {
@ -67,7 +67,7 @@ class ShortcutUtils {
var count = 0
for (chatRoom in defaultAccount.chatRooms) {
if (defaultAccount.isInSecureMode() && !chatRoom.currentParams.isEncryptionEnabled) {
if (defaultAccount.isEndToEndEncryptionMandatory() && !chatRoom.currentParams.isEncryptionEnabled) {
Log.w(
"$TAG Account is in secure mode, skipping not encrypted conversation [${LinphoneUtils.getChatRoomId(
chatRoom

View file

@ -101,7 +101,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="trusted_devices_count, trusted_devices_progress, devices, trusted_devices_progress_label"
android:visibility="@{viewModel.expandDevicesTrust &amp;&amp; viewModel.devices.size() > 0 ? View.VISIBLE : View.GONE}" />
android:visibility="@{viewModel.showContactTrustAndDevices ? (viewModel.expandDevicesTrust &amp;&amp; viewModel.devices.size() > 0 ? View.VISIBLE : View.GONE) : View.GONE, default=gone}" />
<include
android:id="@+id/avatar"
@ -331,8 +331,8 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/section_header_style"
android:onClick="@{() -> viewModel.displayTrustDialog()}"
android:id="@+id/trust_label"
android:onClick="@{() -> viewModel.displayTrustDialog()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="26dp"
@ -342,13 +342,14 @@
android:drawableEnd="@drawable/question"
android:drawableTint="?attr/color_main2_600"
android:drawablePadding="8dp"
android:visibility="@{viewModel.showContactTrustAndDevices ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/info_background"/>
<androidx.appcompat.widget.AppCompatTextView
style="@style/section_header_style"
android:onClick="@{() -> viewModel.toggleDevicesTrustExpand()}"
android:id="@+id/trust_toggle"
android:onClick="@{() -> viewModel.toggleDevicesTrustExpand()}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="26dp"
@ -356,6 +357,7 @@
android:padding="5dp"
android:drawableEnd="@{viewModel.expandDevicesTrust ? @drawable/caret_up : @drawable/caret_down, default=@drawable/caret_up}"
android:drawableTint="?attr/color_main2_600"
android:visibility="@{viewModel.showContactTrustAndDevices ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintStart_toEndOf="@id/trust_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/info_background"/>