diff --git a/changelog.d/6633.feature b/changelog.d/6633.feature
new file mode 100644
index 0000000000..b52e9d95bc
--- /dev/null
+++ b/changelog.d/6633.feature
@@ -0,0 +1 @@
+Add privacy setting to disable personalized learning by the keyboard
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 2ad3fdfb58..5aeac44a55 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -2578,6 +2578,9 @@
Prevent screenshots of the application
Enabling this setting adds the FLAG_SECURE to all Activities. Restart the application for the change to take effect.
+ Incognito keyboard
+ "Request that the keyboard should not update any personalized data such as typing history and dictionary based on what you've typed in conversations. Notice that some keyboards may not respect this setting."
+
Could not save media file
Set a new account password…
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index 00da22c8aa..8a259b0eea 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -1538,11 +1538,10 @@ class TimelineFragment :
observerUserTyping()
- if (vectorPreferences.sendMessageWithEnter()) {
- // imeOptions="actionSend" only works with single line, so we remove multiline inputType
- composerEditText.inputType = composerEditText.inputType and EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE.inv()
- composerEditText.imeOptions = EditorInfo.IME_ACTION_SEND
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ composerEditText.setUseIncognitoKeyboard(vectorPreferences.useIncognitoKeyboard())
}
+ composerEditText.setSendMessageWithEnter(vectorPreferences.sendMessageWithEnter())
composerEditText.setOnEditorActionListener { v, actionId, keyEvent ->
val imeActionId = actionId and EditorInfo.IME_MASK_ACTION
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt
index c751053cdf..9e88882866 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt
@@ -20,10 +20,12 @@ package im.vector.app.features.home.room.detail.composer
import android.content.ClipData
import android.content.Context
import android.net.Uri
+import android.os.Build
import android.text.Editable
import android.util.AttributeSet
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
+import androidx.annotation.RequiresApi
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.view.OnReceiveContentListener
import androidx.core.view.ViewCompat
@@ -79,6 +81,27 @@ class ComposerEditText @JvmOverloads constructor(
return ic
}
+ /** Set whether the keyboard should disable personalized learning. */
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun setUseIncognitoKeyboard(useIncognitoKeyboard: Boolean) {
+ imeOptions = if (useIncognitoKeyboard) {
+ imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
+ } else {
+ imeOptions and EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
+ }
+ }
+
+ /** Set whether enter should send the message or add a new line. */
+ fun setSendMessageWithEnter(sendMessageWithEnter: Boolean) {
+ if (sendMessageWithEnter) {
+ inputType = inputType and EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE.inv()
+ imeOptions = imeOptions or EditorInfo.IME_ACTION_SEND
+ } else {
+ inputType = inputType or EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ imeOptions = imeOptions and EditorInfo.IME_ACTION_SEND.inv()
+ }
+ }
+
init {
addTextChangedListener(
object : SimpleTextWatcher() {
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt
index 16d3210b45..b7812b9ebb 100755
--- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt
@@ -87,6 +87,7 @@ class VectorPreferences @Inject constructor(
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_PERSISTED_SPACE_BACKSTACK = "SETTINGS_PERSISTED_SPACE_BACKSTACK"
+ const val SETTINGS_SECURITY_INCOGNITO_KEYBOARD_PREFERENCE_KEY = "SETTINGS_SECURITY_INCOGNITO_KEYBOARD_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"
@@ -288,6 +289,7 @@ class VectorPreferences @Inject constructor(
SETTINGS_USE_RAGE_SHAKE_KEY,
SETTINGS_SECURITY_USE_FLAG_SECURE,
+ SETTINGS_SECURITY_INCOGNITO_KEYBOARD_PREFERENCE_KEY,
ShortcutsHandler.SHARED_PREF_KEY,
)
@@ -969,6 +971,11 @@ class VectorPreferences @Inject constructor(
return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_FLAG_SECURE, false)
}
+ /** Whether the keyboard should disable personalized learning. */
+ fun useIncognitoKeyboard(): Boolean {
+ return defaultPrefs.getBoolean(SETTINGS_SECURITY_INCOGNITO_KEYBOARD_PREFERENCE_KEY, false)
+ }
+
/**
* The user enable protecting app access with pin code.
* Currently we use the pin code store to know if the pin is enabled, so this is not used
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
index 5cbdf114a5..87f5af67eb 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
@@ -20,6 +20,7 @@ package im.vector.app.features.settings
import android.app.Activity
import android.content.Intent
import android.net.Uri
+import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -160,6 +161,10 @@ class VectorSettingsSecurityPrivacyFragment :
findPreference("SETTINGS_USER_ANALYTICS_CONSENT_KEY")!!
}
+ private val incognitoKeyboardPref by lazy {
+ findPreference(VectorPreferences.SETTINGS_SECURITY_INCOGNITO_KEYBOARD_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
@@ -275,6 +280,9 @@ class VectorSettingsSecurityPrivacyFragment :
// Analytics
setUpAnalytics()
+ // Incognito Keyboard
+ setUpIncognitoKeyboard()
+
// Pin code
openPinCodeSettingsPref.setOnPreferenceClickListener {
openPinCodePreferenceScreen()
@@ -337,6 +345,10 @@ class VectorSettingsSecurityPrivacyFragment :
}
}
+ private fun setUpIncognitoKeyboard() {
+ incognitoKeyboardPref.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ }
+
// Todo this should be refactored and use same state as 4S section
private fun refreshXSigningStatus() {
val crossSigningKeys = session.cryptoService().crossSigningService().getMyCrossSigningKeys()
diff --git a/vector/src/main/res/xml/vector_settings_security_privacy.xml b/vector/src/main/res/xml/vector_settings_security_privacy.xml
index 1e8997e9c8..78e1ba42a8 100644
--- a/vector/src/main/res/xml/vector_settings_security_privacy.xml
+++ b/vector/src/main/res/xml/vector_settings_security_privacy.xml
@@ -141,6 +141,12 @@
android:summary="@string/settings_security_application_protection_summary"
android:title="@string/settings_security_application_protection_title" />
+
+