From 96cf5d2105127f4e0349556449f498abbe58e905 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 24 Aug 2020 14:32:43 +0200
Subject: [PATCH 01/13] Cleanup: propoerly inject things to PushRulesFragment
 and move PushRulesController to its own file

---
 .../im/vector/app/core/di/FragmentModule.kt   |  6 +++
 .../settings/push/PushRulesController.kt      | 44 +++++++++++++++++++
 .../settings/push/PushRulesFragment.kt        | 29 ++----------
 3 files changed, 54 insertions(+), 25 deletions(-)
 create mode 100644 vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt

diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
index 1aa9902137..591d1c0474 100644
--- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
@@ -102,6 +102,7 @@ import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
 import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
 import im.vector.app.features.settings.locale.LocalePickerFragment
 import im.vector.app.features.settings.push.PushGatewaysFragment
+import im.vector.app.features.settings.push.PushRulesFragment
 import im.vector.app.features.share.IncomingShareFragment
 import im.vector.app.features.signout.soft.SoftLogoutFragment
 import im.vector.app.features.terms.ReviewTermsFragment
@@ -282,6 +283,11 @@ interface FragmentModule {
     @FragmentKey(VectorSettingsLabsFragment::class)
     fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment
 
+    @Binds
+    @IntoMap
+    @FragmentKey(PushRulesFragment::class)
+    fun bindPushRulesFragment(fragment: PushRulesFragment): Fragment
+
     @Binds
     @IntoMap
     @FragmentKey(VectorSettingsPreferencesFragment::class)
diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt
new file mode 100644
index 0000000000..a8a1ab2e17
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesController.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.push
+
+import com.airbnb.epoxy.TypedEpoxyController
+import im.vector.app.R
+import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.ui.list.genericFooterItem
+import javax.inject.Inject
+
+class PushRulesController @Inject constructor(
+        private val stringProvider: StringProvider
+) : TypedEpoxyController<PushRulesViewState>() {
+
+    override fun buildModels(data: PushRulesViewState?) {
+        data?.let {
+            it.rules.forEach {
+                pushRuleItem {
+                    id(it.ruleId)
+                    pushRule(it)
+                }
+            }
+        } ?: run {
+            genericFooterItem {
+                id("footer")
+                text(stringProvider.getString(R.string.settings_push_rules_no_rules))
+            }
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt
index 44cb5d8ea2..c361e21254 100644
--- a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesFragment.kt
@@ -17,7 +17,6 @@ package im.vector.app.features.settings.push
 
 import android.os.Bundle
 import android.view.View
-import com.airbnb.epoxy.TypedEpoxyController
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import im.vector.app.R
@@ -25,19 +24,18 @@ import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.core.platform.VectorBaseFragment
-import im.vector.app.core.resources.StringProvider
-import im.vector.app.core.ui.list.genericFooterItem
 import kotlinx.android.synthetic.main.fragment_generic_recycler.*
+import javax.inject.Inject
 
 // Referenced in vector_settings_notifications.xml
-class PushRulesFragment : VectorBaseFragment() {
+class PushRulesFragment @Inject constructor(
+        private val epoxyController: PushRulesController
+) : VectorBaseFragment() {
 
     override fun getLayoutResId() = R.layout.fragment_generic_recycler
 
     private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class)
 
-    private val epoxyController by lazy { PushRulesController(StringProvider(requireContext().resources)) }
-
     override fun onResume() {
         super.onResume()
         (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules)
@@ -56,23 +54,4 @@ class PushRulesFragment : VectorBaseFragment() {
     override fun invalidate() = withState(viewModel) { state ->
         epoxyController.setData(state)
     }
-
-    class PushRulesController(private val stringProvider: StringProvider) : TypedEpoxyController<PushRulesViewState>() {
-
-        override fun buildModels(data: PushRulesViewState?) {
-            data?.let {
-                it.rules.forEach {
-                    pushRuleItem {
-                        id(it.ruleId)
-                        pushRule(it)
-                    }
-                }
-            } ?: run {
-                genericFooterItem {
-                    id("footer")
-                    text(stringProvider.getString(R.string.settings_push_rules_no_rules))
-                }
-            }
-        }
-    }
 }

From 69e9a79ac1885335a6c55a1e5a547d5ee0892aa4 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 24 Aug 2020 14:49:42 +0200
Subject: [PATCH 02/13] Inject StringProvider instead of Context

---
 .../membership/RoomDisplayNameResolver.kt     | 19 ++++++++++---------
 .../sdk/internal/util/StringProvider.kt       |  8 ++++----
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
index d11226bdb1..942da9995e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
@@ -17,7 +17,7 @@
 
 package org.matrix.android.sdk.internal.session.room.membership
 
-import android.content.Context
+import io.realm.Realm
 import org.matrix.android.sdk.R
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toModel
@@ -34,14 +34,15 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
 import org.matrix.android.sdk.internal.database.query.getOrNull
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.UserId
-import io.realm.Realm
+import org.matrix.android.sdk.internal.util.StringProvider
 import javax.inject.Inject
 
 /**
  * This class computes room display name
  */
-internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
-                                                           @UserId private val userId: String
+internal class RoomDisplayNameResolver @Inject constructor(
+        private val stringProvider: StringProvider,
+        @UserId private val userId: String
 ) {
 
     /**
@@ -89,7 +90,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
                         .findFirst()
                         ?.displayName
             } else {
-                context.getString(R.string.room_displayname_room_invite)
+                stringProvider.getString(R.string.room_displayname_room_invite)
             }
         } else if (roomEntity?.membership == Membership.JOIN) {
             val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
@@ -108,13 +109,13 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
             }
             val otherMembersCount = otherMembersSubset.count()
             name = when (otherMembersCount) {
-                0    -> context.getString(R.string.room_displayname_empty_room)
-                1    -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
-                2    -> context.getString(R.string.room_displayname_two_members,
+                0 -> stringProvider.getString(R.string.room_displayname_empty_room)
+                1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
+                2 -> stringProvider.getString(R.string.room_displayname_two_members,
                         resolveRoomMemberName(otherMembersSubset[0], roomMembers),
                         resolveRoomMemberName(otherMembersSubset[1], roomMembers)
                 )
-                else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
+                else -> stringProvider.getQuantityString(R.plurals.room_displayname_three_and_more_members,
                         roomMembers.getNumberOfJoinedMembers() - 1,
                         resolveRoomMemberName(otherMembersSubset[0], roomMembers),
                         roomMembers.getNumberOfJoinedMembers() - 1)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt
index 902d7d3316..9233b2b807 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt
@@ -18,8 +18,8 @@
 package org.matrix.android.sdk.internal.util
 
 import android.content.res.Resources
-import androidx.annotation.ArrayRes
 import androidx.annotation.NonNull
+import androidx.annotation.PluralsRes
 import androidx.annotation.StringRes
 import dagger.Reusable
 import javax.inject.Inject
@@ -56,8 +56,8 @@ internal class StringProvider @Inject constructor(private val resources: Resourc
         return resources.getString(resId, *formatArgs)
     }
 
-    @Throws(Resources.NotFoundException::class)
-    fun getStringArray(@ArrayRes id: Int): Array<String> {
-        return resources.getStringArray(id)
+    @NonNull
+    fun getQuantityString(@PluralsRes resId: Int, quantity: Int, vararg formatArgs: Any?): String {
+        return resources.getQuantityString(resId, quantity, *formatArgs)
     }
 }

From efa3aa5cf8e24726c18ce4a3493feff618db2e13 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 24 Aug 2020 15:08:52 +0200
Subject: [PATCH 03/13] Stop using internal context of VectorLocal in
 CallHeadsUpActionReceiver...

---
 .../call/service/CallHeadsUpActionReceiver.kt | 22 ++++++-------------
 .../app/features/settings/VectorLocale.kt     |  2 +-
 2 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt b/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt
index 179ba288eb..04e7401e6c 100644
--- a/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt
+++ b/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt
@@ -21,8 +21,6 @@ import android.content.Context
 import android.content.Intent
 import im.vector.app.core.di.HasVectorInjector
 import im.vector.app.features.call.WebRtcPeerConnectionManager
-import im.vector.app.features.notifications.NotificationUtils
-import im.vector.app.features.settings.VectorLocale.context
 import timber.log.Timber
 
 class CallHeadsUpActionReceiver : BroadcastReceiver() {
@@ -32,20 +30,14 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() {
         const val CALL_ACTION_REJECT = 0
     }
 
-    private lateinit var peerConnectionManager: WebRtcPeerConnectionManager
-    private lateinit var notificationUtils: NotificationUtils
-
-    init {
-        val appContext = context.applicationContext
-        if (appContext is HasVectorInjector) {
-            peerConnectionManager = appContext.injector().webRtcPeerConnectionManager()
-            notificationUtils = appContext.injector().notificationUtils()
-        }
-    }
-
     override fun onReceive(context: Context, intent: Intent?) {
+        val peerConnectionManager = (context.applicationContext as? HasVectorInjector)
+                ?.injector()
+                ?.webRtcPeerConnectionManager()
+                ?: return
+
         when (intent?.getIntExtra(EXTRA_CALL_ACTION_KEY, 0)) {
-            CALL_ACTION_REJECT -> onCallRejectClicked()
+            CALL_ACTION_REJECT -> onCallRejectClicked(peerConnectionManager)
         }
 
         // Not sure why this should be needed
@@ -56,7 +48,7 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() {
 //        context.stopService(Intent(context, CallHeadsUpService::class.java))
     }
 
-    private fun onCallRejectClicked() {
+    private fun onCallRejectClicked(peerConnectionManager: WebRtcPeerConnectionManager) {
         Timber.d("onCallRejectClicked")
         peerConnectionManager.endCall()
     }
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt
index d2f92e300e..b9d81ab005 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt
@@ -52,7 +52,7 @@ object VectorLocale {
     var applicationLocale = defaultLocale
         private set
 
-    lateinit var context: Context
+    private lateinit var context: Context
 
     /**
      * Init this object

From 116e6fb3c07ca53d64f60f12af453918bd4fc312 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 24 Aug 2020 15:50:47 +0200
Subject: [PATCH 04/13] Call restart() extension

---
 .../java/im/vector/app/core/platform/VectorBaseActivity.kt  | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
index 11a6e326ac..856e84ea14 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
@@ -60,6 +60,7 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.observeEvent
 import im.vector.app.core.extensions.observeNotNull
+import im.vector.app.core.extensions.restart
 import im.vector.app.core.extensions.vectorComponent
 import im.vector.app.core.utils.toast
 import im.vector.app.features.MainActivity
@@ -79,10 +80,10 @@ import im.vector.app.features.settings.VectorPreferences
 import im.vector.app.features.themes.ActivityOtherThemes
 import im.vector.app.features.themes.ThemeUtils
 import im.vector.app.receivers.DebugReceiver
-import org.matrix.android.sdk.api.failure.GlobalError
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.CompositeDisposable
 import io.reactivex.disposables.Disposable
+import org.matrix.android.sdk.api.failure.GlobalError
 import timber.log.Timber
 import kotlin.system.measureTimeMillis
 
@@ -198,8 +199,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
         configurationViewModel.activityRestarter.observe(this, Observer {
             if (!it.hasBeenHandled) {
                 // Recreate the Activity because configuration has changed
-                startActivity(intent)
-                finish()
+                restart()
             }
         })
         pinLocker.getLiveState().observeNotNull(this) {

From ed98613b2d9c82d6dd36b705456043f078ea2712 Mon Sep 17 00:00:00 2001
From: Tobias Preuss <tobias.preuss@googlemail.com>
Date: Wed, 19 Aug 2020 22:59:57 +0200
Subject: [PATCH 05/13] Use File extension functions to make code more concise.

+ This change replaces a few usages of ByteArrayInputStream, FileInputStream,
  FileOutputStream with their equivalent Kotlin extension functions.
---
 CHANGES.md                                               | 2 +-
 .../sdk/internal/crypto/AttachmentEncryptionTest.kt      | 3 +--
 .../crypto/attachments/MXEncryptedAttachments.kt         | 3 +--
 .../android/sdk/internal/crypto/store/db/Helper.kt       | 3 +--
 .../sdk/internal/session/content/UploadContentWorker.kt  | 9 +++------
 .../internal/session/securestorage/SecretStoringUtils.kt | 2 +-
 .../org/matrix/android/sdk/internal/util/FileSaver.kt    | 3 +--
 .../im/vector/app/core/glide/VectorGlideModelLoader.kt   | 3 +--
 .../im/vector/app/core/utils/ExternalApplicationsUtil.kt | 4 ++--
 .../features/notifications/NotificationDrawerManager.kt  | 3 +--
 10 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index d3a16c9b29..a9f2e896aa 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -20,7 +20,7 @@ Build 🧱:
  - Some dependencies have been upgraded (coroutine, recyclerView, appCompat, core-ktx, firebase-messaging)
 
 Other changes:
- -
+ - Use File extension functions to make code more concise (#1996)
 
 Changes in Element 1.0.5 (2020-08-21)
 ===================================================
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt
index 05dbc40e1e..cb24cbb242 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt
@@ -29,7 +29,6 @@ import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
-import java.io.ByteArrayInputStream
 import java.io.InputStream
 
 /**
@@ -46,7 +45,7 @@ class AttachmentEncryptionTest {
         val inputStream: InputStream
 
         inputStream = if (`in`.isEmpty()) {
-            ByteArrayInputStream(`in`)
+            `in`.inputStream()
         } else {
             val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size)
             memoryFile.outputStream.write(`in`)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt
index cec1480d7b..a6d95cc87a 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt
@@ -21,7 +21,6 @@ import android.util.Base64
 import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
 import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey
 import timber.log.Timber
-import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
 import java.io.InputStream
 import java.security.MessageDigest
@@ -179,7 +178,7 @@ internal object MXEncryptedAttachments {
                     return null
                 }
 
-                return ByteArrayInputStream(outputStream.toByteArray())
+                return outputStream.toByteArray().inputStream()
                         .also { Timber.v("Decrypt in ${System.currentTimeMillis() - t0}ms") }
             } catch (oom: OutOfMemoryError) {
                 Timber.e(oom, "## decryptAttachment() failed: OOM")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
index 978c82303e..67e06b5455 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
@@ -21,7 +21,6 @@ import android.util.Base64
 import io.realm.Realm
 import io.realm.RealmConfiguration
 import io.realm.RealmObject
-import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
 import java.io.ObjectOutputStream
 import java.util.zip.GZIPInputStream
@@ -96,7 +95,7 @@ fun <T> deserializeFromRealm(string: String?): T? {
     }
     val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT)
 
-    val bais = ByteArrayInputStream(decodedB64)
+    val bais = decodedB64.inputStream()
     val gzis = GZIPInputStream(bais)
     val ois = SafeObjectInputStream(gzis)
     return ois.use {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
index 6d354cdcbe..720269404f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
@@ -42,10 +42,7 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams
 import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
 import org.matrix.android.sdk.internal.worker.getSessionComponent
 import timber.log.Timber
-import java.io.ByteArrayInputStream
 import java.io.File
-import java.io.FileInputStream
-import java.io.FileOutputStream
 import java.util.UUID
 import javax.inject.Inject
 
@@ -130,7 +127,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
                         val contentUploadResponse = if (params.isEncrypted) {
                             Timber.v("Encrypt thumbnail")
                             notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) }
-                            val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType)
+                            val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType)
                             uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo
                             fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
                                     "thumb_${attachment.name}",
@@ -176,7 +173,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
                     cacheFile.createNewFile()
                     cacheFile.deleteOnExit()
 
-                    val outputStream = FileOutputStream(cacheFile)
+                    val outputStream = cacheFile.outputStream()
                     outputStream.use {
                         inputStream.copyTo(outputStream)
                     }
@@ -203,7 +200,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
                         Timber.v("Encrypt file")
                         notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) }
 
-                        val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(cacheFile), attachment.getSafeMimeType())
+                        val encryptionResult = MXEncryptedAttachments.encryptAttachment(cacheFile.inputStream(), attachment.getSafeMimeType())
                         uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo
 
                         fileUploader
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
index 2ae115f325..8eab44366c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
@@ -219,7 +219,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
 
     @RequiresApi(Build.VERSION_CODES.M)
     private fun decryptStringM(encryptedChunk: ByteArray, keyAlias: String): String {
-        val (iv, encryptedText) = formatMExtract(ByteArrayInputStream(encryptedChunk))
+        val (iv, encryptedText) = formatMExtract(encryptedChunk.inputStream())
 
         val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt
index 27625d90bc..da524cc1b2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt
@@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.util
 
 import androidx.annotation.WorkerThread
 import java.io.File
-import java.io.FileOutputStream
 import java.io.InputStream
 
 /**
@@ -27,7 +26,7 @@ import java.io.InputStream
  */
 @WorkerThread
 fun writeToFile(inputStream: InputStream, outputFile: File) {
-    FileOutputStream(outputFile).use {
+    outputFile.outputStream().use {
         inputStream.copyTo(it)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
index 295609548f..9ac8a4d3bc 100644
--- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
+++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
@@ -31,7 +31,6 @@ import okhttp3.OkHttpClient
 import okhttp3.Request
 import timber.log.Timber
 import java.io.File
-import java.io.FileInputStream
 import java.io.IOException
 import java.io.InputStream
 
@@ -97,7 +96,7 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde
         Timber.v("Load data: $data")
         if (data.isLocalFile() && data.url != null) {
             val initialFile = File(data.url)
-            callback.onDataReady(FileInputStream(initialFile))
+            callback.onDataReady(initialFile.inputStream())
             return
         }
         val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
index b314401138..b1c63a406a 100644
--- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
@@ -518,8 +518,8 @@ fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: Strin
     var outputStream: FileOutputStream? = null
     try {
         dstFile.createNewFile()
-        inputStream = FileInputStream(sourceFile)
-        outputStream = FileOutputStream(dstFile)
+        inputStream = sourceFile.inputStream()
+        outputStream = dstFile.outputStream()
         val buffer = ByteArray(1024 * 10)
         var len: Int
         while (inputStream.read(buffer).also { len = it } != -1) {
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt
index 98d35dc764..e689f9df3f 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt
@@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.content.ContentUrlResolver
 import me.gujun.android.span.span
 import timber.log.Timber
 import java.io.File
-import java.io.FileInputStream
 import java.io.FileOutputStream
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -494,7 +493,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
         try {
             val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
             if (file.exists()) {
-                FileInputStream(file).use {
+                file.inputStream().use {
                     val events: ArrayList<NotifiableEvent>? = currentSession?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
                     if (events != null) {
                         return events.toMutableList()

From 52cf4d24d36e38d2fc63c662915637e7a4a4f068 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 24 Aug 2020 18:05:11 +0200
Subject: [PATCH 06/13] Fix switch language issue

---
 CHANGES.md                                    |  1 +
 .../java/im/vector/app/VectorApplication.kt   | 15 +++---
 .../vector/app/core/services/VectorService.kt |  6 +++
 .../configuration/VectorConfiguration.kt      | 47 ++++++++++---------
 .../VectorSettingsPreferencesFragment.kt      |  1 +
 .../settings/locale/LocalePickerViewModel.kt  |  5 +-
 .../vector/app/features/themes/ThemeUtils.kt  |  6 +++
 7 files changed, 52 insertions(+), 29 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index d3a16c9b29..1bde8a7dfd 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -9,6 +9,7 @@ Improvements 🙌:
 
 Bugfix 🐛:
  - Display name not shown under Settings/General (#1926)
+ - Fix changing language issue
 
 Translations 🗣:
  -
diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt
index 303b9d585a..f64ebf9245 100644
--- a/vector/src/main/java/im/vector/app/VectorApplication.kt
+++ b/vector/src/main/java/im/vector/app/VectorApplication.kt
@@ -32,10 +32,6 @@ import com.airbnb.epoxy.EpoxyAsyncUtil
 import com.airbnb.epoxy.EpoxyController
 import com.facebook.stetho.Stetho
 import com.gabrielittner.threetenbp.LazyThreeTen
-import org.matrix.android.sdk.api.Matrix
-import org.matrix.android.sdk.api.MatrixConfiguration
-import org.matrix.android.sdk.api.auth.AuthenticationService
-import org.matrix.android.sdk.api.legacy.LegacySessionImporter
 import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.di.DaggerVectorComponent
 import im.vector.app.core.di.HasVectorInjector
@@ -50,16 +46,21 @@ import im.vector.app.features.notifications.NotificationUtils
 import im.vector.app.features.pin.PinLocker
 import im.vector.app.features.popup.PopupAlertManager
 import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
+import im.vector.app.features.settings.VectorLocale
 import im.vector.app.features.settings.VectorPreferences
+import im.vector.app.features.themes.ThemeUtils
 import im.vector.app.features.version.VersionProvider
 import im.vector.app.push.fcm.FcmHelper
+import org.matrix.android.sdk.api.Matrix
+import org.matrix.android.sdk.api.MatrixConfiguration
+import org.matrix.android.sdk.api.auth.AuthenticationService
+import org.matrix.android.sdk.api.legacy.LegacySessionImporter
 import timber.log.Timber
 import java.text.SimpleDateFormat
 import java.util.Date
 import java.util.Locale
 import java.util.concurrent.Executors
 import javax.inject.Inject
-
 import androidx.work.Configuration as WorkConfiguration
 
 class VectorApplication :
@@ -119,7 +120,9 @@ class VectorApplication :
                 R.array.com_google_android_gms_fonts_certs
         )
         FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler())
-        vectorConfiguration.initConfiguration()
+        VectorLocale.init(this)
+        ThemeUtils.init(this)
+        vectorConfiguration.applyToApplicationContext()
 
         emojiCompatWrapper.init(fontRequest)
 
diff --git a/vector/src/main/java/im/vector/app/core/services/VectorService.kt b/vector/src/main/java/im/vector/app/core/services/VectorService.kt
index 888f7a8cac..223d720d8a 100644
--- a/vector/src/main/java/im/vector/app/core/services/VectorService.kt
+++ b/vector/src/main/java/im/vector/app/core/services/VectorService.kt
@@ -17,8 +17,10 @@
 package im.vector.app.core.services
 
 import android.app.Service
+import android.content.Context
 import android.content.Intent
 import android.os.IBinder
+import im.vector.app.core.extensions.vectorComponent
 import timber.log.Timber
 
 /**
@@ -31,6 +33,10 @@ abstract class VectorService : Service() {
      */
     private var mIsSelfDestroyed = false
 
+    override fun attachBaseContext(base: Context) {
+        super.attachBaseContext(vectorComponent().vectorConfiguration().getLocalisedContext(base))
+    }
+
     override fun onCreate() {
         super.onCreate()
 
diff --git a/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt b/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt
index 5567a138de..394eca030b 100644
--- a/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt
+++ b/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt
@@ -16,10 +16,11 @@
 
 package im.vector.app.features.configuration
 
-import android.annotation.SuppressLint
 import android.content.Context
 import android.content.res.Configuration
 import android.os.Build
+import android.os.LocaleList
+import androidx.annotation.RequiresApi
 import im.vector.app.features.settings.FontScale
 import im.vector.app.features.settings.VectorLocale
 import im.vector.app.features.themes.ThemeUtils
@@ -40,14 +41,9 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
         }
     }
 
-    /**
-     * Init the configuration from the saved one
-     */
-    fun initConfiguration() {
-        VectorLocale.init(context)
+    fun applyToApplicationContext() {
         val locale = VectorLocale.applicationLocale
         val fontScale = FontScale.getFontScaleValue(context)
-        val theme = ThemeUtils.getApplicationTheme(context)
 
         Locale.setDefault(locale)
         val config = Configuration(context.resources.configuration)
@@ -56,9 +52,6 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
         config.fontScale = fontScale.scale
         @Suppress("DEPRECATION")
         context.resources.updateConfiguration(config, context.resources.displayMetrics)
-
-        // init the theme
-        ThemeUtils.setApplicationTheme(context, theme)
     }
 
     /**
@@ -67,26 +60,22 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
      * @param context the context
      * @return the localised context
      */
-    @SuppressLint("NewApi")
     fun getLocalisedContext(context: Context): Context {
         try {
-            val resources = context.resources
             val locale = VectorLocale.applicationLocale
-            val configuration = resources.configuration
+
+            // create new configuration passing old configuration from original Context
+            val configuration = Configuration(context.resources.configuration)
+
             configuration.fontScale = FontScale.getFontScaleValue(context).scale
 
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                configuration.setLocale(locale)
-                configuration.setLayoutDirection(locale)
-                return context.createConfigurationContext(configuration)
+                setLocaleForApi24(configuration, locale)
             } else {
-                @Suppress("DEPRECATION")
-                configuration.locale = locale
-                configuration.setLayoutDirection(locale)
-                @Suppress("DEPRECATION")
-                resources.updateConfiguration(configuration, resources.displayMetrics)
-                return context
+                configuration.setLocale(locale)
             }
+            configuration.setLayoutDirection(locale)
+            return context.createConfigurationContext(configuration)
         } catch (e: Exception) {
             Timber.e(e, "## getLocalisedContext() failed")
         }
@@ -94,6 +83,20 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
         return context
     }
 
+    @RequiresApi(Build.VERSION_CODES.N)
+    private fun setLocaleForApi24(config: Configuration, locale: Locale) {
+        val set: MutableSet<Locale> = LinkedHashSet()
+        // bring the user locale to the front of the list
+        set.add(locale)
+        val all = LocaleList.getDefault()
+        for (i in 0 until all.size()) {
+            // append other locales supported by the user
+            set.add(all[i])
+        }
+        val locales = set.toTypedArray()
+        config.setLocales(LocaleList(*locales))
+    }
+
     /**
      * Compute the locale status value
      * @return the local status value
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt
index 0d29137289..a84a10f74c 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt
@@ -168,6 +168,7 @@ class VectorSettingsPreferencesFragment @Inject constructor(
                 v.setOnClickListener {
                     dialog.dismiss()
                     FontScale.updateFontScale(activity, i)
+                    vectorConfiguration.applyToApplicationContext()
                     activity.restart()
                 }
             }
diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt
index fd20007c99..df7cc4ba84 100644
--- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt
@@ -26,11 +26,13 @@ import com.squareup.inject.assisted.Assisted
 import com.squareup.inject.assisted.AssistedInject
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.features.configuration.VectorConfiguration
 import im.vector.app.features.settings.VectorLocale
 import kotlinx.coroutines.launch
 
 class LocalePickerViewModel @AssistedInject constructor(
-        @Assisted initialState: LocalePickerViewState
+        @Assisted initialState: LocalePickerViewState,
+        private val vectorConfiguration: VectorConfiguration
 ) : VectorViewModel<LocalePickerViewState, LocalePickerAction, LocalePickerViewEvents>(initialState) {
 
     @AssistedInject.Factory
@@ -70,6 +72,7 @@ class LocalePickerViewModel @AssistedInject constructor(
 
     private fun handleSelectLocale(action: LocalePickerAction.SelectLocale) {
         VectorLocale.saveApplicationLocale(action.locale)
+        vectorConfiguration.applyToApplicationContext()
         _viewEvents.post(LocalePickerViewEvents.RestartActivity)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt
index ef806b55b4..d337b790a3 100644
--- a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt
+++ b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt
@@ -44,6 +44,12 @@ object ThemeUtils {
 
     private val mColorByAttr = HashMap<Int, Int>()
 
+    // init the theme
+    fun init(context: Context) {
+        val theme = getApplicationTheme(context)
+        setApplicationTheme(context, theme)
+    }
+
     /**
      * @return true if current theme is Light or Status
      */

From cb7a1bc9c302752d73237fb91a083adcfa7e6a6b Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 24 Aug 2020 18:20:09 +0200
Subject: [PATCH 07/13] Fix FontSize issue (#1483, #1787)

---
 CHANGES.md                                     |  1 +
 .../app/core/platform/VectorBaseActivity.kt    | 18 ++++++++++++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 1bde8a7dfd..ca35023ede 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ Improvements 🙌:
 Bugfix 🐛:
  - Display name not shown under Settings/General (#1926)
  - Fix changing language issue
+ - Fix FontSize issue (#1483, #1787)
 
 Translations 🗣:
  -
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
index 856e84ea14..bedb02949f 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
@@ -76,6 +76,7 @@ import im.vector.app.features.rageshake.BugReportActivity
 import im.vector.app.features.rageshake.BugReporter
 import im.vector.app.features.rageshake.RageShake
 import im.vector.app.features.session.SessionListener
+import im.vector.app.features.settings.FontScale
 import im.vector.app.features.settings.VectorPreferences
 import im.vector.app.features.themes.ActivityOtherThemes
 import im.vector.app.features.themes.ThemeUtils
@@ -219,6 +220,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
 
         doBeforeSetContentView()
 
+        // Hack for font size
+        applyFontSize()
+
         if (getLayoutRes() != -1) {
             setContentView(getLayoutRes())
         }
@@ -239,6 +243,16 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
         }
     }
 
+    /**
+     * This method has to be called for the font size setting be supported correctly.
+     */
+    private fun applyFontSize() {
+        resources.configuration.fontScale = FontScale.getFontScaleValue(this).scale
+
+        @Suppress("DEPRECATION")
+        resources.updateConfiguration(resources.configuration, resources.displayMetrics)
+    }
+
     private fun handleGlobalError(globalError: GlobalError) {
         when (globalError) {
             is GlobalError.InvalidToken         ->
@@ -302,10 +316,10 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
         super.onActivityResult(requestCode, resultCode, data)
         if (requestCode == PinActivity.PIN_REQUEST_CODE) {
             when (resultCode) {
-                Activity.RESULT_OK                 -> {
+                Activity.RESULT_OK -> {
                     pinLocker.unlock()
                 }
-                else                               -> {
+                else               -> {
                     pinLocker.block()
                     moveTaskToBack(true)
                 }

From 776d892d27a8e2583b03c912f1d58bb12c7a7cdc Mon Sep 17 00:00:00 2001
From: Onuray Sahin <onurays@element.io>
Date: Wed, 26 Aug 2020 12:27:12 +0300
Subject: [PATCH 08/13] Increase version of uCrop library which supports
 Android 10.

---
 CHANGES.md                                                    | 1 +
 vector/build.gradle                                           | 2 +-
 .../im/vector/app/features/media/BigImageViewerActivity.kt    | 4 +---
 .../im/vector/app/features/roomprofile/RoomProfileFragment.kt | 4 +---
 .../app/features/settings/VectorSettingsGeneralFragment.kt    | 3 +--
 5 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index d3a16c9b29..0ab511820a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -9,6 +9,7 @@ Improvements 🙌:
 
 Bugfix 🐛:
  - Display name not shown under Settings/General (#1926)
+ - Change user or room avatar: when selecting Gallery, I'm not proposed to crop the selected image (#1590)
 
 Translations 🗣:
  -
diff --git a/vector/build.gradle b/vector/build.gradle
index c04de62367..ef2d6c3d9e 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -378,7 +378,7 @@ dependencies {
     implementation "com.github.bumptech.glide:glide:$glide_version"
     kapt "com.github.bumptech.glide:compiler:$glide_version"
     implementation 'com.danikula:videocache:2.7.1'
-    implementation 'com.github.yalantis:ucrop:2.2.4'
+    implementation 'com.github.yalantis:ucrop:2.2.6'
 
     // Badge for compatibility
     implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
diff --git a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt
index 9d0a931a32..c619b4aa92 100644
--- a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt
@@ -144,9 +144,7 @@ class BigImageViewerActivity : VectorBaseActivity() {
                             .get(MultiPicker.IMAGE)
                             .getSelectedFiles(this, requestCode, resultCode, data)
                             .firstOrNull()?.let {
-                                // TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
-                                // onRoomAvatarSelected(it)
-                                onAvatarCropped(it.contentUri)
+                                onRoomAvatarSelected(it)
                             }
                 }
                 UCrop.REQUEST_CROP                  -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
index 2722d54950..075ba1bc10 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
@@ -301,9 +301,7 @@ class RoomProfileFragment @Inject constructor(
                             .get(MultiPicker.IMAGE)
                             .getSelectedFiles(requireContext(), requestCode, resultCode, data)
                             .firstOrNull()?.let {
-                                // TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
-                                // onRoomAvatarSelected(it)
-                                onAvatarCropped(it.contentUri)
+                                onRoomAvatarSelected(it)
                             }
                 }
                 UCrop.REQUEST_CROP                  -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt
index 31de5ddd67..e31b81b162 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt
@@ -356,8 +356,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
                             .get(MultiPicker.IMAGE)
                             .getSelectedFiles(requireContext(), requestCode, resultCode, data)
                             .firstOrNull()?.let {
-                                // TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
-                                onAvatarCropped(it.contentUri)
+                                onAvatarSelected(it)
                             }
                 }
                 UCrop.REQUEST_CROP                  -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }

From d014872e3b06c024be4005ec161b81136f637529 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Wed, 26 Aug 2020 11:57:27 +0200
Subject: [PATCH 09/13] Add long click gesture to copy userId, user display
 name, room name, room topic and room alias (#1774)

---
 CHANGES.md                                     |  2 +-
 .../im/vector/app/core/extensions/TextView.kt  | 17 +++++++++++++++++
 .../RoomMemberProfileFragment.kt               | 11 +++++++++--
 .../roomprofile/RoomProfileFragment.kt         | 18 +++++++++++++-----
 4 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index a9f2e896aa..2135401efb 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,7 +5,7 @@ Features ✨:
  -
 
 Improvements 🙌:
- -
+ - Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774)
 
 Bugfix 🐛:
  - Display name not shown under Settings/General (#1926)
diff --git a/vector/src/main/java/im/vector/app/core/extensions/TextView.kt b/vector/src/main/java/im/vector/app/core/extensions/TextView.kt
index cafcf6d1d8..44b85df93a 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/TextView.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/TextView.kt
@@ -24,7 +24,9 @@ import android.widget.TextView
 import androidx.annotation.AttrRes
 import androidx.annotation.StringRes
 import androidx.core.view.isVisible
+import com.google.android.material.snackbar.Snackbar
 import im.vector.app.R
+import im.vector.app.core.utils.copyToClipboard
 import im.vector.app.features.themes.ThemeUtils
 
 /**
@@ -68,3 +70,18 @@ fun TextView.setTextWithColoredPart(@StringRes fullTextRes: Int,
                 }
             }
 }
+
+/**
+ * Set long click listener to copy the current text of the TextView to the clipboard and show a Snackbar
+ */
+fun TextView.copyOnLongClick() {
+    setOnLongClickListener { view ->
+        (view as? TextView)
+                ?.text
+                ?.let { text ->
+                    copyToClipboard(view.context, text, false)
+                    Snackbar.make(view, view.resources.getString(R.string.copied_to_clipboard), Snackbar.LENGTH_SHORT).show()
+                }
+        true
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt
index 9c6e813f0b..cda2d83e3d 100644
--- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt
@@ -35,6 +35,7 @@ import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
 import im.vector.app.core.dialogs.ConfirmationDialogBuilder
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.extensions.copyOnLongClick
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.platform.StateView
@@ -44,11 +45,11 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheet
 import im.vector.app.features.home.AvatarRenderer
 import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
 import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
-import org.matrix.android.sdk.api.session.room.powerlevels.Role
-import org.matrix.android.sdk.api.util.MatrixItem
 import kotlinx.android.parcel.Parcelize
 import kotlinx.android.synthetic.main.fragment_matrix_profile.*
 import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
+import org.matrix.android.sdk.api.session.room.powerlevels.Role
+import org.matrix.android.sdk.api.util.MatrixItem
 import javax.inject.Inject
 
 @Parcelize
@@ -110,6 +111,12 @@ class RoomMemberProfileFragment @Inject constructor(
                 is RoomMemberProfileViewEvents.OnInviteActionSuccess       -> Unit
             }.exhaustive
         }
+        setupLongClicks()
+    }
+
+    private fun setupLongClicks() {
+        memberProfileNameView.copyOnLongClick()
+        memberProfileIdView.copyOnLongClick()
     }
 
     private fun handleShowPowerLevelDemoteWarning(event: RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
index 2722d54950..518932fdcb 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
@@ -34,16 +34,12 @@ import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.yalantis.ucrop.UCrop
-import im.vector.lib.multipicker.MultiPicker
-import im.vector.lib.multipicker.entity.MultiPickerImageType
-import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
-import org.matrix.android.sdk.api.util.MatrixItem
-import org.matrix.android.sdk.api.util.toMatrixItem
 import im.vector.app.R
 import im.vector.app.core.animations.AppBarStateChangeListener
 import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.extensions.copyOnLongClick
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.intent.getFilenameFromUri
@@ -62,9 +58,14 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
 import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
 import im.vector.app.features.media.BigImageViewerActivity
 import im.vector.app.features.media.createUCropWithDefaultSettings
+import im.vector.lib.multipicker.MultiPicker
+import im.vector.lib.multipicker.entity.MultiPickerImageType
 import kotlinx.android.parcel.Parcelize
 import kotlinx.android.synthetic.main.fragment_matrix_profile.*
 import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
+import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
+import org.matrix.android.sdk.api.util.MatrixItem
+import org.matrix.android.sdk.api.util.toMatrixItem
 import timber.log.Timber
 import java.io.File
 import javax.inject.Inject
@@ -120,6 +121,13 @@ class RoomProfileFragment @Inject constructor(
                 .observe()
                 .subscribe { handleQuickActions(it) }
                 .disposeOnDestroyView()
+        setupLongClicks()
+    }
+
+    private fun setupLongClicks() {
+        roomProfileNameView.copyOnLongClick()
+        roomProfileAliasView.copyOnLongClick()
+        roomProfileTopicView.copyOnLongClick()
     }
 
     override fun onOptionsItemSelected(item: MenuItem): Boolean {

From ef912e066bafabc909d17a10dcb6d0d18d3f6953 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Wed, 26 Aug 2020 12:29:46 +0200
Subject: [PATCH 10/13] Remove unused resource

---
 .../disclaimer_top_banner_foreground.xml      | 38 -------------------
 1 file changed, 38 deletions(-)
 delete mode 100644 vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml

diff --git a/vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml b/vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml
deleted file mode 100644
index c031da1e5b..0000000000
--- a/vector/src/main/res/drawable/disclaimer_top_banner_foreground.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="163dp"
-    android:height="127dp"
-    android:viewportWidth="163"
-    android:viewportHeight="127">
-  <path
-      android:pathData="M113.569,169.348C129.753,185.532 153.161,188.363 165.853,175.671C178.545,162.979 175.715,139.57 159.531,123.386C143.347,107.203 44.653,8.372 44.653,8.372L35.819,18.975C35.819,18.975 39.221,27.764 37.204,30.186C35.186,32.608 24.684,32.34 24.684,32.34L6.34,54.358C6.34,54.358 4.89,60.67 6.106,61.885C41.927,97.706 77.748,133.527 113.569,169.348Z"
-      android:strokeWidth="1"
-      android:fillColor="#000000"
-      android:fillAlpha="0.147508741"
-      android:fillType="evenOdd"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="M19.447,19.068L19.447,27.722L28.202,27.713C28.313,27.713 28.415,27.71 28.515,27.703C30.818,27.551 32.617,25.656 32.617,23.391C32.617,21.007 30.641,19.068 28.211,19.068L19.447,19.068ZM10.788,61.81C6.006,61.81 2.129,58.007 2.129,53.316L2.129,37.127C2.097,36.833 2.08,36.535 2.08,36.232C2.08,35.925 2.096,35.621 2.129,35.322L2.129,10.574C2.129,5.882 6.006,2.079 10.788,2.079L28.211,2.079C40.19,2.079 49.935,11.639 49.935,23.391C49.935,34.563 41.04,43.902 29.684,44.652C29.201,44.685 28.704,44.702 28.211,44.702L19.447,44.71L19.447,53.316C19.447,58.007 15.57,61.81 10.788,61.81L10.788,61.81Z"
-      android:strokeWidth="1"
-      android:fillColor="#A2DDEF"
-      android:fillType="evenOdd"
-      android:strokeColor="#00000000"/>
-  <path
-      android:pathData="M19.447,19.068L19.447,27.722L28.202,27.713C28.313,27.713 28.415,27.71 28.515,27.703C30.818,27.551 32.617,25.656 32.617,23.391C32.617,21.007 30.641,19.068 28.211,19.068L19.447,19.068ZM10.788,61.81C6.006,61.81 2.129,58.007 2.129,53.316L2.129,10.574C2.129,5.882 6.006,2.079 10.788,2.079L28.211,2.079C40.19,2.079 49.935,11.639 49.935,23.391C49.935,34.563 41.04,43.902 29.684,44.652C29.201,44.685 28.704,44.702 28.211,44.702L19.447,44.71L19.447,53.316C19.447,58.007 15.57,61.81 10.788,61.81Z"
-      android:strokeWidth="1.52445396"
-      android:fillColor="#00000000"
-      android:strokeColor="#368BD6"
-      android:fillType="evenOdd"/>
-  <path
-      android:pathData="M10.788,53.315L10.788,10.574L28.211,10.574C35.426,10.574 41.276,16.312 41.276,23.39C41.276,30.175 35.902,35.729 29.102,36.178C28.807,36.197 28.51,36.207 28.211,36.207L10.788,36.207"
-      android:strokeWidth="1.52445396"
-      android:fillColor="#00000000"
-      android:strokeColor="#368BD6"
-      android:fillType="evenOdd"
-      android:strokeLineCap="round"/>
-  <path
-      android:pathData="M17.923,5.702C19.25,7.56 19.76,9.815 19.358,12.048C18.956,14.283 17.691,16.229 15.795,17.531C11.881,20.217 6.467,19.282 3.726,15.445C2.399,13.587 1.889,11.333 2.291,9.099C2.693,6.864 3.958,4.917 5.854,3.617C9.768,0.93 15.182,1.865 17.923,5.702ZM41.347,61.805C38.618,61.805 35.934,60.543 34.248,58.185L22.011,41.052C19.266,37.21 20.217,31.913 24.133,29.222C28.049,26.528 33.449,27.461 36.193,31.303L48.431,48.435C51.175,52.277 50.225,57.574 46.309,60.266C44.797,61.306 43.063,61.805 41.347,61.805Z"
-      android:strokeWidth="1"
-      android:fillColor="#368BD6"
-      android:fillType="evenOdd"
-      android:strokeColor="#00000000"/>
-</vector>

From 9f3f981ab07fdf0813b860415949a459cc585a09 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Wed, 26 Aug 2020 12:30:26 +0200
Subject: [PATCH 11/13] Use cached Views

---
 .../im/vector/app/core/preference/PushRulePreference.kt   | 3 +--
 .../app/core/preference/VectorEditTextPreference.kt       | 2 +-
 .../im/vector/app/core/preference/VectorPreference.kt     | 8 ++++----
 .../app/core/preference/VectorPreferenceCategory.kt       | 2 +-
 .../vector/app/core/preference/VectorSwitchPreference.kt  | 2 +-
 5 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt b/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt
index 87584a9db0..9c4878ef06 100755
--- a/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt
@@ -20,7 +20,6 @@ import android.content.Context
 import android.util.AttributeSet
 import android.view.View
 import android.widget.RadioGroup
-import android.widget.TextView
 import androidx.preference.PreferenceViewHolder
 import im.vector.app.R
 import org.matrix.android.sdk.api.pushrules.RuleSetKey
@@ -162,7 +161,7 @@ class PushRulePreference : VectorPreference {
     override fun onBindViewHolder(holder: PreferenceViewHolder) {
         super.onBindViewHolder(holder)
 
-        holder.itemView.findViewById<TextView>(android.R.id.summary)?.visibility = View.GONE
+        holder.findViewById(android.R.id.summary)?.visibility = View.GONE
         holder.itemView.setOnClickListener(null)
         holder.itemView.setOnLongClickListener(null)
 
diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt
index 840e5fa510..348fcffc9b 100644
--- a/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/VectorEditTextPreference.kt
@@ -45,7 +45,7 @@ class VectorEditTextPreference : EditTextPreference {
     override fun onBindViewHolder(holder: PreferenceViewHolder) {
         // display the title in multi-line to avoid ellipsis.
         try {
-            holder.itemView.findViewById<TextView>(android.R.id.title)?.isSingleLine = false
+            (holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false
         } catch (e: Exception) {
             Timber.e(e, "onBindView")
         }
diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt
index 4a9bb6a6f5..dd887dba67 100755
--- a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt
@@ -84,15 +84,15 @@ open class VectorPreference : Preference {
 
         // display the title in multi-line to avoid ellipsis.
         try {
-            val title = itemView.findViewById<TextView>(android.R.id.title)
-            val summary = itemView.findViewById<TextView>(android.R.id.summary)
+            val title = holder.findViewById(android.R.id.title) as? TextView
+            val summary = holder.findViewById(android.R.id.summary) as? TextView
             if (title != null) {
                 title.isSingleLine = false
                 title.setTypeface(null, mTypeface)
             }
 
-            if (title !== summary) {
-                summary.setTypeface(null, mTypeface)
+            summary?.setTypeface(null, mTypeface)
+
             }
 
             // cancel existing animation (find a way to resume if happens during anim?)
diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt b/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt
index e61cde8ebd..eb59da640d 100644
--- a/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/VectorPreferenceCategory.kt
@@ -45,7 +45,7 @@ class VectorPreferenceCategory : PreferenceCategory {
     override fun onBindViewHolder(holder: PreferenceViewHolder) {
         super.onBindViewHolder(holder)
 
-        val titleTextView = holder.itemView.findViewById<TextView>(android.R.id.title)
+        val titleTextView = holder.findViewById(android.R.id.title) as? TextView
 
         titleTextView?.setTypeface(null, Typeface.BOLD)
         titleTextView?.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary))
diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt
index c97991bfcb..346e8488b9 100644
--- a/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/VectorSwitchPreference.kt
@@ -58,7 +58,7 @@ class VectorSwitchPreference : SwitchPreference {
 
     override fun onBindViewHolder(holder: PreferenceViewHolder) {
         // display the title in multi-line to avoid ellipsis.
-        holder.itemView.findViewById<TextView>(android.R.id.title)?.isSingleLine = false
+        (holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false
 
         // cancel existing animation (find a way to resume if happens during anim?)
         currentHighlightAnimator?.cancel()

From 249f268fb52b949926a1dad4089b8d27547453bb Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Wed, 26 Aug 2020 12:55:49 +0200
Subject: [PATCH 12/13] Fix bad color for settings icon on Android < 24 (#1786)

---
 CHANGES.md                                      |  1 +
 .../app/core/preference/VectorPreference.kt     | 17 +++++++++++++++++
 .../settings/VectorSettingsRootFragment.kt      | 13 ++++++++++++-
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/CHANGES.md b/CHANGES.md
index a9f2e896aa..f7682028e1 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -9,6 +9,7 @@ Improvements 🙌:
 
 Bugfix 🐛:
  - Display name not shown under Settings/General (#1926)
+ - Fix bad color for settings icon on Android < 24 (#1786)
 
 Translations 🗣:
  -
diff --git a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt
index dd887dba67..a40ddef6ab 100755
--- a/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/VectorPreference.kt
@@ -20,12 +20,15 @@ import android.animation.Animator
 import android.animation.ArgbEvaluator
 import android.animation.ValueAnimator
 import android.content.Context
+import android.content.res.ColorStateList
 import android.graphics.Color
 import android.graphics.Typeface
 import android.util.AttributeSet
 import android.view.View
+import android.widget.ImageView
 import android.widget.TextView
 import androidx.core.animation.doOnEnd
+import androidx.core.widget.ImageViewCompat
 import androidx.preference.Preference
 import androidx.preference.PreferenceViewHolder
 import im.vector.app.R
@@ -76,6 +79,12 @@ open class VectorPreference : Preference {
             notifyChanged()
         }
 
+    var tintIcon = false
+        set(value) {
+            field = value
+            notifyChanged()
+        }
+
     var currentHighlightAnimator: Animator? = null
 
     override fun onBindViewHolder(holder: PreferenceViewHolder) {
@@ -93,6 +102,14 @@ open class VectorPreference : Preference {
 
             summary?.setTypeface(null, mTypeface)
 
+            if (tintIcon) {
+                // Tint icons (See #1786)
+                val icon = holder.findViewById(android.R.id.icon) as? ImageView
+
+                icon?.let {
+                    val color = ThemeUtils.getColor(context, R.attr.riotx_header_panel_text_secondary)
+                    ImageViewCompat.setImageTintList(it, ColorStateList.valueOf(color))
+                }
             }
 
             // cancel existing animation (find a way to resume if happens during anim?)
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt
index d2ec1a1543..3f3811ce76 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt
@@ -16,7 +16,9 @@
 
 package im.vector.app.features.settings
 
+import android.os.Build
 import im.vector.app.R
+import im.vector.app.core.preference.VectorPreference
 import javax.inject.Inject
 
 class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
@@ -25,6 +27,15 @@ class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragm
     override val preferenceXmlRes = R.xml.vector_settings_root
 
     override fun bindPref() {
-        // Nothing to do
+        // Tint icon on API < 24
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+            tintIcons()
+        }
+    }
+
+    private fun tintIcons() {
+        for (i in 0 until preferenceScreen.preferenceCount) {
+            (preferenceScreen.getPreference(i) as? VectorPreference)?.let { it.tintIcon = true }
+        }
     }
 }

From 25ea221d4727c1cbba6a29ce5a742db65c17cc4d Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Wed, 26 Aug 2020 15:28:48 +0200
Subject: [PATCH 13/13] Create a script to import SAS strings (#1909) It will
 be run at the next Weblate sync, since we have to remove previous
 translations

---
 CHANGES.md                  |   1 +
 tools/import_sas_strings.py | 103 ++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)
 create mode 100755 tools/import_sas_strings.py

diff --git a/CHANGES.md b/CHANGES.md
index f48436d279..ab4a121c6a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -22,6 +22,7 @@ Build 🧱:
 
 Other changes:
  - Use File extension functions to make code more concise (#1996)
+ - Create a script to import SAS strings (#1909)
 
 Changes in Element 1.0.5 (2020-08-21)
 ===================================================
diff --git a/tools/import_sas_strings.py b/tools/import_sas_strings.py
new file mode 100755
index 0000000000..faf4ed7080
--- /dev/null
+++ b/tools/import_sas_strings.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+
+#  Copyright (c) 2020 New Vector Ltd
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import argparse
+import json
+import os
+import os.path
+# Run `pip3 install requests` if not installed yet
+import requests
+
+### Arguments
+
+parser = argparse.ArgumentParser(description='Download sas string from matrix-doc.')
+parser.add_argument('-v',
+                    '--verbose',
+                    help="increase output verbosity.",
+                    action="store_true")
+
+args = parser.parse_args()
+
+if args.verbose:
+    print("Argument:")
+    print(args)
+
+base_url = "https://raw.githubusercontent.com/matrix-org/matrix-doc/master/data-definitions/sas-emoji.json"
+
+print("Downloading " + base_url + "…")
+
+r0 = requests.get(base_url)
+data0 = json.loads(r0.content.decode())
+
+if args.verbose:
+    print("Json data:")
+    print(data0)
+
+print()
+
+# emoji -> translation
+default = dict()
+# Language -> emoji -> translation
+cumul = dict()
+
+for emoji in data0:
+    description = emoji["description"]
+    if args.verbose:
+        print("Description: " + description)
+    default[description] = description
+
+    for lang in emoji["translated_descriptions"]:
+        if args.verbose:
+            print("Lang: " + lang)
+        if not (lang in cumul):
+            cumul[lang] = dict()
+        cumul[lang][description] = emoji["translated_descriptions"][lang]
+
+if args.verbose:
+    print(default)
+    print(cumul)
+
+def write_file(file, dict):
+    print("Writing file " + file)
+    if args.verbose:
+        print("With")
+        print(dict)
+    os.makedirs(os.path.dirname(file), exist_ok=True)
+    with open(file, mode="w", encoding="utf8") as o:
+        o.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
+        o.write("<resources>\n")
+        o.write("    <!-- Generated file, do not edit -->\n")
+        for key in dict:
+            if dict[key] is None:
+                continue
+            o.write("    <string name=\"verification_emoji_" + key.lower().replace(" ", "_") + "\">" + dict[key].replace("'", "\\'") + "</string>\n")
+        o.write("</resources>\n")
+
+scripts_dir = os.path.dirname(os.path.abspath(__file__))
+data_defs_dir = os.path.join(scripts_dir, "../matrix-sdk-android/src/main/res")
+
+# Write default file
+write_file(os.path.join(data_defs_dir, "values/strings_sas.xml"), default)
+
+# Write each language file
+for lang in cumul:
+    androidLang = lang\
+        .replace("_", "-r")\
+        .replace("zh-rHans", "zh-rCN")
+    write_file(os.path.join(data_defs_dir, "values-" + androidLang + "/strings_sas.xml"), cumul[lang])
+
+print()
+print("Success!")