From f4314ebdaef94e2b3dac5f91f8a7f46bcfc1f313 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Wed, 1 Jul 2020 21:58:58 +0200
Subject: [PATCH 01/28] Version++

---
 CHANGES.md          | 24 ++++++++++++++++++++++++
 vector/build.gradle |  2 +-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/CHANGES.md b/CHANGES.md
index ad3f82af9a..4a7d0d70af 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,27 @@
+Changes in Riot.imX 0.91.4 (2020-XX-XX)
+===================================================
+
+Features ✨:
+ -
+
+Improvements 🙌:
+ -
+
+Bugfix 🐛:
+ -
+
+Translations 🗣:
+ -
+
+SDK API changes ⚠️:
+ - 
+
+Build 🧱:
+ -
+
+Other changes:
+ -
+
 Changes in Riot.imX 0.91.3 (2020-07-01)
 ===================================================
 
diff --git a/vector/build.gradle b/vector/build.gradle
index 3c74ccda97..e497b156ae 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -17,7 +17,7 @@ androidExtensions {
 // Note: 2 digits max for each value
 ext.versionMajor = 0
 ext.versionMinor = 91
-ext.versionPatch = 3
+ext.versionPatch = 4
 
 static def getGitTimestamp() {
     def cmd = 'git show -s --format=%ct'

From 93fb40f3235422c244e0c3575893763ab0f97f7e Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 11:29:00 +0200
Subject: [PATCH 02/28] (re-)Enable abortOnError for lint And fix a first issue
 (on unused code)

---
 vector/build.gradle                                            | 3 +--
 .../vector/riotx/features/form/FormEditTextWithButtonItem.kt   | 1 +
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/vector/build.gradle b/vector/build.gradle
index e497b156ae..92e7239dbf 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -232,8 +232,7 @@ android {
     lintOptions {
         lintConfig file("lint.xml")
 
-        // TODO Restore true once pb with WorkManager is fixed
-        abortOnError false
+        abortOnError true
     }
 
     compileOptions {
diff --git a/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt b/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt
index 0650c0f55c..799f6abe00 100644
--- a/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt
+++ b/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt
@@ -56,6 +56,7 @@ abstract class FormEditTextWithButtonItem : VectorEpoxyModel<FormEditTextWithBut
     }
 
     override fun bind(holder: Holder) {
+        super.bind(holder)
         holder.textInputLayout.isEnabled = enabled
         holder.textInputLayout.hint = hint
 

From 5713fa4f595b80281e85c65047aba1f668914707 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 12:17:09 +0200
Subject: [PATCH 03/28] Clean code

---
 .../java/im/vector/riotx/VectorApplication.kt     | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/VectorApplication.kt b/vector/src/main/java/im/vector/riotx/VectorApplication.kt
index d0a3174227..ab7c3e1bf7 100644
--- a/vector/src/main/java/im/vector/riotx/VectorApplication.kt
+++ b/vector/src/main/java/im/vector/riotx/VectorApplication.kt
@@ -63,7 +63,13 @@ import java.util.Locale
 import java.util.concurrent.Executors
 import javax.inject.Inject
 
-class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider {
+import androidx.work.Configuration as WorkConfiguration
+
+class VectorApplication :
+        Application(),
+        HasVectorInjector,
+        MatrixConfiguration.Provider,
+        WorkConfiguration.Provider {
 
     lateinit var appContext: Context
     @Inject lateinit var legacySessionImporter: LegacySessionImporter
@@ -85,6 +91,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
     @Inject lateinit var webRtcPeerConnectionManager: WebRtcPeerConnectionManager
 
     lateinit var vectorComponent: VectorComponent
+
     // font thread handler
     private var fontThreadHandler: Handler? = null
 
@@ -157,7 +164,11 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
 
     override fun providesMatrixConfiguration() = MatrixConfiguration(BuildConfig.FLAVOR_DESCRIPTION)
 
-    override fun getWorkManagerConfiguration() = androidx.work.Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build()
+    override fun getWorkManagerConfiguration(): WorkConfiguration {
+        return WorkConfiguration.Builder()
+                .setExecutor(Executors.newCachedThreadPool())
+                .build()
+    }
 
     override fun injector(): VectorComponent {
         return vectorComponent

From 1de819b0a3ab6dd3d4e878ed831c3416ce45de59 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 12:21:23 +0200
Subject: [PATCH 04/28] Fix lint false-positive about WorkManger (#1012)

---
 CHANGES.md                                      | 2 +-
 matrix-sdk-android/src/main/AndroidManifest.xml | 6 ------
 vector/src/main/AndroidManifest.xml             | 6 ++++++
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 4a7d0d70af..378ea2279a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,7 +17,7 @@ SDK API changes ⚠️:
  - 
 
 Build 🧱:
- -
+ - Fix lint false-positive about WorkManger (#1012)
 
 Other changes:
  -
diff --git a/matrix-sdk-android/src/main/AndroidManifest.xml b/matrix-sdk-android/src/main/AndroidManifest.xml
index 94b2db2bf1..c02f34f1c9 100644
--- a/matrix-sdk-android/src/main/AndroidManifest.xml
+++ b/matrix-sdk-android/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     package="im.vector.matrix.android">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -8,11 +7,6 @@
 
     <application android:networkSecurityConfig="@xml/network_security_config">
 
-        <provider
-            android:name="androidx.work.impl.WorkManagerInitializer"
-            android:authorities="${applicationId}.workmanager-init"
-            android:exported="false"
-            tools:node="remove" />
         <!--
          The SDK offers a secured File provider to access downloaded files.
          Access to these file will be given via the FileService, with a temporary
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index 3ed0d95b71..f9b78db17c 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -247,6 +247,12 @@
 
         <!-- Providers -->
 
+        <!-- Remove WorkManagerInitializer Provider because we are using on-demand initialization of WorkManager-->
+        <provider
+            android:name="androidx.work.impl.WorkManagerInitializer"
+            android:authorities="${applicationId}.workmanager-init"
+            tools:node="remove" />
+
         <provider
             android:name="androidx.core.content.FileProvider"
             android:authorities="${applicationId}.fileProvider"

From 542d11d7f1fd095fddb7d0b8dd7aaca78ec3ab7d Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 12:44:07 +0200
Subject: [PATCH 05/28] Upgrade build-tools from 3.5.3 to 3.6.6 and gradle from
 5.4.1 to 5.6.4

---
 CHANGES.md                               | 2 ++
 build.gradle                             | 2 +-
 gradle/wrapper/gradle-wrapper.properties | 4 ++--
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 378ea2279a..3555894bf4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,6 +18,8 @@ SDK API changes ⚠️:
 
 Build 🧱:
  - Fix lint false-positive about WorkManger (#1012)
+ - Upgrade build-tools from 3.5.3 to 3.6.6
+ - Upgrade gradle from 5.4.1 to 5.6.4
 
 Other changes:
  -
diff --git a/build.gradle b/build.gradle
index 74a62f0d17..5f1fa78620 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,7 +10,7 @@ buildscript {
         }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.5.3'
+        classpath 'com.android.tools.build:gradle:3.6.3'
         classpath 'com.google.gms:google-services:4.3.2'
         classpath "com.airbnb.okreplay:gradle-plugin:1.5.0"
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 51b92600a0..4da2435f42 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Sep 27 10:10:35 CEST 2019
+#Thu Jul 02 12:33:07 CEST 2020
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

From 69eaf2695e8c48eb78fec1c1defe54e6d41dfa24 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Thu, 2 Jul 2020 14:08:09 +0200
Subject: [PATCH 06/28] FIx / inbound session bad migration

---
 .../internal/crypto/store/db/RealmCryptoStoreMigration.kt    | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
index eb2fc9ebad..47af558b90 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
@@ -182,7 +182,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
                     try {
                         val oldSerializedData = obj.getString("olmInboundGroupSessionData")
                         deserializeFromRealm<MXOlmInboundGroupSession2>(oldSerializedData)?.let { mxOlmInboundGroupSession2 ->
-                            val newOlmInboundGroupSessionWrapper2 = OlmInboundGroupSessionWrapper2()
+                            val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier()
+                            val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false)
                                     .apply {
                                         olmInboundGroupSession = mxOlmInboundGroupSession2.mSession
                                         roomId = mxOlmInboundGroupSession2.mRoomId
@@ -191,7 +192,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
                                         forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain
                                     }
 
-                            obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper2))
+                            obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper))
                         }
                     } catch (e: Exception) {
                         Timber.e(e, "Error")

From 2ef82f1b827eeca512c7f05badbc2f13ef3cf3ae Mon Sep 17 00:00:00 2001
From: ganfra <francoisg@matrix.org>
Date: Thu, 2 Jul 2020 16:05:05 +0200
Subject: [PATCH 07/28] Use HomeActivity.newIntent to make sure we have args

---
 .../features/notifications/NotificationUtils.kt      | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt
index d7dabd0778..36874d5782 100755
--- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt
+++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt
@@ -205,7 +205,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
     @SuppressLint("NewApi")
     fun buildForegroundServiceNotification(@StringRes subTitleResId: Int, withProgress: Boolean = true): Notification {
         // build the pending intent go to the home screen if this is clicked.
-        val i = Intent(context, HomeActivity::class.java)
+        val i = HomeActivity.newIntent(context)
         i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
         val pi = PendingIntent.getActivity(context, 0, i, 0)
 
@@ -307,7 +307,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
         val contentPendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), contentIntent, 0)
 
         val answerCallPendingIntent = TaskStackBuilder.create(context)
-                .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java))
+                .addNextIntentWithParentStack(HomeActivity.newIntent(context))
                 .addNextIntent(VectorCallActivity.newIntent(
                         context = context,
                         callId = callId,
@@ -459,7 +459,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
         )
 
         val contentPendingIntent = TaskStackBuilder.create(context)
-                .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java))
+                .addNextIntentWithParentStack(HomeActivity.newIntent(context))
                 // TODO other userId
                 .addNextIntent(VectorCallActivity.newIntent(context, callId, roomId, "otherUserId", true, isVideo, null))
                 .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
@@ -651,7 +651,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
                             stringProvider.getString(R.string.join),
                             joinIntentPendingIntent)
 
-                    val contentIntent = Intent(context, HomeActivity::class.java)
+                    val contentIntent = HomeActivity.newIntent(context)
                     contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
                     // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that
                     contentIntent.data = Uri.parse("foobar://" + inviteNotifiableEvent.eventId)
@@ -689,7 +689,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
                 .setColor(accentColor)
                 .setAutoCancel(true)
                 .apply {
-                    val contentIntent = Intent(context, HomeActivity::class.java)
+                    val contentIntent = HomeActivity.newIntent(context)
                     contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
                     // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that
                     contentIntent.data = Uri.parse("foobar://" + simpleNotifiableEvent.eventId)
@@ -718,7 +718,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
 
         // Recreate the back stack
         return TaskStackBuilder.create(context)
-                .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java))
+                .addNextIntentWithParentStack(HomeActivity.newIntent(context))
                 .addNextIntent(roomIntentTap)
                 .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
     }

From 5008bfd6a9c7daf42196ec15749fd4b01e99954d Mon Sep 17 00:00:00 2001
From: ganfra <francoisg@matrix.org>
Date: Thu, 2 Jul 2020 16:17:00 +0200
Subject: [PATCH 08/28] Update CHANGES

---
 CHANGES.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGES.md b/CHANGES.md
index 4a7d0d70af..519a42db4e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,7 +8,7 @@ Improvements 🙌:
  -
 
 Bugfix 🐛:
- -
+ - Fix crash when coming from a notification (#1601)
 
 Translations 🗣:
  -

From 596fcf94bac88f461cb6ef487f893fe710a6d613 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Thu, 2 Jul 2020 19:26:05 +0200
Subject: [PATCH 09/28] Fix / Serialization issues

Fixes  keybackup import failing and UTD of incoming messages
---
 matrix-sdk-android/proguard-rules.pro | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/matrix-sdk-android/proguard-rules.pro b/matrix-sdk-android/proguard-rules.pro
index 08a20cbf0a..fa860d8049 100644
--- a/matrix-sdk-android/proguard-rules.pro
+++ b/matrix-sdk-android/proguard-rules.pro
@@ -64,3 +64,19 @@
 
 ### Webrtc
 -keep class org.webrtc.** { *; }
+
+### Serializable persisted classes
+# https://www.guardsquare.com/en/products/proguard/manual/examples#serializable
+-keepnames class * implements java.io.Serializable
+
+-keepclassmembers class * implements java.io.Serializable {
+    static final long serialVersionUID;
+    private static final java.io.ObjectStreamField[] serialPersistentFields;
+    !static !transient <fields>;
+    !private <fields>;
+    !private <methods>;
+    private void writeObject(java.io.ObjectOutputStream);
+    private void readObject(java.io.ObjectInputStream);
+    java.lang.Object writeReplace();
+    java.lang.Object readResolve();
+}
\ No newline at end of file

From e098b87d0a9908f9cccbb0afab83819433083f2d Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 21:30:49 +0200
Subject: [PATCH 10/28] Update comment

---
 .../internal/crypto/store/db/RealmCryptoStoreMigration.kt       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
index 47af558b90..7bf8e2478f 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
@@ -176,7 +176,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
                     }
                 }
 
-        // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper2
+        // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper
         realm.schema.get("OlmInboundGroupSessionEntity")
                 ?.transform { obj ->
                     try {

From 15223ecfe4ccda4b97b27c8511d668e9b0b5e49c Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 21:31:39 +0200
Subject: [PATCH 11/28] Update changelog with the recent change

---
 CHANGES.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGES.md b/CHANGES.md
index 4a7d0d70af..61e27a1476 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,7 +8,7 @@ Improvements 🙌:
  -
 
 Bugfix 🐛:
- -
+ - Fix Exception when importing keys (#1576)
 
 Translations 🗣:
  -

From bfb8b6203cca75448e97efc0f7bafc2ff62a7121 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 22:02:42 +0200
Subject: [PATCH 12/28] Add proguard command (commented)

---
 vector/proguard-rules.pro | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/vector/proguard-rules.pro b/vector/proguard-rules.pro
index 56d3b95510..bc27767d8a 100644
--- a/vector/proguard-rules.pro
+++ b/vector/proguard-rules.pro
@@ -20,4 +20,7 @@
 # hide the original source file name.
 #-renamesourcefileattribute SourceFile
 
--keep class im.vector.riotx.features.** { *; }
\ No newline at end of file
+-keep class im.vector.riotx.features.** { *; }
+
+## print all the rules in a file
+# -printconfiguration ../proguard_files/full-r8-config.txt

From d4050a7b9d18a92b56960c192d5662f2b48184ba Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Thu, 2 Jul 2020 23:39:42 +0200
Subject: [PATCH 13/28] Due to a bug introduced in Android gradle plugin 3.6.0,
 we have to specify the ndk version to use

---
 vector/build.gradle | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/vector/build.gradle b/vector/build.gradle
index 92e7239dbf..f966f441b2 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -106,6 +106,11 @@ def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0
 
 android {
     compileSdkVersion 29
+
+    // Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use
+    // Ref: https://issuetracker.google.com/issues/144111441
+    ndkVersion "21.3.6528147"
+
     defaultConfig {
         applicationId "im.vector.app"
         // Set to API 21: see #405

From bdfce35d9a11c8aea854b4fbe6f14013aeaad6cd Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Fri, 3 Jul 2020 09:34:38 +0200
Subject: [PATCH 14/28] Fix / save media on old android

+ add numbers to file if needed
---
 CHANGES.md                                    |   2 +
 .../core/utils/ExternalApplicationsUtil.kt    | 195 ++++++++++++++----
 .../home/room/detail/RoomDetailFragment.kt    |  24 ++-
 .../action/MessageSharedActionViewModel.kt    |   4 +-
 4 files changed, 173 insertions(+), 52 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index b56cbef37a..636e848c3b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,8 @@ Improvements 🙌:
 Bugfix 🐛:
  - Fix crash when coming from a notification (#1601)
  - Fix Exception when importing keys (#1576)
+ - File isn't downloaded when another file with the same name already exists (#1578)
+ - saved images don't show up in gallery (#1324)
 
 Translations 🗣:
  -
diff --git a/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt
index d93d4e9089..2520f44f50 100644
--- a/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt
+++ b/vector/src/main/java/im/vector/riotx/core/utils/ExternalApplicationsUtil.kt
@@ -17,29 +17,39 @@
 package im.vector.riotx.core.utils
 
 import android.app.Activity
+import android.app.DownloadManager
 import android.content.ActivityNotFoundException
 import android.content.ContentValues
 import android.content.Context
 import android.content.Intent
 import android.graphics.BitmapFactory
+import android.media.MediaScannerConnection
 import android.net.Uri
 import android.os.Build
+import android.os.Environment
 import android.provider.Browser
 import android.provider.MediaStore
+import android.webkit.MimeTypeMap
 import android.widget.Toast
 import androidx.browser.customtabs.CustomTabsIntent
 import androidx.browser.customtabs.CustomTabsSession
 import androidx.core.content.ContextCompat
 import androidx.core.content.FileProvider
 import androidx.fragment.app.Fragment
+import im.vector.matrix.android.api.extensions.tryThis
 import im.vector.riotx.BuildConfig
 import im.vector.riotx.R
 import im.vector.riotx.features.notifications.NotificationUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
 import okio.buffer
 import okio.sink
 import okio.source
 import timber.log.Timber
 import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
 import java.text.SimpleDateFormat
 import java.util.Date
 import java.util.Locale
@@ -301,42 +311,20 @@ fun shareMedia(context: Context, file: File, mediaMimeType: String?) {
 
 fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) {
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-        val externalContentUri: Uri
-        val values = ContentValues()
-        when {
-            mediaMimeType?.startsWith("image/") == true -> {
-                externalContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
-                values.put(MediaStore.Images.Media.TITLE, title)
-                values.put(MediaStore.Images.Media.DISPLAY_NAME, title)
-                values.put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
-                values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
-                values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
-            }
-            mediaMimeType?.startsWith("video/") == true -> {
-                externalContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
-                values.put(MediaStore.Video.Media.TITLE, title)
-                values.put(MediaStore.Video.Media.DISPLAY_NAME, title)
-                values.put(MediaStore.Video.Media.MIME_TYPE, mediaMimeType)
-                values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis())
-                values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis())
-            }
-            mediaMimeType?.startsWith("audio/") == true -> {
-                externalContentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
-                values.put(MediaStore.Audio.Media.TITLE, title)
-                values.put(MediaStore.Audio.Media.DISPLAY_NAME, title)
-                values.put(MediaStore.Audio.Media.MIME_TYPE, mediaMimeType)
-                values.put(MediaStore.Audio.Media.DATE_ADDED, System.currentTimeMillis())
-                values.put(MediaStore.Audio.Media.DATE_TAKEN, System.currentTimeMillis())
-            }
-            else                                        -> {
-                externalContentUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI
-                values.put(MediaStore.Downloads.TITLE, title)
-                values.put(MediaStore.Downloads.DISPLAY_NAME, title)
-                values.put(MediaStore.Downloads.MIME_TYPE, mediaMimeType)
-                values.put(MediaStore.Downloads.DATE_ADDED, System.currentTimeMillis())
-                values.put(MediaStore.Downloads.DATE_TAKEN, System.currentTimeMillis())
-            }
+        val values = ContentValues().apply {
+            put(MediaStore.Images.Media.TITLE, title)
+            put(MediaStore.Images.Media.DISPLAY_NAME, title)
+            put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
+            put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
+            put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
         }
+        val externalContentUri = when {
+            mediaMimeType?.startsWith("image/") == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+            mediaMimeType?.startsWith("video/") == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+            mediaMimeType?.startsWith("audio/") == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+            else                                        -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
+        }
+
         val uri = context.contentResolver.insert(externalContentUri, values)
         if (uri == null) {
             Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show()
@@ -357,16 +345,70 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String
                 notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
             }
         }
-        // TODO add notification?
     } else {
-        @Suppress("DEPRECATION")
-        Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
-            mediaScanIntent.data = Uri.fromFile(file)
-            context.sendBroadcast(mediaScanIntent)
+        saveMediaLegacy(context, mediaMimeType, title, file)
+    }
+}
+
+@Suppress("DEPRECATION")
+private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: String, file: File) {
+    val state = Environment.getExternalStorageState()
+    if (Environment.MEDIA_MOUNTED != state) {
+        context.toast(context.getString(R.string.error_saving_media_file))
+        return
+    }
+
+    GlobalScope.launch(Dispatchers.IO) {
+        val dest = when {
+            mediaMimeType?.startsWith("image/") == true -> Environment.DIRECTORY_PICTURES
+            mediaMimeType?.startsWith("video/") == true -> Environment.DIRECTORY_MOVIES
+            mediaMimeType?.startsWith("audio/") == true -> Environment.DIRECTORY_MUSIC
+            else                                        -> Environment.DIRECTORY_DOWNLOADS
+        }
+        val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
+        try {
+            val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) {
+                val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
+                "$title.$extension"
+            } else {
+                title
+            }
+            val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename)
+            if (savedFile != null) {
+                val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as? DownloadManager
+                downloadManager?.addCompletedDownload(
+                        savedFile.name,
+                        title,
+                        true,
+                        mediaMimeType ?: "application/octet-stream",
+                        savedFile.absolutePath,
+                        savedFile.length(),
+                        true)
+                addToGallery(savedFile, mediaMimeType, context)
+            }
+        } catch (error: Throwable) {
+            GlobalScope.launch(Dispatchers.Main) {
+                context.toast(context.getString(R.string.error_saving_media_file))
+            }
         }
     }
 }
 
+private fun addToGallery(savedFile: File, mediaMimeType: String?, context: Context) {
+    // MediaScannerConnection provides a way for applications to pass a newly created or downloaded media file to the media scanner service.
+    var mediaConnection: MediaScannerConnection? = null
+    val mediaScannerConnectionClient: MediaScannerConnection.MediaScannerConnectionClient = object : MediaScannerConnection.MediaScannerConnectionClient {
+        override fun onMediaScannerConnected() {
+            mediaConnection?.scanFile(savedFile.path, mediaMimeType)
+        }
+
+        override fun onScanCompleted(path: String, uri: Uri?) {
+            if (path == savedFile.path) mediaConnection?.disconnect()
+        }
+    }
+    mediaConnection = MediaScannerConnection(context, mediaScannerConnectionClient).apply { connect() }
+}
+
 /**
  * Open the play store to the provided application Id, default to this app
  */
@@ -381,3 +423,76 @@ fun openPlayStore(activity: Activity, appId: String = BuildConfig.APPLICATION_ID
         }
     }
 }
+
+// ==============================================================================================================
+// Media utils
+// ==============================================================================================================
+/**
+ * Copy a file into a dstPath directory.
+ * The output filename can be provided.
+ * The output file is not overridden if it is already exist.
+ *
+ * ~~ This is copied from the old matrix sdk ~~
+ *
+ * @param sourceFile     the file source path
+ * @param dstDirPath     the dst path
+ * @param outputFilename optional the output filename
+ * @param callback       the asynchronous callback
+ */
+@Suppress("DEPRECATION")
+fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?): File? {
+    // defines another name for the external media
+    val dstFileName: String
+
+    // build a filename is not provided
+    if (null == outputFilename) {
+        // extract the file extension from the uri
+        val dotPos = sourceFile.name.lastIndexOf(".")
+        var fileExt = ""
+        if (dotPos > 0) {
+            fileExt = sourceFile.name.substring(dotPos)
+        }
+        dstFileName = "vector_" + System.currentTimeMillis() + fileExt
+    } else {
+        dstFileName = outputFilename
+    }
+
+    var dstFile = File(dstDirPath, dstFileName)
+
+    // if the file already exists, append a marker
+    if (dstFile.exists()) {
+        var baseFileName = dstFileName
+        var fileExt = ""
+        val lastDotPos = dstFileName.lastIndexOf(".")
+        if (lastDotPos > 0) {
+            baseFileName = dstFileName.substring(0, lastDotPos)
+            fileExt = dstFileName.substring(lastDotPos)
+        }
+        var counter = 1
+        while (dstFile.exists()) {
+            dstFile = File(dstDirPath, "$baseFileName($counter)$fileExt")
+            counter++
+        }
+    }
+
+    // Copy source file to destination
+    var inputStream: FileInputStream? = null
+    var outputStream: FileOutputStream? = null
+    try {
+        dstFile.createNewFile()
+        inputStream = FileInputStream(sourceFile)
+        outputStream = FileOutputStream(dstFile)
+        val buffer = ByteArray(1024 * 10)
+        var len: Int
+        while (inputStream.read(buffer).also { len = it } != -1) {
+            outputStream.write(buffer, 0, len)
+        }
+        return dstFile
+    } catch (failure: Throwable) {
+        return null
+    } finally {
+        // Close resources
+        tryThis { inputStream?.close() }
+        tryThis { outputStream?.close() }
+    }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index 2d7a26efb7..ea5376fd17 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -22,6 +22,7 @@ import android.content.DialogInterface
 import android.content.Intent
 import android.graphics.Typeface
 import android.net.Uri
+import android.os.Build
 import android.os.Bundle
 import android.os.Parcelable
 import android.text.Spannable
@@ -222,6 +223,7 @@ class RoomDetailFragment @Inject constructor(
 
         private const val AUDIO_CALL_PERMISSION_REQUEST_CODE = 1
         private const val VIDEO_CALL_PERMISSION_REQUEST_CODE = 2
+        private const val SAVE_ATTACHEMENT_REQUEST_CODE = 3
 
         /**
          * Sanitize the display name.
@@ -1194,17 +1196,12 @@ class RoomDetailFragment @Inject constructor(
     override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
         if (allGranted(grantResults)) {
             when (requestCode) {
-//                PERMISSION_REQUEST_CODE_DOWNLOAD_FILE   -> {
-//                    val action = roomDetailViewModel.pendingAction
-//                    if (action != null) {
-//                        (action as? RoomDetailAction.DownloadFile)
-//                                ?.messageFileContent
-//                                ?.getFileName()
-//                                ?.let { showSnackWithMessage(getString(R.string.downloading_file, it)) }
-//                        roomDetailViewModel.pendingAction = null
-//                        roomDetailViewModel.handle(action)
-//                    }
-//                }
+                SAVE_ATTACHEMENT_REQUEST_CODE -> {
+                    sharedActionViewModel.pendingAction?.let {
+                        handleActions(it)
+                        sharedActionViewModel.pendingAction = null
+                    }
+                }
                 PERMISSION_REQUEST_CODE_INCOMING_URI    -> {
                     val pendingUri = roomDetailViewModel.pendingUri
                     if (pendingUri != null) {
@@ -1357,6 +1354,11 @@ class RoomDetailFragment @Inject constructor(
     }
 
     private fun onSaveActionClicked(action: EventSharedAction.Save) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
+                !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) {
+            sharedActionViewModel.pendingAction = action
+            return
+        }
         session.fileService().downloadFile(
                 downloadMode = FileService.DownloadMode.FOR_EXTERNAL_SHARE,
                 id = action.eventId,
diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt
index 2e041fd2ea..ec5c49f814 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt
@@ -21,4 +21,6 @@ import javax.inject.Inject
 /**
  * Activity shared view model to handle message actions
  */
-class MessageSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<EventSharedAction>()
+class MessageSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<EventSharedAction>() {
+    var pendingAction : EventSharedAction? = null
+}

From 85ee183e4f7a730e6aafb19613d53666157fbd1c Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Fri, 3 Jul 2020 12:28:32 +0200
Subject: [PATCH 15/28] Update
 vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt

---
 .../riotx/features/home/room/detail/RoomDetailFragment.kt       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index ea5376fd17..c941784842 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -1354,7 +1354,7 @@ class RoomDetailFragment @Inject constructor(
     }
 
     private fun onSaveActionClicked(action: EventSharedAction.Save) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
                 !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) {
             sharedActionViewModel.pendingAction = action
             return

From c4ad90696f782dcdf2e85c4fa5d125d52fff389c Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Fri, 3 Jul 2020 12:28:38 +0200
Subject: [PATCH 16/28] Update
 vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt

---
 .../riotx/features/home/room/detail/RoomDetailFragment.kt       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
index c941784842..9d7ea58bb5 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt
@@ -1355,7 +1355,7 @@ class RoomDetailFragment @Inject constructor(
 
     private fun onSaveActionClicked(action: EventSharedAction.Save) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
-                !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) {
+                && !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) {
             sharedActionViewModel.pendingAction = action
             return
         }

From e9ba7342d5d3ad5c07136de3bc3160378302b597 Mon Sep 17 00:00:00 2001
From: Tulir Asokan <tulir@maunium.net>
Date: Fri, 3 Jul 2020 23:10:44 +0300
Subject: [PATCH 17/28] Fix reply fallback format

Signed-off-by: Tulir Asokan <tulir@maunium.net>
---
 CHANGES.md                                           |  1 +
 .../session/room/send/LocalEchoEventFactory.kt       | 12 +++++-------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index c5cae43f67..9138eb6ad2 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ Improvements 🙌:
 Bugfix 🐛:
  - Fix crash when coming from a notification (#1601)
  - Fix Exception when importing keys (#1576)
+ - Fix reply fallback leaking sender locale (#429)
 
 Translations 🗣:
  -
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt
index 08dc4e80d8..370a81e409 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt
@@ -177,7 +177,6 @@ internal class LocalEchoEventFactory @Inject constructor(
         val body = bodyForReply(originalEvent.getLastMessageContent(), originalEvent.root.getClearContent().toModel())
         val replyFormatted = REPLY_PATTERN.format(
                 permalink,
-                stringProvider.getString(R.string.message_reply_to_prefix),
                 userLink,
                 originalEvent.senderInfo.disambiguatedDisplayName,
                 body.takeFormatted(),
@@ -372,7 +371,6 @@ internal class LocalEchoEventFactory @Inject constructor(
         val body = bodyForReply(eventReplied.getLastMessageContent(), eventReplied.root.getClearContent().toModel())
         val replyFormatted = REPLY_PATTERN.format(
                 permalink,
-                stringProvider.getString(R.string.message_reply_to_prefix),
                 userLink,
                 userId,
                 body.takeFormatted(),
@@ -434,10 +432,10 @@ internal class LocalEchoEventFactory @Inject constructor(
                     TextContent(content.body, formattedText)
                 }
             }
-            MessageType.MSGTYPE_FILE   -> return TextContent(stringProvider.getString(R.string.reply_to_a_file))
-            MessageType.MSGTYPE_AUDIO  -> return TextContent(stringProvider.getString(R.string.reply_to_an_audio_file))
-            MessageType.MSGTYPE_IMAGE  -> return TextContent(stringProvider.getString(R.string.reply_to_an_image))
-            MessageType.MSGTYPE_VIDEO  -> return TextContent(stringProvider.getString(R.string.reply_to_a_video))
+            MessageType.MSGTYPE_FILE   -> return TextContent("sent a file.")
+            MessageType.MSGTYPE_AUDIO  -> return TextContent("sent an audio file.")
+            MessageType.MSGTYPE_IMAGE  -> return TextContent("sent an image.")
+            MessageType.MSGTYPE_VIDEO  -> return TextContent("sent a video.")
             else                       -> return TextContent(content?.body ?: "")
         }
     }
@@ -489,6 +487,6 @@ internal class LocalEchoEventFactory @Inject constructor(
         //     </blockquote>
         // </mx-reply>
         // No whitespace because currently breaks temporary formatted text to Span
-        const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">%s</a><a href="%s">%s</a><br />%s</blockquote></mx-reply>%s"""
+        const val REPLY_PATTERN = """<mx-reply><blockquote><a href="%s">In reply to</a> <a href="%s">%s</a><br />%s</blockquote></mx-reply>%s"""
     }
 }

From 51e63c5d1de60eabd1c095214ec1b20038667643 Mon Sep 17 00:00:00 2001
From: Tulir Asokan <tulir@maunium.net>
Date: Fri, 3 Jul 2020 23:12:38 +0300
Subject: [PATCH 18/28] Remove unused reply fallback translations

Signed-off-by: Tulir Asokan <tulir@maunium.net>
---
 matrix-sdk-android/src/main/res/values-ar/strings.xml     | 6 ------
 matrix-sdk-android/src/main/res/values-az/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-bg/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-ca/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-cs/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-de/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-el/strings.xml     | 6 ------
 matrix-sdk-android/src/main/res/values-eo/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-es-rMX/strings.xml | 7 -------
 matrix-sdk-android/src/main/res/values-es/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-et/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-eu/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-fa/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-fi/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-fr/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-gl/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-hu/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-is/strings.xml     | 1 -
 matrix-sdk-android/src/main/res/values-it/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-ja/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-ko/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-nl/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-nn/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-pl/strings.xml     | 6 ------
 matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml | 7 -------
 matrix-sdk-android/src/main/res/values-ru/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-sk/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-sq/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-uk/strings.xml     | 7 -------
 matrix-sdk-android/src/main/res/values-vls/strings.xml    | 7 -------
 matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml | 7 -------
 matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml | 7 -------
 matrix-sdk-android/src/main/res/values/strings.xml        | 7 -------
 33 files changed, 222 deletions(-)

diff --git a/matrix-sdk-android/src/main/res/values-ar/strings.xml b/matrix-sdk-android/src/main/res/values-ar/strings.xml
index ab48ea9934..e9aba1721a 100644
--- a/matrix-sdk-android/src/main/res/values-ar/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ar/strings.xml
@@ -63,12 +63,6 @@
     <string name="summary_user_sent_sticker">أرسل ⁨%1$s⁩ ملصقا.</string>
 
     <string name="notice_avatar_changed_too">(تغيّرت الصورة أيضا)</string>
-    <string name="message_reply_to_prefix">ردا على</string>
-
-    <string name="reply_to_an_image">أرسل صورة.</string>
-    <string name="reply_to_a_video">أرسل فديوهًا.</string>
-    <string name="reply_to_an_audio_file">أرسل ملف صوت.</string>
-    <string name="reply_to_a_file">أرسل ملفًا.</string>
 
     <string name="room_displayname_invite_from">دعوة من ⁨%s⁩</string>
     <string name="room_displayname_empty_room">غرفة فارغة</string>
diff --git a/matrix-sdk-android/src/main/res/values-az/strings.xml b/matrix-sdk-android/src/main/res/values-az/strings.xml
index c4347619d0..9c60dfafa7 100644
--- a/matrix-sdk-android/src/main/res/values-az/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-az/strings.xml
@@ -52,8 +52,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Şifrəni aça bilmir: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Göndərənin cihazı bu mesaj üçün açarları bizə göndərməyib.</string>
 
-    <string name="message_reply_to_prefix">Cavab olaraq</string>
-
     <string name="could_not_redact">Redaktə etmək olmur</string>
     <string name="unable_to_send_message">Mesaj göndərmək olmur</string>
 
@@ -69,11 +67,6 @@
     <string name="medium_email">Elektron poçt ünvanı</string>
     <string name="medium_phone_number">Telefon nömrəsi</string>
 
-    <string name="reply_to_an_image">şəkil göndərdi.</string>
-    <string name="reply_to_a_video">video göndərdi.</string>
-    <string name="reply_to_an_audio_file">səs faylı göndərdi.</string>
-    <string name="reply_to_a_file">fayl göndərdi.</string>
-
     <string name="room_displayname_invite_from">%s-dən dəvət</string>
     <string name="room_displayname_room_invite">Otağa dəvət</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-bg/strings.xml b/matrix-sdk-android/src/main/res/values-bg/strings.xml
index ea53f593fa..07d59852f3 100644
--- a/matrix-sdk-android/src/main/res/values-bg/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-bg/strings.xml
@@ -63,13 +63,6 @@
 
     <string name="summary_user_sent_sticker">%1$s изпрати стикер.</string>
 
-    <string name="message_reply_to_prefix">В отговор на</string>
-
-    <string name="reply_to_an_image">изпрати снимка.</string>
-    <string name="reply_to_a_video">изпрати видео.</string>
-    <string name="reply_to_an_audio_file">изпрати аудио файл.</string>
-    <string name="reply_to_a_file">изпрати файл.</string>
-
     <string name="room_displayname_invite_from">Покана от %s</string>
     <string name="room_displayname_room_invite">Покана за стая</string>
     <string name="room_displayname_two_members">%1$s и %2$s</string>
diff --git a/matrix-sdk-android/src/main/res/values-ca/strings.xml b/matrix-sdk-android/src/main/res/values-ca/strings.xml
index c59ee3b23d..2dc2206c8c 100644
--- a/matrix-sdk-android/src/main/res/values-ca/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ca/strings.xml
@@ -76,11 +76,4 @@
 
     <string name="summary_user_sent_sticker">%1$s ha enviat un adhesiu.</string>
 
-    <string name="message_reply_to_prefix">En resposta a</string>
-
-    <string name="reply_to_an_image">ha enviat una imatge.</string>
-    <string name="reply_to_a_video">ha enviat un vídeo.</string>
-    <string name="reply_to_an_audio_file">ha enviat un fitxer d\'àudio.</string>
-    <string name="reply_to_a_file">ha enviat un fitxer.</string>
-
 </resources>
diff --git a/matrix-sdk-android/src/main/res/values-cs/strings.xml b/matrix-sdk-android/src/main/res/values-cs/strings.xml
index 7e5081b6e9..44908c38f7 100644
--- a/matrix-sdk-android/src/main/res/values-cs/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-cs/strings.xml
@@ -46,8 +46,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Nelze dešifrovat: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Odesílatelovo zařízení neposlalo klíče pro tuto zprávu.</string>
 
-    <string name="message_reply_to_prefix">V odpovědi na</string>
-
     <string name="could_not_redact">Nelze vymazat</string>
     <string name="unable_to_send_message">Zprávu nelze odeslat</string>
 
@@ -63,11 +61,6 @@
     <string name="medium_email">E-mailová adresa</string>
     <string name="medium_phone_number">Telefonní číslo</string>
 
-    <string name="reply_to_an_image">odeslal obrázek.</string>
-    <string name="reply_to_a_video">odeslal video.</string>
-    <string name="reply_to_an_audio_file">odeslal zvukový soubor.</string>
-    <string name="reply_to_a_file">odeslal soubor.</string>
-
     <string name="room_displayname_invite_from">Pozvání od %s</string>
     <string name="room_displayname_room_invite">Pozvání do místnosti</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-de/strings.xml b/matrix-sdk-android/src/main/res/values-de/strings.xml
index d19396d932..94da3369d8 100644
--- a/matrix-sdk-android/src/main/res/values-de/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-de/strings.xml
@@ -73,13 +73,6 @@
 
     <string name="summary_user_sent_sticker">%1$s sandte einen Sticker.</string>
 
-    <string name="message_reply_to_prefix">Als Antwort auf</string>
-
-    <string name="reply_to_an_image">hat ein Bild gesendet.</string>
-    <string name="reply_to_a_video">hat ein Video gesendet.</string>
-    <string name="reply_to_an_audio_file">hat eine Audio-Datei gesendet.</string>
-    <string name="reply_to_a_file">sandte eine Datei.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Einladung von %s</string>
     <string name="room_displayname_room_invite">Raumeinladung</string>
diff --git a/matrix-sdk-android/src/main/res/values-el/strings.xml b/matrix-sdk-android/src/main/res/values-el/strings.xml
index 37eac5351e..9db4e91849 100644
--- a/matrix-sdk-android/src/main/res/values-el/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-el/strings.xml
@@ -40,8 +40,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Αδυναμία αποκρυπτογράφησης: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Η συσκευή του/της αποστολέα δεν μας έχει στείλει τα κλειδιά για αυτό το μήνυμα.</string>
 
-    <string name="message_reply_to_prefix">Προς απάντηση στο</string>
-
     <string name="unable_to_send_message">Αποτυχία αποστολής μηνύματος</string>
 
     <string name="message_failed_to_upload">Αποτυχία αναφόρτωσης εικόνας</string>
@@ -56,10 +54,6 @@
     <string name="notice_voip_finished">Η VoIP διάσκεψη έληξε</string>
 
     <string name="notice_room_join">Ο/Η %1$s εισήλθε στο δωμάτιο</string>
-    <string name="reply_to_an_image">έστειλε μία εικόνα.</string>
-    <string name="reply_to_a_video">έστειλε ένα βίντεο.</string>
-    <string name="reply_to_an_audio_file">έστειλε ένα αρχείο ήχου.</string>
-    <string name="reply_to_a_file">έστειλε ένα αρχείο.</string>
 
     <string name="room_displayname_invite_from">Πρόσκληση από %s</string>
     <string name="room_displayname_room_invite">Πρόσκληση στο δωμάτιο</string>
diff --git a/matrix-sdk-android/src/main/res/values-eo/strings.xml b/matrix-sdk-android/src/main/res/values-eo/strings.xml
index 69600394ac..4a1e2c4c65 100644
--- a/matrix-sdk-android/src/main/res/values-eo/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-eo/strings.xml
@@ -17,8 +17,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Ne eblas malĉifri: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">La aparato de la sendanto ne sendis al ni la ŝlosilojn por tiu mesaĝo.</string>
 
-    <string name="message_reply_to_prefix">Responde al</string>
-
     <string name="summary_message">%1$s: %2$s</string>
     <string name="notice_display_name_set">%1$s ŝanĝis sian vidigan nomon al %2$s</string>
     <string name="notice_display_name_changed_from">%1$s ŝanĝis sian vidigan nomon de %2$s al %3$s</string>
@@ -62,11 +60,6 @@
     <string name="medium_email">Retpoŝtadreso</string>
     <string name="medium_phone_number">Telefonnumero</string>
 
-    <string name="reply_to_an_image">sendis bildon.</string>
-    <string name="reply_to_a_video">sendis filmon.</string>
-    <string name="reply_to_an_audio_file">sendis sondosieron.</string>
-    <string name="reply_to_a_file">sendis dosieron.</string>
-
     <string name="room_displayname_invite_from">Invito de %s</string>
     <string name="room_displayname_room_invite">Ĉambra invito</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml
index 56cbe6ace5..35b7bfc829 100644
--- a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml
@@ -73,13 +73,6 @@
 
     <string name="summary_user_sent_sticker">%1$s envió una calcomanía.</string>
 
-    <string name="message_reply_to_prefix">En respuesta a</string>
-
-    <string name="reply_to_an_image">envió una imagen.</string>
-    <string name="reply_to_a_video">envió un video.</string>
-    <string name="reply_to_an_audio_file">envió un archivo de audio.</string>
-    <string name="reply_to_a_file">envió un archivo.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Invitación de %s</string>
     <string name="room_displayname_room_invite">Invitación de Sala</string>
diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml
index 69f02d2ef4..3c019b3b80 100644
--- a/matrix-sdk-android/src/main/res/values-es/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-es/strings.xml
@@ -73,13 +73,6 @@
 
     <string name="summary_user_sent_sticker">%1$s envió una pegatina.</string>
 
-    <string name="message_reply_to_prefix">En respuesta a</string>
-
-    <string name="reply_to_an_image">envió una imagen.</string>
-    <string name="reply_to_a_video">envió un vídeo.</string>
-    <string name="reply_to_an_audio_file">envió un archivo de audio.</string>
-    <string name="reply_to_a_file">envió un archivo.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Invitación de %s</string>
     <string name="room_displayname_room_invite">Invitación a Sala</string>
diff --git a/matrix-sdk-android/src/main/res/values-et/strings.xml b/matrix-sdk-android/src/main/res/values-et/strings.xml
index 3a5a1ff767..2536500247 100644
--- a/matrix-sdk-android/src/main/res/values-et/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-et/strings.xml
@@ -50,8 +50,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Ei õnnestu dekrüptida: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Sõnumi saatja seade ei ole selle sõnumi jaoks saatnud dekrüptimisvõtmeid.</string>
 
-    <string name="message_reply_to_prefix">Vastuseks kasutajale</string>
-
     <string name="could_not_redact">Ei saanud muuta sõnumit</string>
     <string name="unable_to_send_message">Sõnumi saatmine ei õnnestunud</string>
 
@@ -67,11 +65,6 @@
     <string name="medium_email">E-posti aadress</string>
     <string name="medium_phone_number">Telefoninumber</string>
 
-    <string name="reply_to_an_image">saatis pildi.</string>
-    <string name="reply_to_a_video">saatis video.</string>
-    <string name="reply_to_an_audio_file">saatis helifaili.</string>
-    <string name="reply_to_a_file">saatis faili.</string>
-
     <string name="room_displayname_invite_from">Kutse kasutajalt %s</string>
     <string name="room_displayname_room_invite">Kutse jututuppa</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-eu/strings.xml b/matrix-sdk-android/src/main/res/values-eu/strings.xml
index 7938db3cbd..1a5c81fe5e 100644
--- a/matrix-sdk-android/src/main/res/values-eu/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-eu/strings.xml
@@ -63,13 +63,6 @@
 
     <string name="summary_user_sent_sticker">%1$s erabiltzaileak eranskailu bat bidali du.</string>
 
-    <string name="message_reply_to_prefix">Honi erantzunez</string>
-
-    <string name="reply_to_an_image">irudi bat bidali du.</string>
-    <string name="reply_to_a_video">bideo bat bidali du.</string>
-    <string name="reply_to_an_audio_file">audio fitxategi bat bidali du.</string>
-    <string name="reply_to_a_file">fitxategi bat bidali du.</string>
-
     <string name="room_displayname_invite_from">%s gelarako gonbidapena</string>
     <string name="room_displayname_room_invite">Gela gonbidapena</string>
     <string name="room_displayname_two_members">%1$s eta %2$s</string>
diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml
index 7addf22ca8..18d8578e54 100644
--- a/matrix-sdk-android/src/main/res/values-fa/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml
@@ -51,8 +51,6 @@
     <string name="notice_crypto_unable_to_decrypt">** ناتوان در رمزگشایی: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">دستگاه فرستنده، کلیدهای این پیام را برایمان نفرستاده است.</string>
 
-    <string name="message_reply_to_prefix">در پاسخ به</string>
-
     <string name="unable_to_send_message">ناتوان در فرستادن پیام</string>
 
     <string name="message_failed_to_upload">شکست در بارگذاری تصویر</string>
@@ -67,11 +65,6 @@
     <string name="medium_email">نشانی رایانامه</string>
     <string name="medium_phone_number">شماره تلفن</string>
 
-    <string name="reply_to_an_image">تصویری فرستاد.</string>
-    <string name="reply_to_a_video">ویدیویی فرستاد.</string>
-    <string name="reply_to_an_audio_file">پرونده‌ای صوتی فرستاد.</string>
-    <string name="reply_to_a_file">پرونده‌ای فرستاد.</string>
-
     <string name="room_displayname_invite_from">دعوت از %s</string>
     <string name="room_displayname_room_invite">دعوت اتاق</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-fi/strings.xml b/matrix-sdk-android/src/main/res/values-fi/strings.xml
index 06820183fd..078769942c 100644
--- a/matrix-sdk-android/src/main/res/values-fi/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-fi/strings.xml
@@ -70,13 +70,6 @@
 
     <string name="summary_user_sent_sticker">%1$s lähetti tarran.</string>
 
-    <string name="message_reply_to_prefix">Vastauksena käyttäjälle</string>
-
-    <string name="reply_to_an_image">oli lähettänyt kuvan.</string>
-    <string name="reply_to_a_video">lähetti videon.</string>
-    <string name="reply_to_an_audio_file">lähetti äänitiedoston.</string>
-    <string name="reply_to_a_file">lähetti tiedoston.</string>
-
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="one">%1$s ja yksi muu</item>
         <item quantity="other">%1$s ja %2$d muuta</item>
diff --git a/matrix-sdk-android/src/main/res/values-fr/strings.xml b/matrix-sdk-android/src/main/res/values-fr/strings.xml
index a744c35b99..aad3bd1afb 100644
--- a/matrix-sdk-android/src/main/res/values-fr/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-fr/strings.xml
@@ -63,13 +63,6 @@
 
     <string name="summary_user_sent_sticker">%1$s a envoyé un sticker.</string>
 
-    <string name="message_reply_to_prefix">En réponse à</string>
-
-    <string name="reply_to_an_image">a envoyé une image.</string>
-    <string name="reply_to_a_video">a envoyé une vidéo.</string>
-    <string name="reply_to_an_audio_file">a envoyé un fichier audio.</string>
-    <string name="reply_to_a_file">a envoyé un fichier.</string>
-
     <string name="room_displayname_invite_from">Invitation de %s</string>
     <string name="room_displayname_room_invite">Invitation au salon</string>
     <string name="room_displayname_empty_room">Salon vide</string>
diff --git a/matrix-sdk-android/src/main/res/values-gl/strings.xml b/matrix-sdk-android/src/main/res/values-gl/strings.xml
index 907730f154..77868e7df3 100644
--- a/matrix-sdk-android/src/main/res/values-gl/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-gl/strings.xml
@@ -50,8 +50,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Imposíbel descifrar: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">O dispositivo do que envía non enviou as chaves desta mensaxe.</string>
 
-    <string name="message_reply_to_prefix">Respondéndolle a</string>
-
     <string name="could_not_redact">Non se puido redactar</string>
     <string name="unable_to_send_message">Non foi posíbel enviar a mensaxe</string>
 
@@ -64,11 +62,6 @@
 
     <string name="medium_phone_number">Número de teléfono</string>
 
-    <string name="reply_to_an_image">Responder a</string>
-    <string name="reply_to_a_video">enviar un vídeo.</string>
-    <string name="reply_to_an_audio_file">enviar un ficheiro de son.</string>
-    <string name="reply_to_a_file">enviar un ficheiro.</string>
-
     <string name="room_displayname_two_members">%1$s e %2$s</string>
 
 
diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml
index 03d52bef44..35f35eaecd 100644
--- a/matrix-sdk-android/src/main/res/values-hu/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml
@@ -62,13 +62,6 @@
 
     <string name="summary_user_sent_sticker">%1$s küldött egy matricát.</string>
 
-    <string name="message_reply_to_prefix">Válasz erre:</string>
-
-    <string name="reply_to_an_image">képet küldött.</string>
-    <string name="reply_to_a_video">videót küldött.</string>
-    <string name="reply_to_an_audio_file">hangfájlt küldött.</string>
-    <string name="reply_to_a_file">fájlt küldött.</string>
-
     <string name="room_displayname_invite_from">Meghívó tőle: %s</string>
     <string name="room_displayname_room_invite">Meghívó egy szobába</string>
     <string name="room_displayname_two_members">%1$s és %2$s</string>
diff --git a/matrix-sdk-android/src/main/res/values-is/strings.xml b/matrix-sdk-android/src/main/res/values-is/strings.xml
index 01954ae2b4..ecf19edb8a 100644
--- a/matrix-sdk-android/src/main/res/values-is/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-is/strings.xml
@@ -24,7 +24,6 @@
 
     <string name="notice_avatar_changed_too">(einnig var skipt um auðkennismynd)</string>
     <string name="notice_crypto_unable_to_decrypt">** Mistókst að afkóða: %s **</string>
-    <string name="message_reply_to_prefix">Sem svar til</string>
 
     <string name="unable_to_send_message">Gat ekki sent skilaboð</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml
index ec86122313..42328b836f 100644
--- a/matrix-sdk-android/src/main/res/values-it/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-it/strings.xml
@@ -62,13 +62,6 @@
 
     <string name="summary_user_sent_sticker">%1$s ha inviato un adesivo.</string>
 
-    <string name="message_reply_to_prefix">In risposta a</string>
-
-    <string name="reply_to_an_image">inviata un\'immagine.</string>
-    <string name="reply_to_a_video">inviato un video.</string>
-    <string name="reply_to_an_audio_file">inviato un file audio.</string>
-    <string name="reply_to_a_file">inviato un file.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Invito da %s</string>
     <string name="room_displayname_room_invite">Invito nella stanza</string>
diff --git a/matrix-sdk-android/src/main/res/values-ja/strings.xml b/matrix-sdk-android/src/main/res/values-ja/strings.xml
index b72d1a13ca..366c743494 100644
--- a/matrix-sdk-android/src/main/res/values-ja/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ja/strings.xml
@@ -56,8 +56,6 @@
     <string name="notice_crypto_unable_to_decrypt">** 解読できません: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">送信者の端末からこのメッセージのキーが送信されていません。</string>
 
-    <string name="message_reply_to_prefix">に返信</string>
-
     <string name="could_not_redact">修正できませんでした</string>
     <string name="unable_to_send_message">メッセージを送信できません</string>
 
@@ -73,9 +71,4 @@
     <string name="medium_email">メールアドレス</string>
     <string name="medium_phone_number">電話番号</string>
 
-    <string name="reply_to_an_image">画像を送信しました。</string>
-    <string name="reply_to_a_video">動画を送りました。</string>
-    <string name="reply_to_an_audio_file">音声ファイルを送信しました。</string>
-    <string name="reply_to_a_file">ファイルを送信しました。</string>
-
 </resources>
diff --git a/matrix-sdk-android/src/main/res/values-ko/strings.xml b/matrix-sdk-android/src/main/res/values-ko/strings.xml
index 68e94bb641..88c5e7d618 100644
--- a/matrix-sdk-android/src/main/res/values-ko/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ko/strings.xml
@@ -52,8 +52,6 @@
     <string name="notice_crypto_unable_to_decrypt">** 암호를 복호화할 수 없음: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">발신인의 기기에서 이 메시지의 키를 보내지 않았습니다.</string>
 
-    <string name="message_reply_to_prefix">관련 대화</string>
-
     <string name="could_not_redact">검열할 수 없습니다</string>
     <string name="unable_to_send_message">메시지를 보낼 수 없습니다</string>
 
@@ -69,11 +67,6 @@
     <string name="medium_email">이메일 주소</string>
     <string name="medium_phone_number">전화번호</string>
 
-    <string name="reply_to_an_image">사진을 보냈습니다.</string>
-    <string name="reply_to_a_video">동영상을 보냈습니다.</string>
-    <string name="reply_to_an_audio_file">오디오 파일을 보냈습니다.</string>
-    <string name="reply_to_a_file">파일을 보냈습니다.</string>
-
     <string name="room_displayname_invite_from">%s에서 초대함</string>
     <string name="room_displayname_room_invite">방 초대</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-nl/strings.xml b/matrix-sdk-android/src/main/res/values-nl/strings.xml
index d08b3c7845..22eb61f109 100644
--- a/matrix-sdk-android/src/main/res/values-nl/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-nl/strings.xml
@@ -71,13 +71,6 @@
 
     <string name="summary_user_sent_sticker">%1$s heeft een sticker gestuurd.</string>
 
-    <string name="message_reply_to_prefix">Als antwoord op</string>
-
-    <string name="reply_to_an_image">heeft een afbeelding gestuurd.</string>
-    <string name="reply_to_a_video">heeft een video gestuurd.</string>
-    <string name="reply_to_an_audio_file">heeft een audiobestand gestuurd.</string>
-    <string name="reply_to_a_file">heeft een bestand gestuurd.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Uitnodiging van %s</string>
     <string name="room_displayname_room_invite">Gespreksuitnodiging</string>
diff --git a/matrix-sdk-android/src/main/res/values-nn/strings.xml b/matrix-sdk-android/src/main/res/values-nn/strings.xml
index edc50a5a0e..601cf4c9df 100644
--- a/matrix-sdk-android/src/main/res/values-nn/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-nn/strings.xml
@@ -49,8 +49,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Fekk ikkje til å dekryptera: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Avsendareiningi hev ikkje sendt oss nyklane fyr denna meldingi.</string>
 
-    <string name="message_reply_to_prefix">Som svar til</string>
-
     <string name="could_not_redact">Kunde ikkje gjera um</string>
     <string name="unable_to_send_message">Fekk ikkje å senda meldingi</string>
 
@@ -64,11 +62,6 @@
     <string name="medium_email">Epostadresse</string>
     <string name="medium_phone_number">Telefonnummer</string>
 
-    <string name="reply_to_an_image">sende eit bilæte.</string>
-    <string name="reply_to_a_video">sende ein video.</string>
-    <string name="reply_to_an_audio_file">sende ei ljodfil.</string>
-    <string name="reply_to_a_file">sende ei fil.</string>
-
     <string name="room_displayname_invite_from">Innbjoding frå %s</string>
     <string name="room_displayname_room_invite">Rominnbjoding</string>
     <string name="room_displayname_two_members">%1$s og %2$s</string>
diff --git a/matrix-sdk-android/src/main/res/values-pl/strings.xml b/matrix-sdk-android/src/main/res/values-pl/strings.xml
index 4e1d256788..dc380516b7 100644
--- a/matrix-sdk-android/src/main/res/values-pl/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-pl/strings.xml
@@ -42,7 +42,6 @@
     <string name="notice_room_withdraw">%1$s wycofał(a) zaproszenie %2$s</string>
     <string name="notice_answered_call">%s odebrał(a) połączenie.</string>
     <string name="notice_avatar_changed_too">(awatar też został zmieniony)</string>
-    <string name="message_reply_to_prefix">W odpowiedzi do</string>
 
     <string name="room_displayname_invite_from">Zaproszenie od %s</string>
     <string name="room_displayname_room_invite">Zaproszenie do pokoju</string>
@@ -76,11 +75,6 @@
     <string name="could_not_redact">Nie można zredagować</string>
     <string name="room_error_join_failed_empty_room">Obecnie nie jest możliwe ponowne dołączenie do pustego pokoju.</string>
 
-    <string name="reply_to_an_image">wyślij zdjęcie.</string>
-    <string name="reply_to_a_video">wyślij wideo.</string>
-    <string name="reply_to_an_audio_file">wyślij plik audio.</string>
-    <string name="reply_to_a_file">wyślij plik.</string>
-
     <string name="notice_event_redacted">Wiadomość usunięta</string>
     <string name="notice_event_redacted_by">Wiadomość usunięta przez %1$s</string>
     <string name="notice_event_redacted_with_reason">Wiadomość usunięta [powód: %1$s]</string>
diff --git a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml
index 17e7ae33a1..a573c659a6 100644
--- a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml
@@ -74,13 +74,6 @@
 
     <string name="summary_user_sent_sticker">%1$s enviou um sticker.</string>
 
-    <string name="message_reply_to_prefix">Em resposta a</string>
-
-    <string name="reply_to_an_image">enviou uma imagem.</string>
-    <string name="reply_to_a_video">enviou um vídeo.</string>
-    <string name="reply_to_an_audio_file">enviou um arquivo de áudio.</string>
-    <string name="reply_to_a_file">enviou um arquivo.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Convite de %s</string>
     <string name="room_displayname_room_invite">Convite para sala</string>
diff --git a/matrix-sdk-android/src/main/res/values-ru/strings.xml b/matrix-sdk-android/src/main/res/values-ru/strings.xml
index 3e20353b7d..bd0dcef3dd 100644
--- a/matrix-sdk-android/src/main/res/values-ru/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ru/strings.xml
@@ -73,13 +73,6 @@
 
     <string name="summary_user_sent_sticker">%1$s отправил стикер.</string>
 
-    <string name="message_reply_to_prefix">В ответ на</string>
-
-    <string name="reply_to_an_image">отправил изображение.</string>
-    <string name="reply_to_a_video">отправил видео.</string>
-    <string name="reply_to_an_audio_file">отправил аудиофайл.</string>
-    <string name="reply_to_a_file">отправил файл.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Приглашение от %s</string>
     <string name="room_displayname_room_invite">Приглашение в комнату</string>
diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml
index c6eb6b896b..8aec8fccf9 100644
--- a/matrix-sdk-android/src/main/res/values-sk/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml
@@ -62,13 +62,6 @@
 
     <string name="summary_user_sent_sticker">%1$s poslal nálepku.</string>
 
-    <string name="message_reply_to_prefix">Odpoveď na</string>
-
-    <string name="reply_to_an_image">odoslal obrázok.</string>
-    <string name="reply_to_a_video">odoslal video.</string>
-    <string name="reply_to_an_audio_file">odoslal zvukový súbor.</string>
-    <string name="reply_to_a_file">Odoslal súbor.</string>
-
     <string name="room_displayname_invite_from">Pozvanie od %s</string>
     <string name="room_displayname_room_invite">Pozvanie do miestnosti</string>
     <string name="room_displayname_two_members">%1$s a %2$s</string>
diff --git a/matrix-sdk-android/src/main/res/values-sq/strings.xml b/matrix-sdk-android/src/main/res/values-sq/strings.xml
index 853d4729af..e63e28288f 100644
--- a/matrix-sdk-android/src/main/res/values-sq/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-sq/strings.xml
@@ -34,8 +34,6 @@
     <string name="notice_crypto_unable_to_decrypt">** S’arrihet të shfshehtëzohet: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Pajisja e dërguesit nuk na ka dërguar kyçet për këtë mesazh.</string>
 
-    <string name="message_reply_to_prefix">Në përgjigje të</string>
-
     <string name="could_not_redact">S’u redaktua dot</string>
     <string name="unable_to_send_message">S’arrihet të dërgohet mesazh</string>
 
@@ -51,11 +49,6 @@
     <string name="medium_email">Adresë email</string>
     <string name="medium_phone_number">Numër telefoni</string>
 
-    <string name="reply_to_an_image">dërgoi një figurë.</string>
-    <string name="reply_to_a_video">dërgoi një video.</string>
-    <string name="reply_to_an_audio_file">dërgoi një kartelë audio.</string>
-    <string name="reply_to_a_file">dërgoi një kartelë.</string>
-
     <string name="room_displayname_invite_from">Ftesë nga %s</string>
     <string name="room_displayname_room_invite">Ftesë Dhome</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-uk/strings.xml b/matrix-sdk-android/src/main/res/values-uk/strings.xml
index bf83e39d72..eb5071f190 100644
--- a/matrix-sdk-android/src/main/res/values-uk/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-uk/strings.xml
@@ -56,8 +56,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Неможливо розшифрувати: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">Пристрій відправника не надіслав нам ключ для цього повідомлення.</string>
 
-    <string name="message_reply_to_prefix">У відповідь на</string>
-
     <string name="could_not_redact">Неможливо відредагувати</string>
     <string name="unable_to_send_message">Не вдалося надіслати повідомлення</string>
 
@@ -71,11 +69,6 @@
     <string name="medium_email">Адреса електронної пошти</string>
     <string name="medium_phone_number">Номер телефону</string>
 
-    <string name="reply_to_an_image">надіслав зображення.</string>
-    <string name="reply_to_a_video">надіслав відео.</string>
-    <string name="reply_to_an_audio_file">надіслав аудіо файл.</string>
-    <string name="reply_to_a_file">надіслав файл.</string>
-
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="one">%1$s та 1 інший</item>
         <item quantity="few">%1$s та %2$d інші</item>
diff --git a/matrix-sdk-android/src/main/res/values-vls/strings.xml b/matrix-sdk-android/src/main/res/values-vls/strings.xml
index dad88788e4..5c9132ed35 100644
--- a/matrix-sdk-android/src/main/res/values-vls/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-vls/strings.xml
@@ -50,8 +50,6 @@
     <string name="notice_crypto_unable_to_decrypt">** Kun nie ountsleuteln: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">’t Toestel van den afzender èt geen sleutels vo da bericht hier gesteurd.</string>
 
-    <string name="message_reply_to_prefix">Als antwoord ip</string>
-
     <string name="could_not_redact">Kosteg nie verwyderd wordn</string>
     <string name="unable_to_send_message">Kosteg ’t bericht nie verzendn</string>
 
@@ -67,11 +65,6 @@
     <string name="medium_email">E-mailadresse</string>
     <string name="medium_phone_number">Telefongnumero</string>
 
-    <string name="reply_to_an_image">èt e fotootje gesteurd.</string>
-    <string name="reply_to_a_video">èt e filmtje gesteurd.</string>
-    <string name="reply_to_an_audio_file">èt e geluudsfragment gesteurd.</string>
-    <string name="reply_to_a_file">èt e bestand gesteurd.</string>
-
     <string name="room_displayname_invite_from">Uutnodigienge van %s</string>
     <string name="room_displayname_room_invite">Gespreksuutnodigienge</string>
 
diff --git a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml
index 0c0953c92d..48dbd27a1b 100644
--- a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml
@@ -63,13 +63,6 @@
     <string name="summary_message">%1$s:%2$s</string>
     <string name="summary_user_sent_sticker">%1$s 发送了一张贴纸。</string>
 
-    <string name="reply_to_an_image">发送了一张图片。</string>
-    <string name="reply_to_a_video">发送了一个视频。</string>
-    <string name="reply_to_an_audio_file">发送了一段音频。</string>
-    <string name="reply_to_a_file">发送了一个文件。</string>
-
-    <string name="message_reply_to_prefix">回复</string>
-
     <string name="room_displayname_empty_room">空聊天室</string>
     <string name="room_displayname_invite_from">来自 %s 的邀请</string>
     <string name="room_displayname_room_invite">聊天室邀请</string>
diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml
index ca2fd79aa2..f3da62dccc 100644
--- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml
@@ -62,13 +62,6 @@
 
     <string name="summary_user_sent_sticker">%1$s 傳送了一張貼圖。</string>
 
-    <string name="message_reply_to_prefix">回覆</string>
-
-    <string name="reply_to_an_image">傳送了圖片。</string>
-    <string name="reply_to_a_video">傳送了影片。</string>
-    <string name="reply_to_an_audio_file">傳送了音訊檔案。</string>
-    <string name="reply_to_a_file">傳送了檔案。</string>
-
     <string name="room_displayname_invite_from">來自%s 的邀請</string>
     <string name="room_displayname_room_invite">聊天室邀請</string>
     <string name="room_displayname_two_members">%1$s 和 %2$s</string>
diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml
index 9b7fa01eaf..0dc64c1b4b 100644
--- a/matrix-sdk-android/src/main/res/values/strings.xml
+++ b/matrix-sdk-android/src/main/res/values/strings.xml
@@ -112,7 +112,6 @@
     <string name="notice_crypto_error_unkwown_inbound_session_id">The sender\'s device has not sent us the keys for this message.</string>
 
     <!-- Messages -->
-    <string name="message_reply_to_prefix">In reply to</string>
 
     <!-- Room Screen -->
     <string name="could_not_redact">Could not redact</string>
@@ -139,12 +138,6 @@
     <string name="medium_email">Email address</string>
     <string name="medium_phone_number">Phone number</string>
 
-    <!-- Reply to -->
-    <string name="reply_to_an_image">sent an image.</string>
-    <string name="reply_to_a_video">sent a video.</string>
-    <string name="reply_to_an_audio_file">sent an audio file.</string>
-    <string name="reply_to_a_file">sent a file.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Invite from %s</string>
     <string name="room_displayname_room_invite">Room Invite</string>

From 0cfd33fc8b8133a24c17e1f748ab5f33cd4467ee Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Sat, 4 Jul 2020 11:15:20 +0200
Subject: [PATCH 19/28] Typo

---
 CHANGES.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGES.md b/CHANGES.md
index c5cae43f67..3fa394c97b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,7 +18,7 @@ SDK API changes ⚠️:
  - 
 
 Build 🧱:
- - Fix lint false-positive about WorkManger (#1012)
+ - Fix lint false-positive about WorkManager (#1012)
  - Upgrade build-tools from 3.5.3 to 3.6.6
  - Upgrade gradle from 5.4.1 to 5.6.4
 

From b853397c0a21808bb9259c2755bbefb77c99c0d0 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Sat, 4 Jul 2020 12:10:17 +0200
Subject: [PATCH 20/28] Re-activate Wellknown support with updated UI (#1614)

---
 CHANGES.md                                    |  2 +-
 .../riotx/features/login/LoginFragment.kt     |  3 +++
 vector/src/main/res/layout/fragment_login.xml | 10 ++++++++++
 .../fragment_login_server_selection.xml       | 20 ++++---------------
 vector/src/main/res/values/strings.xml        |  9 +++++----
 5 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 3fa394c97b..a6bb5d6a29 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,7 +2,7 @@ Changes in Riot.imX 0.91.4 (2020-XX-XX)
 ===================================================
 
 Features ✨:
- -
+ - Re-activate Wellknown support with updated UI (#1614)
 
 Improvements 🙌:
  -
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt
index eaf0a3cc78..28c2299faa 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt
@@ -54,6 +54,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
 
     private var passwordShown = false
     private var isSignupMode = false
+
     // Temporary patch for https://github.com/vector-im/riotX-android/issues/1410,
     // waiting for https://github.com/matrix-org/synapse/issues/7576
     private var isNumericOnlyUserIdForbidden = false
@@ -138,6 +139,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
             loginServerIcon.isVisible = false
             loginTitle.text = getString(R.string.login_signin_matrix_id_title)
             loginNotice.text = getString(R.string.login_signin_matrix_id_notice)
+            loginPasswordNotice.isVisible = true
         } else {
             val resId = when (state.signMode) {
                 SignMode.Unknown            -> error("developer error")
@@ -165,6 +167,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
                     loginNotice.text = getString(R.string.login_server_other_text)
                 }
             }
+            loginPasswordNotice.isVisible = false
         }
     }
 
diff --git a/vector/src/main/res/layout/fragment_login.xml b/vector/src/main/res/layout/fragment_login.xml
index a35a60104d..8e7fc9e418 100644
--- a/vector/src/main/res/layout/fragment_login.xml
+++ b/vector/src/main/res/layout/fragment_login.xml
@@ -106,6 +106,16 @@
 
             </FrameLayout>
 
+            <TextView
+                android:id="@+id/loginPasswordNotice"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="start"
+                android:text="@string/login_signin_matrix_id_password_notice"
+                android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
+                android:visibility="gone"
+                tools:visibility="visible" />
+
             <androidx.constraintlayout.widget.ConstraintLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/vector/src/main/res/layout/fragment_login_server_selection.xml b/vector/src/main/res/layout/fragment_login_server_selection.xml
index f634456935..16465486a2 100644
--- a/vector/src/main/res/layout/fragment_login_server_selection.xml
+++ b/vector/src/main/res/layout/fragment_login_server_selection.xml
@@ -188,35 +188,23 @@
                 android:layout_marginTop="24dp"
                 android:text="@string/login_continue"
                 android:transitionName="loginSubmitTransition"
-                app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdNotice"
+                app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdSubmit"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" />
 
-            <TextView
-                android:id="@+id/loginServerIKnowMyIdNotice"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:gravity="start"
-                android:text="@string/login_connect_using_matrix_id_notice"
-                android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
-                android:visibility="gone"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" />
-
             <com.google.android.material.button.MaterialButton
                 android:id="@+id/loginServerIKnowMyIdSubmit"
                 style="@style/Style.Vector.Login.Button.Text"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
+                android:layout_marginTop="32dp"
+                android:layout_marginBottom="32dp"
                 android:text="@string/login_connect_using_matrix_id_submit"
-                android:visibility="gone"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@+id/loginServerIKnowMyIdNotice" />
+                app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" />
 
         </androidx.constraintlayout.widget.ConstraintLayout>
 
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index d8aad6f539..c3f0e9df41 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -1995,10 +1995,11 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
     </plurals>
 
     <string name="login_connect_using_matrix_id_notice">Alternatively, if you already have an account and you know your Matrix identifier and your password, you can use this method:</string>
-    <string name="login_connect_using_matrix_id_submit">Sign in with my Matrix identifier</string>
-    <string name="login_signin_matrix_id_title">Sign in</string>
-    <string name="login_signin_matrix_id_notice">Enter your identifier and your password</string>
-    <string name="login_signin_matrix_id_hint">User identifier</string>
+    <string name="login_connect_using_matrix_id_submit">Sign in with Matrix ID</string>
+    <string name="login_signin_matrix_id_title">Sign in with Matrix ID</string>
+    <string name="login_signin_matrix_id_notice">If you set up an account on a homeserver, use your Matrix ID (e.g. @user:domain.com) and password below.</string>
+    <string name="login_signin_matrix_id_hint">Matrix ID</string>
+    <string name="login_signin_matrix_id_password_notice">If you don’t know your password, go back to reset it.</string>
     <string name="login_signin_matrix_id_error_invalid_matrix_id">This is not a valid user identifier. Expected format: \'@user:homeserver.org\'</string>
     <string name="autodiscover_well_known_error">Unable to find a valid homeserver. Please check your identifier</string>
 

From 2a68c8d08be9233b6625ce37f75a9ae6b0e74ed2 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 6 Jul 2020 10:49:03 +0200
Subject: [PATCH 21/28] Simplify the server selection screen: remove the
 "Continue" button

---
 .../riotx/features/login/LoginActivity.kt     |  1 +
 .../riotx/features/login/LoginFragment.kt     |  1 +
 .../login/LoginServerSelectionFragment.kt     | 38 ++-----------------
 .../LoginSignUpSignInSelectionFragment.kt     |  1 +
 .../riotx/features/login/LoginViewModel.kt    | 15 +++++++-
 .../riotx/features/login/LoginViewState.kt    |  2 +-
 .../vector/riotx/features/login/ServerType.kt |  1 +
 .../res/drawable/bg_login_server_selector.xml |  1 +
 .../fragment_login_server_selection.xml       | 24 +++---------
 9 files changed, 29 insertions(+), 55 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
index 86be00702c..1eebf532e7 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
@@ -235,6 +235,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
             ServerType.Other     -> addFragmentToBackstack(R.id.loginFragmentContainer,
                     LoginServerUrlFormFragment::class.java,
                     option = commonOption)
+            ServerType.Unknown   -> Unit /* Should not happen */
         }
     }
 
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt
index 28c2299faa..ef8281fa89 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt
@@ -166,6 +166,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
                     loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl())
                     loginNotice.text = getString(R.string.login_server_other_text)
                 }
+                ServerType.Unknown   -> Unit /* Should not happen */
             }
             loginPasswordNotice.isVisible = false
         }
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt
index 79c5c7d024..3a1bba7f11 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt
@@ -19,7 +19,6 @@ package im.vector.riotx.features.login
 import android.os.Bundle
 import android.view.View
 import butterknife.OnClick
-import com.airbnb.mvrx.withState
 import im.vector.riotx.R
 import im.vector.riotx.core.utils.openUrlInChromeCustomTab
 import kotlinx.android.synthetic.main.fragment_login_server_selection.*
@@ -40,11 +39,7 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
     }
 
     private fun updateSelectedChoice(state: LoginViewState) {
-        state.serverType.let {
-            loginServerChoiceMatrixOrg.isChecked = it == ServerType.MatrixOrg
-            loginServerChoiceModular.isChecked = it == ServerType.Modular
-            loginServerChoiceOther.isChecked = it == ServerType.Other
-        }
+        loginServerChoiceMatrixOrg.isChecked = state.serverType == ServerType.MatrixOrg
     }
 
     private fun initTextViews() {
@@ -61,42 +56,17 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
 
     @OnClick(R.id.loginServerChoiceMatrixOrg)
     fun selectMatrixOrg() {
-        if (loginServerChoiceMatrixOrg.isChecked) {
-            // Consider this is a submit
-            submit()
-        } else {
-            loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg))
-        }
+        loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg))
     }
 
     @OnClick(R.id.loginServerChoiceModular)
     fun selectModular() {
-        if (loginServerChoiceModular.isChecked) {
-            // Consider this is a submit
-            submit()
-        } else {
-            loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Modular))
-        }
+        loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Modular))
     }
 
     @OnClick(R.id.loginServerChoiceOther)
     fun selectOther() {
-        if (loginServerChoiceOther.isChecked) {
-            // Consider this is a submit
-            submit()
-        } else {
-            loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other))
-        }
-    }
-
-    @OnClick(R.id.loginServerSubmit)
-    fun submit() = withState(loginViewModel) { state ->
-        if (state.serverType == ServerType.MatrixOrg) {
-            // Request login flow here
-            loginViewModel.handle(LoginAction.UpdateHomeServer(getString(R.string.matrix_org_server_url)))
-        } else {
-            loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnServerSelectionDone))
-        }
+        loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other))
     }
 
     @OnClick(R.id.loginServerIKnowMyIdSubmit)
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt
index 427ad99b41..6ac5993f30 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginSignUpSignInSelectionFragment.kt
@@ -49,6 +49,7 @@ open class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLo
                 loginSignupSigninTitle.text = getString(R.string.login_server_other_title)
                 loginSignupSigninText.text = getString(R.string.login_connect_to, state.homeServerUrl.toReducedUrl())
             }
+            ServerType.Unknown   -> Unit /* Should not happen */
         }
     }
 
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
index fc970297d1..47736ec047 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
@@ -321,7 +321,7 @@ class LoginViewModel @AssistedInject constructor(
             LoginAction.ResetHomeServerType -> {
                 setState {
                     copy(
-                            serverType = ServerType.MatrixOrg
+                            serverType = ServerType.Unknown
                     )
                 }
             }
@@ -390,6 +390,15 @@ class LoginViewModel @AssistedInject constructor(
                     serverType = action.serverType
             )
         }
+
+        when (action.serverType) {
+            ServerType.Unknown   -> Unit /* Should not happen */
+            ServerType.MatrixOrg ->
+                // Request login flow here
+                handle(LoginAction.UpdateHomeServer(stringProvider.getString(R.string.matrix_org_server_url)))
+            ServerType.Modular,
+            ServerType.Other     -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone)
+        }.exhaustive
     }
 
     private fun handleInitWith(action: LoginAction.InitWith) {
@@ -682,7 +691,9 @@ class LoginViewModel @AssistedInject constructor(
                 _viewEvents.post(LoginViewEvents.Failure(failure))
                 setState {
                     copy(
-                            asyncHomeServerLoginFlowRequest = Uninitialized
+                            asyncHomeServerLoginFlowRequest = Uninitialized,
+                            // If we were trying to retrieve matrix.org login flow, also reset the serverType
+                            serverType = if (serverType == ServerType.MatrixOrg) ServerType.Unknown else serverType
                     )
                 }
             }
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt
index 944d1f7d82..655966ce25 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt
@@ -35,7 +35,7 @@ data class LoginViewState(
 
         // User choices
         @PersistState
-        val serverType: ServerType = ServerType.MatrixOrg,
+        val serverType: ServerType = ServerType.Unknown,
         @PersistState
         val signMode: SignMode = SignMode.Unknown,
         @PersistState
diff --git a/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt b/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt
index 4c7007c137..50dfee19f0 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/ServerType.kt
@@ -17,6 +17,7 @@
 package im.vector.riotx.features.login
 
 enum class ServerType {
+    Unknown,
     MatrixOrg,
     Modular,
     Other
diff --git a/vector/src/main/res/drawable/bg_login_server_selector.xml b/vector/src/main/res/drawable/bg_login_server_selector.xml
index 57be1e5d54..3fcc4e006a 100644
--- a/vector/src/main/res/drawable/bg_login_server_selector.xml
+++ b/vector/src/main/res/drawable/bg_login_server_selector.xml
@@ -2,6 +2,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:drawable="@drawable/bg_login_server_checked" android:state_checked="true" />
+    <item android:drawable="@drawable/bg_login_server_checked" android:state_pressed="true" />
 
     <item android:drawable="@drawable/bg_login_server" />
 
diff --git a/vector/src/main/res/layout/fragment_login_server_selection.xml b/vector/src/main/res/layout/fragment_login_server_selection.xml
index 16465486a2..de7bf65cbb 100644
--- a/vector/src/main/res/layout/fragment_login_server_selection.xml
+++ b/vector/src/main/res/layout/fragment_login_server_selection.xml
@@ -43,6 +43,7 @@
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toBottomOf="@+id/loginServerTitle" />
 
+            <!-- Use a CheckableConstraintLayout to keep the pressed state when retrieving login flow -->
             <im.vector.riotx.core.platform.CheckableConstraintLayout
                 android:id="@+id/loginServerChoiceMatrixOrg"
                 android:layout_width="match_parent"
@@ -84,7 +85,7 @@
 
             </im.vector.riotx.core.platform.CheckableConstraintLayout>
 
-            <im.vector.riotx.core.platform.CheckableConstraintLayout
+            <androidx.constraintlayout.widget.ConstraintLayout
                 android:id="@+id/loginServerChoiceModular"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -135,9 +136,9 @@
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintTop_toTopOf="@+id/loginServerChoiceModularText" />
 
-            </im.vector.riotx.core.platform.CheckableConstraintLayout>
+            </androidx.constraintlayout.widget.ConstraintLayout>
 
-            <im.vector.riotx.core.platform.CheckableConstraintLayout
+            <androidx.constraintlayout.widget.ConstraintLayout
                 android:id="@+id/loginServerChoiceOther"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -178,20 +179,7 @@
                     app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOtherTitle" />
 
-            </im.vector.riotx.core.platform.CheckableConstraintLayout>
-
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/loginServerSubmit"
-                style="@style/Style.Vector.Login.Button"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:text="@string/login_continue"
-                android:transitionName="loginSubmitTransition"
-                app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdSubmit"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" />
+            </androidx.constraintlayout.widget.ConstraintLayout>
 
             <com.google.android.material.button.MaterialButton
                 android:id="@+id/loginServerIKnowMyIdSubmit"
@@ -204,7 +192,7 @@
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" />
+                app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" />
 
         </androidx.constraintlayout.widget.ConstraintLayout>
 

From e7f13c9efec817a3a8622610554a5fecce10abb6 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Sun, 5 Jul 2020 23:41:19 +0200
Subject: [PATCH 22/28]  Handle JobCancellationException

---
 .../im/vector/riotx/features/login/AbstractLoginFragment.kt    | 3 +++
 .../main/java/im/vector/riotx/features/login/LoginViewModel.kt | 3 ---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt
index 5927e5b117..90be21b6be 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/AbstractLoginFragment.kt
@@ -73,6 +73,9 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
 
     override fun showFailure(throwable: Throwable) {
         when (throwable) {
+            is Failure.Cancelled                      ->
+                /* Ignore this error, user has cancelled the action */
+                Unit
             is Failure.ServerError                    ->
                 if (throwable.error.code == MatrixError.M_FORBIDDEN
                         && throwable.httpCode == HttpsURLConnection.HTTP_FORBIDDEN /* 403 */) {
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
index 47736ec047..b7db9fd229 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
@@ -436,7 +436,6 @@ class LoginViewModel @AssistedInject constructor(
                 }
 
                 override fun onFailure(failure: Throwable) {
-                    // TODO Handled JobCancellationException
                     setState {
                         copy(
                                 asyncResetPassword = Fail(failure)
@@ -478,7 +477,6 @@ class LoginViewModel @AssistedInject constructor(
                 }
 
                 override fun onFailure(failure: Throwable) {
-                    // TODO Handled JobCancellationException
                     setState {
                         copy(
                                 asyncResetMailConfirmed = Fail(failure)
@@ -593,7 +591,6 @@ class LoginViewModel @AssistedInject constructor(
                         }
 
                         override fun onFailure(failure: Throwable) {
-                            // TODO Handled JobCancellationException
                             setState {
                                 copy(
                                         asyncLoginAction = Fail(failure)

From e859357c6aea56742978b02945ad82107dc8e9da Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 6 Jul 2020 13:49:39 +0200
Subject: [PATCH 23/28] Handle certificate error in case of Direct Login

---
 .../internal/auth/login/DirectLoginTask.kt    | 23 ++++-
 .../internal/wellknown/GetWellknownTask.kt    |  7 ++
 .../im/vector/riotx/core/utils/UrlUtils.kt    |  8 ++
 .../login/LoginServerUrlFormFragment.kt       |  3 +-
 .../riotx/features/login/LoginViewModel.kt    | 97 +++++++++++++------
 5 files changed, 104 insertions(+), 34 deletions(-)

diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt
index 22a921a094..51dbac2cc3 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/login/DirectLoginTask.kt
@@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.auth.login
 import dagger.Lazy
 import im.vector.matrix.android.api.auth.data.Credentials
 import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
+import im.vector.matrix.android.api.failure.Failure
 import im.vector.matrix.android.api.session.Session
 import im.vector.matrix.android.internal.auth.AuthAPI
 import im.vector.matrix.android.internal.auth.SessionCreator
@@ -27,6 +28,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated
 import im.vector.matrix.android.internal.network.RetrofitFactory
 import im.vector.matrix.android.internal.network.executeRequest
 import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
+import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException
 import im.vector.matrix.android.internal.task.Task
 import okhttp3.OkHttpClient
 import javax.inject.Inject
@@ -49,13 +51,28 @@ internal class DefaultDirectLoginTask @Inject constructor(
 
     override suspend fun execute(params: DirectLoginTask.Params): Session {
         val client = buildClient(params.homeServerConnectionConfig)
-        val authAPI = retrofitFactory.create(client, params.homeServerConnectionConfig.homeServerUri.toString())
+        val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString()
+
+        val authAPI = retrofitFactory.create(client, homeServerUrl)
                 .create(AuthAPI::class.java)
 
         val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName)
 
-        val credentials = executeRequest<Credentials>(null) {
-            apiCall = authAPI.login(loginParams)
+        val credentials = try {
+            executeRequest<Credentials>(null) {
+                apiCall = authAPI.login(loginParams)
+            }
+        } catch (throwable: Throwable) {
+            when (throwable) {
+                is UnrecognizedCertificateException -> {
+                    throw Failure.UnrecognizedCertificateFailure(
+                            homeServerUrl,
+                            throwable.fingerprint
+                    )
+                }
+                else                                ->
+                    throw throwable
+            }
         }
 
         return sessionCreator.createSession(credentials, params.homeServerConnectionConfig)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt
index 8ded737c64..b42aef5f88 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/wellknown/GetWellknownTask.kt
@@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated
 import im.vector.matrix.android.internal.network.RetrofitFactory
 import im.vector.matrix.android.internal.network.executeRequest
 import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
+import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException
 import im.vector.matrix.android.internal.session.homeserver.CapabilitiesAPI
 import im.vector.matrix.android.internal.session.identity.IdentityAuthAPI
 import im.vector.matrix.android.internal.task.Task
@@ -106,6 +107,12 @@ internal class DefaultGetWellknownTask @Inject constructor(
             }
         } catch (throwable: Throwable) {
             when (throwable) {
+                is UnrecognizedCertificateException        -> {
+                    throw Failure.UnrecognizedCertificateFailure(
+                            "https://$domain",
+                            throwable.fingerprint
+                    )
+                }
                 is Failure.NetworkConnection               -> {
                     WellknownResult.Ignore
                 }
diff --git a/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt b/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt
index 0361fc9d71..c26cd85dc7 100644
--- a/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt
+++ b/vector/src/main/java/im/vector/riotx/core/utils/UrlUtils.kt
@@ -37,3 +37,11 @@ internal fun String.ensureProtocol(): String {
         else                -> this
     }
 }
+
+internal fun String.ensureTrailingSlash(): String {
+    return when {
+        isEmpty()      -> this
+        !endsWith("/") -> "$this/"
+        else           -> this
+    }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt
index cb90ef2397..28331bc99e 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt
@@ -70,7 +70,7 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment()
                 loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_modular_hint)
                 loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_modular_notice)
             }
-            ServerType.Other   -> {
+            else               -> {
                 loginServerUrlFormIcon.isVisible = false
                 loginServerUrlFormTitle.text = getString(R.string.login_server_other_title)
                 loginServerUrlFormText.text = getString(R.string.login_connect_to_a_custom_server)
@@ -78,7 +78,6 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment()
                 loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_other_hint)
                 loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_other_notice)
             }
-            else               -> error("This fragment should not be displayed in matrix.org mode")
         }
     }
 
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
index b7db9fd229..a7c58f4b04 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
@@ -39,6 +39,7 @@ import im.vector.matrix.android.api.auth.registration.RegistrationResult
 import im.vector.matrix.android.api.auth.registration.RegistrationWizard
 import im.vector.matrix.android.api.auth.registration.Stage
 import im.vector.matrix.android.api.auth.wellknown.WellknownResult
+import im.vector.matrix.android.api.failure.Failure
 import im.vector.matrix.android.api.session.Session
 import im.vector.matrix.android.api.util.Cancelable
 import im.vector.riotx.R
@@ -47,6 +48,7 @@ import im.vector.riotx.core.extensions.configureAndStart
 import im.vector.riotx.core.extensions.exhaustive
 import im.vector.riotx.core.platform.VectorViewModel
 import im.vector.riotx.core.resources.StringProvider
+import im.vector.riotx.core.utils.ensureTrailingSlash
 import im.vector.riotx.features.call.WebRtcPeerConnectionManager
 import im.vector.riotx.features.notifications.PushRuleTriggerListener
 import im.vector.riotx.features.session.SessionListener
@@ -87,8 +89,12 @@ class LoginViewModel @AssistedInject constructor(
         }
     }
 
+    // Store the last action, to redo it after user has trusted the untrusted certificate
+    private var lastAction: LoginAction? = null
     private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
 
+    private val matrixOrgUrl = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
+
     val currentThreePid: String?
         get() = registrationWizard?.currentThreePid
 
@@ -111,8 +117,8 @@ class LoginViewModel @AssistedInject constructor(
             is LoginAction.UpdateServerType           -> handleUpdateServerType(action)
             is LoginAction.UpdateSignMode             -> handleUpdateSignMode(action)
             is LoginAction.InitWith                   -> handleInitWith(action)
-            is LoginAction.UpdateHomeServer           -> handleUpdateHomeserver(action)
-            is LoginAction.LoginOrRegister            -> handleLoginOrRegister(action)
+            is LoginAction.UpdateHomeServer           -> handleUpdateHomeserver(action).also { lastAction = action }
+            is LoginAction.LoginOrRegister            -> handleLoginOrRegister(action).also { lastAction = action }
             is LoginAction.LoginWithToken             -> handleLoginWithToken(action)
             is LoginAction.WebLoginSuccess            -> handleWebLoginSuccess(action)
             is LoginAction.ResetPassword              -> handleResetPassword(action)
@@ -126,10 +132,23 @@ class LoginViewModel @AssistedInject constructor(
     }
 
     private fun handleUserAcceptCertificate(action: LoginAction.UserAcceptCertificate) {
-        // It happen when we get the login flow, so alter the homeserver config and retrieve again the login flow
-        currentHomeServerConnectionConfig
-                ?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) }
-                ?.let { getLoginFlow(it) }
+        // It happen when we get the login flow, or during direct authentication.
+        // So alter the homeserver config and retrieve again the login flow
+        when (val finalLastAction = lastAction) {
+            is LoginAction.UpdateHomeServer ->
+                currentHomeServerConnectionConfig
+                        ?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) }
+                        ?.let { getLoginFlow(it) }
+            is LoginAction.LoginOrRegister  ->
+                handleDirectLogin(
+                        finalLastAction,
+                        HomeServerConnectionConfig.Builder()
+                                // Will be replaced by the task
+                                .withHomeServerUri("https://dummy.org")
+                                .withAllowedFingerPrints(listOf(action.fingerprint))
+                                .build()
+                )
+        }
     }
 
     private fun handleLoginWithToken(action: LoginAction.LoginWithToken) {
@@ -333,6 +352,7 @@ class LoginViewModel @AssistedInject constructor(
                             asyncHomeServerLoginFlowRequest = Uninitialized,
                             homeServerUrl = null,
                             loginMode = LoginMode.Unknown,
+                            serverType = ServerType.Unknown,
                             loginModeSupportedTypes = emptyList()
                     )
                 }
@@ -395,7 +415,7 @@ class LoginViewModel @AssistedInject constructor(
             ServerType.Unknown   -> Unit /* Should not happen */
             ServerType.MatrixOrg ->
                 // Request login flow here
-                handle(LoginAction.UpdateHomeServer(stringProvider.getString(R.string.matrix_org_server_url)))
+                handle(LoginAction.UpdateHomeServer(matrixOrgUrl))
             ServerType.Modular,
             ServerType.Other     -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone)
         }.exhaustive
@@ -492,23 +512,22 @@ class LoginViewModel @AssistedInject constructor(
             SignMode.Unknown            -> error("Developer error, invalid sign mode")
             SignMode.SignIn             -> handleLogin(action)
             SignMode.SignUp             -> handleRegisterWith(action)
-            SignMode.SignInWithMatrixId -> handleDirectLogin(action)
+            SignMode.SignInWithMatrixId -> handleDirectLogin(action, null)
         }.exhaustive
     }
 
-    private fun handleDirectLogin(action: LoginAction.LoginOrRegister) {
+    private fun handleDirectLogin(action: LoginAction.LoginOrRegister, homeServerConnectionConfig: HomeServerConnectionConfig?) {
         setState {
             copy(
                     asyncLoginAction = Loading()
             )
         }
 
-        // TODO Handle certificate error in this case. Direct login is deactivated now, so we will handle that later
-        authenticationService.getWellKnownData(action.username, null, object : MatrixCallback<WellknownResult> {
+        authenticationService.getWellKnownData(action.username, homeServerConnectionConfig, object : MatrixCallback<WellknownResult> {
             override fun onSuccess(data: WellknownResult) {
                 when (data) {
                     is WellknownResult.Prompt          ->
-                        onWellknownSuccess(action, data)
+                        onWellknownSuccess(action, data, homeServerConnectionConfig)
                     is WellknownResult.InvalidMatrixId -> {
                         setState {
                             copy(
@@ -529,23 +548,26 @@ class LoginViewModel @AssistedInject constructor(
             }
 
             override fun onFailure(failure: Throwable) {
-                setState {
-                    copy(
-                            asyncLoginAction = Fail(failure)
-                    )
-                }
+                onDirectLoginError(failure)
             }
         })
     }
 
-    private fun onWellknownSuccess(action: LoginAction.LoginOrRegister, wellKnownPrompt: WellknownResult.Prompt) {
-        val homeServerConnectionConfig = HomeServerConnectionConfig(
-                homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl),
-                identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
-        )
+    private fun onWellknownSuccess(action: LoginAction.LoginOrRegister,
+                                   wellKnownPrompt: WellknownResult.Prompt,
+                                   homeServerConnectionConfig: HomeServerConnectionConfig?) {
+        val alteredHomeServerConnectionConfig = homeServerConnectionConfig
+                ?.copy(
+                        homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl),
+                        identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
+                )
+                ?: HomeServerConnectionConfig(
+                        homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl),
+                        identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
+                )
 
         authenticationService.directAuthentication(
-                homeServerConnectionConfig,
+                alteredHomeServerConnectionConfig,
                 action.username,
                 action.password,
                 action.initialDeviceName,
@@ -555,15 +577,29 @@ class LoginViewModel @AssistedInject constructor(
                     }
 
                     override fun onFailure(failure: Throwable) {
-                        setState {
-                            copy(
-                                    asyncLoginAction = Fail(failure)
-                            )
-                        }
+                        onDirectLoginError(failure)
                     }
                 })
     }
 
+    private fun onDirectLoginError(failure: Throwable) {
+        if (failure is Failure.UnrecognizedCertificateFailure) {
+            // Display this error in a dialog
+            _viewEvents.post(LoginViewEvents.Failure(failure))
+            setState {
+                copy(
+                        asyncLoginAction = Uninitialized
+                )
+            }
+        } else {
+            setState {
+                copy(
+                        asyncLoginAction = Fail(failure)
+                )
+            }
+        }
+    }
+
     private fun handleLogin(action: LoginAction.LoginOrRegister) {
         val safeLoginWizard = loginWizard
 
@@ -679,7 +715,10 @@ class LoginViewModel @AssistedInject constructor(
 
         setState {
             copy(
-                    asyncHomeServerLoginFlowRequest = Loading()
+                    asyncHomeServerLoginFlowRequest = Loading(),
+                    // If user has entered https://matrix.org, ensure that server type is ServerType.MatrixOrg
+                    // It is also useful to set the value again in the case of a certificate error on matrix.org
+                    serverType = if (homeServerConnectionConfig.homeServerUri.toString() == matrixOrgUrl) ServerType.MatrixOrg else serverType
             )
         }
 

From cfdf5cb552fbf40ac2c450d81723ff789dca17d1 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 6 Jul 2020 14:57:28 +0200
Subject: [PATCH 24/28] Add a delay to avoid crash. Sounds like a workaround...

---
 .../vector/riotx/features/login/LoginViewModel.kt  | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
index a7c58f4b04..f68290e862 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
@@ -19,6 +19,7 @@ package im.vector.riotx.features.login
 import android.content.Context
 import android.net.Uri
 import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
@@ -53,6 +54,8 @@ import im.vector.riotx.features.call.WebRtcPeerConnectionManager
 import im.vector.riotx.features.notifications.PushRuleTriggerListener
 import im.vector.riotx.features.session.SessionListener
 import im.vector.riotx.features.signout.soft.SoftLogoutActivity
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 import timber.log.Timber
 import java.util.concurrent.CancellationException
 
@@ -399,9 +402,16 @@ class LoginViewModel @AssistedInject constructor(
         when (action.signMode) {
             SignMode.SignUp             -> startRegistrationFlow()
             SignMode.SignIn             -> startAuthenticationFlow()
-            SignMode.SignInWithMatrixId -> _viewEvents.post(LoginViewEvents.OnSignModeSelected)
+            SignMode.SignInWithMatrixId -> {
+                viewModelScope.launch {
+                    // Add a delay to avoid crash
+                    delay(50)
+                    _viewEvents.post(LoginViewEvents.OnSignModeSelected)
+                }
+                Unit
+            }
             SignMode.Unknown            -> Unit
-        }.exhaustive
+        }
     }
 
     private fun handleUpdateServerType(action: LoginAction.UpdateServerType) {

From f998cb6b18f9cdbc68113529bac07f67fe0ca1a0 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 6 Jul 2020 17:12:47 +0200
Subject: [PATCH 25/28] Upload device keys only once to the homeserver and fix
 crash when no network (#1629)

---
 CHANGES.md                                    |  2 +-
 .../internal/crypto/DefaultCryptoService.kt   | 22 +++++++++++++------
 .../internal/crypto/store/IMXCryptoStore.kt   |  3 +++
 .../crypto/store/db/RealmCryptoStore.kt       | 12 ++++++++++
 .../store/db/RealmCryptoStoreMigration.kt     | 10 ++++++++-
 .../store/db/model/CryptoMetadataEntity.kt    |  3 +++
 6 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 20b3b34375..a8313cc722 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,7 +5,7 @@ Features ✨:
  -
 
 Improvements 🙌:
- -
+ - Upload device keys only once to the homeserver and fix crash when no network (#1629)
 
 Bugfix 🐛:
  - Fix crash when coming from a notification (#1601)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt
index 02197fb5f3..01dd0ca17d 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt
@@ -70,7 +70,6 @@ import im.vector.matrix.android.internal.crypto.model.event.RoomKeyWithHeldConte
 import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent
 import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
 import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
-import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
 import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
 import im.vector.matrix.android.internal.crypto.model.toRest
 import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
@@ -343,8 +342,11 @@ internal class DefaultCryptoService @Inject constructor(
         cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
             // Open the store
             cryptoStore.open()
-            // TODO why do that everytime? we should mark that it was done
-            uploadDeviceKeys()
+            // this can throw if no network
+            tryThis {
+                uploadDeviceKeys()
+            }
+
             oneTimeKeysUploader.maybeUploadOneTimeKeys()
             // this can throw if no backup
             tryThis {
@@ -389,7 +391,7 @@ internal class DefaultCryptoService @Inject constructor(
 //            } else {
 
             // Why would we do that? it will be called at end of syn
-                incomingGossipingRequestManager.processReceivedGossipingRequests()
+            incomingGossipingRequestManager.processReceivedGossipingRequests()
 //            }
         }.fold(
                 {
@@ -888,7 +890,7 @@ internal class DefaultCryptoService @Inject constructor(
      */
     private fun handleSDKLevelGossip(secretName: String?, secretValue: String): Boolean {
         return when (secretName) {
-            MASTER_KEY_SSSS_NAME -> {
+            MASTER_KEY_SSSS_NAME       -> {
                 crossSigningService.onSecretMSKGossip(secretValue)
                 true
             }
@@ -980,7 +982,11 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Upload my user's device keys.
      */
-    private suspend fun uploadDeviceKeys(): KeysUploadResponse {
+    private suspend fun uploadDeviceKeys() {
+        if (cryptoStore.getDeviceKeysUploaded()) {
+            Timber.d("Keys already uploaded, nothing to do")
+            return
+        }
         // Prepare the device keys data to send
         // Sign it
         val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
@@ -991,7 +997,9 @@ internal class DefaultCryptoService @Inject constructor(
         )
 
         val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null)
-        return uploadKeysTask.execute(uploadDeviceKeysParams)
+        uploadKeysTask.execute(uploadDeviceKeysParams)
+
+        cryptoStore.setDeviceKeysUploaded(true)
     }
 
     /**
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt
index 3540f57608..f518332298 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt
@@ -433,4 +433,7 @@ internal interface IMXCryptoStore {
     fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest?
     fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
     fun getGossipingEventsTrail(): List<Event>
+
+    fun setDeviceKeysUploaded(uploaded: Boolean)
+    fun getDeviceKeysUploaded(): Boolean
 }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt
index ec5e64dde8..0e67850304 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt
@@ -842,6 +842,18 @@ internal class RealmCryptoStore @Inject constructor(
         } ?: false
     }
 
+    override fun setDeviceKeysUploaded(uploaded: Boolean) {
+        doRealmTransaction(realmConfiguration) {
+            it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer = uploaded
+        }
+    }
+
+    override fun getDeviceKeysUploaded(): Boolean {
+        return doWithRealm(realmConfiguration) {
+            it.where<CryptoMetadataEntity>().findFirst()?.deviceKeysSentToServer
+        } ?: false
+    }
+
     override fun setRoomsListBlacklistUnverifiedDevices(roomIds: List<String>) {
         doRealmTransaction(realmConfiguration) {
             // Reset all
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
index 7bf8e2478f..0cca430799 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt
@@ -54,7 +54,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
         // 0, 1, 2: legacy Riot-Android
         // 3: migrate to RiotX schema
         // 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
-        const val CRYPTO_STORE_SCHEMA_VERSION = 10L
+        const val CRYPTO_STORE_SCHEMA_VERSION = 11L
     }
 
     override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
@@ -70,6 +70,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
         if (oldVersion <= 7) migrateTo8(realm)
         if (oldVersion <= 8) migrateTo9(realm)
         if (oldVersion <= 9) migrateTo10(realm)
+        if (oldVersion <= 10) migrateTo11(realm)
     }
 
     private fun migrateTo1Legacy(realm: DynamicRealm) {
@@ -446,4 +447,11 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi
                 .addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java)
                 .setNullable(SharedSessionEntityFields.CHAIN_INDEX, true)
     }
+
+    // Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity
+    private fun migrateTo11(realm: DynamicRealm) {
+        Timber.d("Step 10 -> 11")
+        realm.schema.get("CryptoMetadataEntity")
+                ?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java)
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt
index 2d4706ba76..f3c34af586 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt
@@ -36,6 +36,9 @@ internal open class CryptoMetadataEntity(
         // The keys backup version currently used. Null means no backup.
         var backupVersion: String? = null,
 
+        // The device keys has been sent to the homeserver
+        var deviceKeysSentToServer: Boolean = false,
+
         var xSignMasterPrivateKey: String? = null,
         var xSignUserPrivateKey: String? = null,
         var xSignSelfSignedPrivateKey: String? = null,

From 38c54e0f2ccb90ed6fe8dcabf26d2020b5ebb983 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Mon, 6 Jul 2020 18:51:39 +0200
Subject: [PATCH 26/28] QuickFix / crash when  starting in airplane mode

---
 .../matrix/android/internal/crypto/DefaultCryptoService.kt     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt
index 02197fb5f3..0af7a2d36d 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt
@@ -98,6 +98,7 @@ import im.vector.matrix.android.internal.session.sync.model.SyncResponse
 import im.vector.matrix.android.internal.task.TaskExecutor
 import im.vector.matrix.android.internal.task.TaskThread
 import im.vector.matrix.android.internal.task.configureWith
+import im.vector.matrix.android.internal.task.launchToCallback
 import im.vector.matrix.android.internal.util.JsonCanonicalizer
 import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
 import im.vector.matrix.android.internal.util.fetchCopied
@@ -340,7 +341,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     fun ensureDevice() {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
+        cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) {
             // Open the store
             cryptoStore.open()
             // TODO why do that everytime? we should mark that it was done

From 8b1a07b8a89252185be1a89ba4b7966b294f125f Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 6 Jul 2020 23:01:45 +0200
Subject: [PATCH 27/28] Add the new value to the ViewEvent, because the state
 is maybe not up to date.

---
 .../vector/riotx/features/login/LoginActivity.kt | 13 +++++++------
 .../riotx/features/login/LoginViewEvents.kt      |  4 ++--
 .../riotx/features/login/LoginViewModel.kt       | 16 +++-------------
 .../features/signout/soft/SoftLogoutFragment.kt  |  5 +++--
 4 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
index 1eebf532e7..f71b0ecba4 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
@@ -151,8 +151,8 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
                             // TODO Disabled because it provokes a flickering
                             // ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
                         })
-            is LoginViewEvents.OnServerSelectionDone                      -> onServerSelectionDone()
-            is LoginViewEvents.OnSignModeSelected                         -> onSignModeSelected()
+            is LoginViewEvents.OnServerSelectionDone                      -> onServerSelectionDone(loginViewEvents)
+            is LoginViewEvents.OnSignModeSelected                         -> onSignModeSelected(loginViewEvents)
             is LoginViewEvents.OnLoginFlowRetrieved                       ->
                 addFragmentToBackstack(R.id.loginFragmentContainer,
                         if (loginViewEvents.isSso) {
@@ -228,8 +228,8 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
                 .show()
     }
 
-    private fun onServerSelectionDone() = withState(loginViewModel) { state ->
-        when (state.serverType) {
+    private fun onServerSelectionDone(loginViewEvents: LoginViewEvents.OnServerSelectionDone) {
+        when (loginViewEvents.serverType) {
             ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow
             ServerType.Modular,
             ServerType.Other     -> addFragmentToBackstack(R.id.loginFragmentContainer,
@@ -239,8 +239,9 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
         }
     }
 
-    private fun onSignModeSelected() = withState(loginViewModel) { state ->
-        when (state.signMode) {
+    private fun onSignModeSelected(loginViewEvents: LoginViewEvents.OnSignModeSelected) = withState(loginViewModel) { state ->
+        // state.signMode could not be ready yet. So use value from the ViewEvent
+        when (loginViewEvents.signMode) {
             SignMode.Unknown            -> error("Sign mode has to be set before calling this method")
             SignMode.SignUp             -> {
                 // This is managed by the LoginViewEvents
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt
index 9b69ba8a4f..fe5c00399b 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewEvents.kt
@@ -33,9 +33,9 @@ sealed class LoginViewEvents : VectorViewEvents {
     // Navigation event
 
     object OpenServerSelection : LoginViewEvents()
-    object OnServerSelectionDone : LoginViewEvents()
+    data class OnServerSelectionDone(val serverType: ServerType) : LoginViewEvents()
     data class OnLoginFlowRetrieved(val isSso: Boolean) : LoginViewEvents()
-    object OnSignModeSelected : LoginViewEvents()
+    data class OnSignModeSelected(val signMode: SignMode) : LoginViewEvents()
     object OnForgetPasswordClicked : LoginViewEvents()
     object OnResetPasswordSendThreePidDone : LoginViewEvents()
     object OnResetPasswordMailConfirmationSuccess : LoginViewEvents()
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
index f68290e862..7edc674b11 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
@@ -19,7 +19,6 @@ package im.vector.riotx.features.login
 import android.content.Context
 import android.net.Uri
 import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
@@ -54,8 +53,6 @@ import im.vector.riotx.features.call.WebRtcPeerConnectionManager
 import im.vector.riotx.features.notifications.PushRuleTriggerListener
 import im.vector.riotx.features.session.SessionListener
 import im.vector.riotx.features.signout.soft.SoftLogoutActivity
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
 import timber.log.Timber
 import java.util.concurrent.CancellationException
 
@@ -402,14 +399,7 @@ class LoginViewModel @AssistedInject constructor(
         when (action.signMode) {
             SignMode.SignUp             -> startRegistrationFlow()
             SignMode.SignIn             -> startAuthenticationFlow()
-            SignMode.SignInWithMatrixId -> {
-                viewModelScope.launch {
-                    // Add a delay to avoid crash
-                    delay(50)
-                    _viewEvents.post(LoginViewEvents.OnSignModeSelected)
-                }
-                Unit
-            }
+            SignMode.SignInWithMatrixId -> _viewEvents.post(LoginViewEvents.OnSignModeSelected(SignMode.SignInWithMatrixId))
             SignMode.Unknown            -> Unit
         }
     }
@@ -427,7 +417,7 @@ class LoginViewModel @AssistedInject constructor(
                 // Request login flow here
                 handle(LoginAction.UpdateHomeServer(matrixOrgUrl))
             ServerType.Modular,
-            ServerType.Other     -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone)
+            ServerType.Other     -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone(action.serverType))
         }.exhaustive
     }
 
@@ -661,7 +651,7 @@ class LoginViewModel @AssistedInject constructor(
         // Ensure Wizard is ready
         loginWizard
 
-        _viewEvents.post(LoginViewEvents.OnSignModeSelected)
+        _viewEvents.post(LoginViewEvents.OnSignModeSelected(SignMode.SignIn))
     }
 
     private fun onFlowResponse(flowResult: FlowResult) {
diff --git a/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt b/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt
index 13b90f26e8..fadcaa8055 100644
--- a/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt
+++ b/vector/src/main/java/im/vector/riotx/features/signout/soft/SoftLogoutFragment.kt
@@ -93,8 +93,9 @@ class SoftLogoutFragment @Inject constructor(
         softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password))
     }
 
-    override fun signinFallbackSubmit() {
-        loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnSignModeSelected))
+    override fun signinFallbackSubmit() = withState(loginViewModel) { state ->
+        // The loginViewModel has been prepared for a SSO/login fallback recovery (above)
+        loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnSignModeSelected(state.signMode)))
     }
 
     override fun clearData() {

From 1e6d98a121470f7f0ccea1954231c671642ba278 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 6 Jul 2020 23:31:03 +0200
Subject: [PATCH 28/28] Prepare release 0.91.04-beta

---
 CHANGES.md | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 62aeb5473d..e264facd8e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -14,20 +14,11 @@ Bugfix 🐛:
  - saved images don't show up in gallery (#1324)
  - Fix reply fallback leaking sender locale (#429)
 
-Translations 🗣:
- -
-
-SDK API changes ⚠️:
- - 
-
 Build 🧱:
  - Fix lint false-positive about WorkManager (#1012)
  - Upgrade build-tools from 3.5.3 to 3.6.6
  - Upgrade gradle from 5.4.1 to 5.6.4
 
-Other changes:
- -
-
 Changes in Riot.imX 0.91.3 (2020-07-01)
 ===================================================