Support HS admin option to disable E2EE for DMs

Fixes #1794
This commit is contained in:
Valere 2020-07-30 12:08:30 +02:00
parent b732ea6c69
commit 562cfce9e2
19 changed files with 138 additions and 16 deletions

View File

@ -53,5 +53,15 @@ data class WellKnown(
val identityServer: WellKnownBaseConfig? = null, val identityServer: WellKnownBaseConfig? = null,
@Json(name = "m.integrations") @Json(name = "m.integrations")
val integrations: JsonDict? = null val integrations: JsonDict? = null,
@Json(name = "im.vector.riot.e2ee")
val e2eAdminSetting: E2EWellKnownConfig? = null
)
@JsonClass(generateAdapter = true)
data class E2EWellKnownConfig(
@Json(name = "default")
val e2eDefault: Boolean = true
) )

View File

@ -32,7 +32,12 @@ data class HomeServerCapabilities(
/** /**
* Default identity server url, provided in Wellknown * Default identity server url, provided in Wellknown
*/ */
val defaultIdentityServerUrl: String? = null val defaultIdentityServerUrl: String? = null,
/**
* Option to allow homeserver admins to set the default E2EE behaviour back to disabled for DMs / private rooms
* (as it was before) for various environments where this is desired.
*/
val adminE2EByDefault: Boolean = true
) { ) {
companion object { companion object {
const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L

View File

@ -16,6 +16,7 @@
package im.vector.matrix.android.internal.database package im.vector.matrix.android.internal.database
import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntityFields
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
import io.realm.DynamicRealm import io.realm.DynamicRealm
import io.realm.RealmMigration import io.realm.RealmMigration
@ -28,6 +29,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
Timber.v("Migrating Realm Session from $oldVersion to $newVersion") Timber.v("Migrating Realm Session from $oldVersion to $newVersion")
if (oldVersion <= 0) migrateTo1(realm) if (oldVersion <= 0) migrateTo1(realm)
if (oldVersion <= 1) migrateTo2(realm)
} }
private fun migrateTo1(realm: DynamicRealm) { private fun migrateTo1(realm: DynamicRealm) {
@ -40,4 +42,13 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
obj.setBoolean(RoomSummaryEntityFields.HAS_FAILED_SENDING, false) obj.setBoolean(RoomSummaryEntityFields.HAS_FAILED_SENDING, false)
} }
} }
private fun migrateTo2(realm: DynamicRealm) {
Timber.d("Step 1 -> 2")
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.ADMIN_E2_E_BY_DEFAULT, Boolean::class.java)
?.transform { obj ->
obj.setBoolean(HomeServerCapabilitiesEntityFields.ADMIN_E2_E_BY_DEFAULT, true)
}
}
} }

View File

@ -46,7 +46,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
context: Context) { context: Context) {
companion object { companion object {
const val SESSION_STORE_SCHEMA_VERSION = 1L const val SESSION_STORE_SCHEMA_VERSION = 2L
} }
private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE) private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE)

View File

@ -29,7 +29,8 @@ internal object HomeServerCapabilitiesMapper {
canChangePassword = entity.canChangePassword, canChangePassword = entity.canChangePassword,
maxUploadFileSize = entity.maxUploadFileSize, maxUploadFileSize = entity.maxUploadFileSize,
lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported, lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported,
defaultIdentityServerUrl = entity.defaultIdentityServerUrl defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
adminE2EByDefault = entity.adminE2EByDefault
) )
} }
} }

View File

@ -24,6 +24,7 @@ internal open class HomeServerCapabilitiesEntity(
var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN, var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN,
var lastVersionIdentityServerSupported: Boolean = false, var lastVersionIdentityServerSupported: Boolean = false,
var defaultIdentityServerUrl: String? = null, var defaultIdentityServerUrl: String? = null,
var adminE2EByDefault: Boolean = true,
var lastUpdatedTimestamp: Long = 0L var lastUpdatedTimestamp: Long = 0L
) : RealmObject() { ) : RealmObject() {

View File

@ -108,13 +108,15 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {
homeServerCapabilitiesEntity.defaultIdentityServerUrl = getWellknownResult.identityServerUrl homeServerCapabilitiesEntity.defaultIdentityServerUrl = getWellknownResult.identityServerUrl
homeServerCapabilitiesEntity.adminE2EByDefault = getWellknownResult.wellKnown.e2eAdminSetting?.e2eDefault ?: true
// We are also checking for integration manager configurations // We are also checking for integration manager configurations
val config = configExtractor.extract(getWellknownResult.wellKnown) val config = configExtractor.extract(getWellknownResult.wellKnown)
if (config != null) { if (config != null) {
Timber.v("Extracted integration config : $config") Timber.v("Extracted integration config : $config")
realm.insertOrUpdate(config) realm.insertOrUpdate(config)
} }
} else {
homeServerCapabilitiesEntity.adminE2EByDefault = true
} }
homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time homeServerCapabilitiesEntity.lastUpdatedTimestamp = Date().time
} }

View File

@ -38,6 +38,14 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
fun create(initialState: CreateDirectRoomViewState): CreateDirectRoomViewModel fun create(initialState: CreateDirectRoomViewState): CreateDirectRoomViewModel
} }
init {
setState {
copy(
hsAdminHasDisabledE2E = !session.getHomeServerCapabilities().adminE2EByDefault
)
}
}
companion object : MvRxViewModelFactory<CreateDirectRoomViewModel, CreateDirectRoomViewState> { companion object : MvRxViewModelFactory<CreateDirectRoomViewModel, CreateDirectRoomViewState> {
@JvmStatic @JvmStatic
@ -63,7 +71,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
}.exhaustive }.exhaustive
} }
setDirectMessage() setDirectMessage()
enableEncryptionIfInvitedUsersSupportIt = true enableEncryptionIfInvitedUsersSupportIt = session.getHomeServerCapabilities().adminE2EByDefault
} }
session.rx() session.rx()

View File

@ -21,5 +21,6 @@ import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
data class CreateDirectRoomViewState( data class CreateDirectRoomViewState(
val createAndInviteState: Async<String> = Uninitialized val createAndInviteState: Async<String> = Uninitialized,
val hsAdminHasDisabledE2E: Boolean = false
) : MvRxState ) : MvRxState

View File

@ -209,7 +209,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, size.width, size.height, ContentUrlResolver.ThumbnailMethod.SCALE) Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, size.width, size.height, ContentUrlResolver.ThumbnailMethod.SCALE)
} }
// Fallback to base url // Fallback to base url
?: data.url ?: data.url.takeIf { it?.startsWith("content://") == true }
GlideApp GlideApp
.with(imageView) .with(imageView)

View File

@ -103,7 +103,10 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin
id("encryption") id("encryption")
enabled(enableFormElement) enabled(enableFormElement)
title(stringProvider.getString(R.string.create_room_encryption_title)) title(stringProvider.getString(R.string.create_room_encryption_title))
summary(stringProvider.getString(R.string.create_room_encryption_description)) summary(
if (viewState.hsAdminHasDisabledE2E) stringProvider.getString(R.string.settings_hs_admin_e2e_disabled)
else stringProvider.getString(R.string.create_room_encryption_description)
)
switchChecked(viewState.isEncrypted) switchChecked(viewState.isEncrypted)
listener { value -> listener { value ->

View File

@ -43,6 +43,15 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
fun create(initialState: CreateRoomViewState): CreateRoomViewModel fun create(initialState: CreateRoomViewState): CreateRoomViewModel
} }
init {
setState {
copy(
isEncrypted = !this.isPublic && session.getHomeServerCapabilities().adminE2EByDefault,
hsAdminHasDisabledE2E = !session.getHomeServerCapabilities().adminE2EByDefault
)
}
}
companion object : MvRxViewModelFactory<CreateRoomViewModel, CreateRoomViewState> { companion object : MvRxViewModelFactory<CreateRoomViewModel, CreateRoomViewState> {
@JvmStatic @JvmStatic
@ -69,7 +78,12 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
private fun setName(action: CreateRoomAction.SetName) = setState { copy(roomName = action.name) } private fun setName(action: CreateRoomAction.SetName) = setState { copy(roomName = action.name) }
private fun setIsPublic(action: CreateRoomAction.SetIsPublic) = setState { copy(isPublic = action.isPublic) } private fun setIsPublic(action: CreateRoomAction.SetIsPublic) = setState {
copy(
isPublic = action.isPublic,
isEncrypted = !action.isPublic && session.getHomeServerCapabilities().adminE2EByDefault
)
}
private fun setIsInRoomDirectory(action: CreateRoomAction.SetIsInRoomDirectory) = setState { copy(isInRoomDirectory = action.isInRoomDirectory) } private fun setIsInRoomDirectory(action: CreateRoomAction.SetIsInRoomDirectory) = setState { copy(isInRoomDirectory = action.isInRoomDirectory) }

View File

@ -25,5 +25,6 @@ data class CreateRoomViewState(
val isPublic: Boolean = false, val isPublic: Boolean = false,
val isInRoomDirectory: Boolean = false, val isInRoomDirectory: Boolean = false,
val isEncrypted: Boolean = false, val isEncrypted: Boolean = false,
val hsAdminHasDisabledE2E: Boolean = false,
val asyncCreateRoomRequest: Async<String> = Uninitialized val asyncCreateRoomRequest: Async<String> = Uninitialized
) : MvRxState ) : MvRxState

View File

@ -72,6 +72,8 @@ class VectorPreferences @Inject constructor(private val context: Context) {
const val SETTINGS_ALLOW_INTEGRATIONS_KEY = "SETTINGS_ALLOW_INTEGRATIONS_KEY" const val SETTINGS_ALLOW_INTEGRATIONS_KEY = "SETTINGS_ALLOW_INTEGRATIONS_KEY"
const val SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY = "SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY" const val SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY = "SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY"
const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY" const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY"
const val SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT = "SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT"
// const val SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY = "SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY" // const val SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY = "SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY"
// user // user

View File

@ -20,6 +20,9 @@ package im.vector.riotx.features.settings
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
@ -28,6 +31,7 @@ import androidx.core.view.isVisible
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.internal.crypto.crosssigning.isVerified import im.vector.matrix.android.internal.crypto.crosssigning.isVerified
@ -55,6 +59,7 @@ import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet
import im.vector.riotx.features.themes.ThemeUtils import im.vector.riotx.features.themes.ThemeUtils
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import me.gujun.android.span.span
import javax.inject.Inject import javax.inject.Inject
class VectorSettingsSecurityPrivacyFragment @Inject constructor( class VectorSettingsSecurityPrivacyFragment @Inject constructor(
@ -96,6 +101,15 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!! findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!!
} }
override fun onCreateRecyclerView(inflater: LayoutInflater?, parent: ViewGroup?, savedInstanceState: Bundle?): RecyclerView {
return super.onCreateRecyclerView(inflater, parent, savedInstanceState).also {
// Insert animation are really annoying the first time the list is shown
// due to the way preference fragment is done, it's not trivial to disable it for first appearance only..
// And it's not that an issue that this list is not animated, it's pretty static
it.itemAnimator = null
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
// My device name may have been updated // My device name may have been updated
@ -109,6 +123,9 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
}.also { }.also {
disposables.add(it) disposables.add(it)
} }
val e2eByDefault = session.getHomeServerCapabilities().adminE2EByDefault
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible = !e2eByDefault
} }
private val secureBackupCategory by lazy { private val secureBackupCategory by lazy {
@ -220,6 +237,19 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
ThemeUtils.tintDrawable(it, ThemeUtils.tintDrawable(it,
ContextCompat.getDrawable(it, R.drawable.ic_secure_backup)!!, R.attr.vctr_settings_icon_tint_color) ContextCompat.getDrawable(it, R.drawable.ic_secure_backup)!!, R.attr.vctr_settings_icon_tint_color)
} }
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.let {
it.icon = ThemeUtils.tintDrawableWithColor(
ContextCompat.getDrawable(requireContext(), R.drawable.ic_notification_privacy_warning)!!,
ContextCompat.getColor(requireContext(), R.color.riotx_destructive_accent)
)
it.summary = span {
text = getString(R.string.settings_hs_admin_e2e_disabled)
textColor = ContextCompat.getColor(requireContext(), R.color.riotx_destructive_accent)
}
it.isVisible = session.getHomeServerCapabilities().adminE2EByDefault
}
} }
// Todo this should be refactored and use same state as 4S section // Todo this should be refactored and use same state as 4S section

View File

@ -22,6 +22,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.ScrollView import android.widget.ScrollView
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.isVisible
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.args import com.airbnb.mvrx.args
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
@ -35,6 +36,8 @@ import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.setupAsSearch import im.vector.riotx.core.extensions.setupAsSearch
import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.createdirect.CreateDirectRoomViewModel
import im.vector.riotx.features.createdirect.CreateDirectRoomViewState
import kotlinx.android.synthetic.main.fragment_known_users.* import kotlinx.android.synthetic.main.fragment_known_users.*
import javax.inject.Inject import javax.inject.Inject
@ -51,6 +54,8 @@ class KnownUsersFragment @Inject constructor(
override fun getMenuRes() = args.menuResId override fun getMenuRes() = args.menuResId
private val viewModel: UserDirectoryViewModel by activityViewModel() private val viewModel: UserDirectoryViewModel by activityViewModel()
private val createDMViewModel: CreateDirectRoomViewModel by activityViewModel()
private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -58,13 +63,17 @@ class KnownUsersFragment @Inject constructor(
sharedActionViewModel = activityViewModelProvider.get(UserDirectorySharedActionViewModel::class.java) sharedActionViewModel = activityViewModelProvider.get(UserDirectorySharedActionViewModel::class.java)
knownUsersTitle.text = args.title knownUsersTitle.text = args.title
vectorBaseActivity.setSupportActionBar(knownUsersToolbar) vectorBaseActivity.setSupportActionBar(knownUsersToolbar)
setupRecyclerView() setupRecyclerView()
setupFilterView() setupFilterView()
setupAddByMatrixIdView() setupAddByMatrixIdView()
setupAddFromPhoneBookView() setupAddFromPhoneBookView()
setupCloseView() setupCloseView()
createDMViewModel.selectSubscribe(this, CreateDirectRoomViewState::hsAdminHasDisabledE2E) {
knownUsersE2EbyDefaultDisabled.isVisible = it
}
viewModel.selectSubscribe(this, UserDirectoryViewState::pendingInvitees) { viewModel.selectSubscribe(this, UserDirectoryViewState::pendingInvitees) {
renderSelectedUsers(it) renderSelectedUsers(it)
} }

View File

@ -106,6 +106,21 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/knownUsersFilter" /> app:layout_constraintTop_toBottomOf="@+id/knownUsersFilter" />
<TextView
android:id="@+id/knownUsersE2EbyDefaultDisabled"
android:visibility="gone"
tools:visibility="visible"
android:layout_margin="16dp"
app:layout_constraintTop_toBottomOf="@id/knownUsersFilterDivider"
android:text="@string/settings_hs_admin_e2e_disabled"
android:textColor="@color/riotx_destructive_accent"
android:drawableLeft="@drawable/ic_warning_badge"
android:drawablePadding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/addByMatrixId" android:id="@+id/addByMatrixId"
style="@style/VectorButtonStyleText" style="@style/VectorButtonStyleText"
@ -121,7 +136,7 @@
app:iconPadding="13dp" app:iconPadding="13dp"
app:iconTint="@color/riotx_accent" app:iconTint="@color/riotx_accent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/knownUsersFilterDivider" /> app:layout_constraintTop_toBottomOf="@id/knownUsersE2EbyDefaultDisabled" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/addFromPhoneBook" android:id="@+id/addFromPhoneBook"

View File

@ -2201,7 +2201,7 @@ Not all features in Riot are implemented in Element yet. Main missing (and comin
<string name="encryption_information_dg_xsigning_not_trusted">Cross-Signing is enabled.\nKeys are not trusted</string> <string name="encryption_information_dg_xsigning_not_trusted">Cross-Signing is enabled.\nKeys are not trusted</string>
<string name="encryption_information_dg_xsigning_disabled">Cross-Signing is not enabled</string> <string name="encryption_information_dg_xsigning_disabled">Cross-Signing is not enabled</string>
<string name="settings_hs_admin_e2e_disabled">Your server admin has disabled end-to-end encryption by default in private rooms &amp; Direct Messages.</string>
<string name="settings_active_sessions_list">Active Sessions</string> <string name="settings_active_sessions_list">Active Sessions</string>
<string name="settings_active_sessions_show_all">Show All Sessions</string> <string name="settings_active_sessions_show_all">Show All Sessions</string>
<string name="settings_active_sessions_manage">Manage Sessions</string> <string name="settings_active_sessions_manage">Manage Sessions</string>

View File

@ -3,6 +3,16 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<im.vector.riotx.core.preference.VectorPreference
android:icon="@drawable/ic_notification_privacy_warning"
android:key="SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT"
android:persistent="false"
tools:summary="@string/settings_hs_admin_e2e_disabled"
app:isPreferenceVisible="false"
tools:isPreferenceVisible="true">
</im.vector.riotx.core.preference.VectorPreference>
<!-- ************ Cryptography section ************ --> <!-- ************ Cryptography section ************ -->
<im.vector.riotx.core.preference.VectorPreferenceCategory <im.vector.riotx.core.preference.VectorPreferenceCategory
android:key="SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY" android:key="SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY"
@ -53,9 +63,9 @@
android:title="@string/settings_secure_backup_section_title"> android:title="@string/settings_secure_backup_section_title">
<im.vector.riotx.core.preference.VectorPreference <im.vector.riotx.core.preference.VectorPreference
android:icon="@drawable/ic_secure_backup"
android:key="SETTINGS_SECURE_BACKUP_RECOVERY_PREFERENCE_KEY" android:key="SETTINGS_SECURE_BACKUP_RECOVERY_PREFERENCE_KEY"
android:persistent="false" android:persistent="false"
android:icon="@drawable/ic_secure_backup"
android:title="@string/settings_secure_backup_setup" /> android:title="@string/settings_secure_backup_setup" />
<im.vector.riotx.core.preference.VectorPreference <im.vector.riotx.core.preference.VectorPreference
@ -99,8 +109,7 @@
</im.vector.riotx.core.preference.VectorPreferenceCategory> </im.vector.riotx.core.preference.VectorPreferenceCategory>
<im.vector.riotx.core.preference.VectorPreferenceCategory <im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/settings_other">
android:title="@string/settings_other">
<im.vector.riotx.core.preference.VectorSwitchPreference <im.vector.riotx.core.preference.VectorSwitchPreference
android:defaultValue="false" android:defaultValue="false"