forked from GitHub-Mirror/riotX-android
Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
Benoit Marty | a89f0ddd1d | |
Benoit Marty | 9cd69d1e33 | |
Benoit Marty | df6080b1da |
23
CHANGES.md
23
CHANGES.md
|
@ -1,26 +1,3 @@
|
||||||
Changes in RiotX 0.5.0 (2019-XX-XX)
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
Features:
|
|
||||||
-
|
|
||||||
|
|
||||||
Improvements:
|
|
||||||
- Reduce default release build log level, and lab option to enable more logs.
|
|
||||||
|
|
||||||
Other changes:
|
|
||||||
-
|
|
||||||
|
|
||||||
Bugfix:
|
|
||||||
- Fix crash due to missing informationData (#535)
|
|
||||||
- Progress in initial sync dialog is decreasing for a step and should not (#532)
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
-
|
|
||||||
|
|
||||||
Build:
|
|
||||||
- Fix issue with version name (#533)
|
|
||||||
- Fix rendering issue of accepted third party invitation event
|
|
||||||
|
|
||||||
Changes in RiotX 0.4.0 (2019-XX-XX)
|
Changes in RiotX 0.4.0 (2019-XX-XX)
|
||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule
|
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import kotlin.random.Random
|
import java.util.*
|
||||||
|
|
||||||
internal class CryptoStoreHelper {
|
internal class CryptoStoreHelper {
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ internal class CryptoStoreHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createCredential() = Credentials(
|
fun createCredential() = Credentials(
|
||||||
userId = "userId_" + Random.nextInt(),
|
userId = "userId_" + Random().nextInt(),
|
||||||
homeServer = "http://matrix.org",
|
homeServer = "http://matrix.org",
|
||||||
accessToken = "access_token",
|
accessToken = "access_token",
|
||||||
refreshToken = null,
|
refreshToken = null,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.matrix.android.api.comparators
|
package im.vector.matrix.android.api.comparators
|
||||||
|
|
||||||
import im.vector.matrix.android.api.interfaces.DatedObject
|
import im.vector.matrix.android.api.interfaces.DatedObject
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object DatedObjectComparators {
|
object DatedObjectComparators {
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.matrix.android.api.extensions
|
||||||
import im.vector.matrix.android.api.comparators.DatedObjectComparators
|
import im.vector.matrix.android.api.comparators.DatedObjectComparators
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||||
import java.util.Collections
|
import java.util.*
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* MXDeviceInfo
|
* MXDeviceInfo
|
||||||
|
|
|
@ -18,17 +18,18 @@ package im.vector.matrix.android.api.pushrules
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.RoomService
|
import im.vector.matrix.android.api.session.room.RoomService
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
private val regex = Regex("^(==|<=|>=|<|>)?(\\d*)$")
|
private val regex = Pattern.compile("^(==|<=|>=|<|>)?(\\d*)$")
|
||||||
|
|
||||||
class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_count) {
|
class RoomMemberCountCondition(val `is`: String) : Condition(Kind.room_member_count) {
|
||||||
|
|
||||||
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
|
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
|
||||||
return conditionResolver.resolveRoomMemberCountCondition(this)
|
return conditionResolver.resolveRoomMemberCountCondition(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun technicalDescription(): String {
|
override fun technicalDescription(): String {
|
||||||
return "Room member count is $iz"
|
return "Room member count is $`is`"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSatisfied(event: Event, session: RoomService?): Boolean {
|
fun isSatisfied(event: Event, session: RoomService?): Boolean {
|
||||||
|
@ -55,9 +56,12 @@ class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_coun
|
||||||
*/
|
*/
|
||||||
private fun parseIsField(): Pair<String?, Int>? {
|
private fun parseIsField(): Pair<String?, Int>? {
|
||||||
try {
|
try {
|
||||||
val match = regex.find(iz) ?: return null
|
val match = regex.matcher(`is`)
|
||||||
val (prefix, count) = match.destructured
|
if (match.find()) {
|
||||||
return prefix to count.toInt()
|
val prefix = match.group(1)
|
||||||
|
val count = match.group(2).toInt()
|
||||||
|
return prefix to count
|
||||||
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
Timber.d(t)
|
Timber.d(t)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ import androidx.lifecycle.LiveData
|
||||||
|
|
||||||
interface InitialSyncProgressService {
|
interface InitialSyncProgressService {
|
||||||
|
|
||||||
fun getInitialSyncProgressStatus() : LiveData<Status?>
|
fun getLiveStatus() : LiveData<Status?>
|
||||||
|
|
||||||
data class Status(
|
data class Status(
|
||||||
@StringRes val statusText: Int,
|
@StringRes val statusText: Int?,
|
||||||
val percentProgress: Int = 0
|
val percentProgress: Int = 0
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@ package im.vector.matrix.android.api.session.pushers
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
interface PushersService {
|
interface PushersService {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.matrix.android.api.session.room.model.PowerLevels
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
|
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
|
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
|
||||||
import im.vector.matrix.android.internal.auth.data.ThreePidMedium
|
import im.vector.matrix.android.internal.auth.data.ThreePidMedium
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter to create a room, with facilities functions to configure it
|
* Parameter to create a room, with facilities functions to configure it
|
||||||
|
@ -132,7 +133,7 @@ class CreateRoomParams {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (null == initialStates) {
|
if (null == initialStates) {
|
||||||
initialStates = mutableListOf(algoEvent)
|
initialStates = Arrays.asList<Event>(algoEvent)
|
||||||
} else {
|
} else {
|
||||||
initialStates!!.add(algoEvent)
|
initialStates!!.add(algoEvent)
|
||||||
}
|
}
|
||||||
|
@ -165,7 +166,7 @@ class CreateRoomParams {
|
||||||
content = contentMap.toContent())
|
content = contentMap.toContent())
|
||||||
|
|
||||||
if (null == initialStates) {
|
if (null == initialStates) {
|
||||||
initialStates = mutableListOf(historyVisibilityEvent)
|
initialStates = Arrays.asList<Event>(historyVisibilityEvent)
|
||||||
} else {
|
} else {
|
||||||
initialStates!!.add(historyVisibilityEvent)
|
initialStates!!.add(historyVisibilityEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.math.BigInteger
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.Calendar
|
import java.util.*
|
||||||
import javax.crypto.*
|
import javax.crypto.*
|
||||||
import javax.crypto.spec.GCMParameterSpec
|
import javax.crypto.spec.GCMParameterSpec
|
||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
@ -479,7 +479,12 @@ object SecretStoringUtils {
|
||||||
val output = Cipher.getInstance(RSA_MODE)
|
val output = Cipher.getInstance(RSA_MODE)
|
||||||
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.privateKey)
|
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.privateKey)
|
||||||
|
|
||||||
return CipherInputStream(encrypted, output).use { it.readBytes() }
|
val bos = ByteArrayOutputStream()
|
||||||
|
CipherInputStream(encrypted, output).use {
|
||||||
|
it.copyTo(bos)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bos.toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun formatMExtract(bis: InputStream): Pair<ByteArray, ByteArray> {
|
private fun formatMExtract(bis: InputStream): Pair<ByteArray, ByteArray> {
|
||||||
|
@ -490,7 +495,14 @@ object SecretStoringUtils {
|
||||||
val iv = ByteArray(ivSize)
|
val iv = ByteArray(ivSize)
|
||||||
bis.read(iv, 0, ivSize)
|
bis.read(iv, 0, ivSize)
|
||||||
|
|
||||||
val encrypted = bis.readBytes()
|
|
||||||
|
val bos = ByteArrayOutputStream()
|
||||||
|
var next = bis.read()
|
||||||
|
while (next != -1) {
|
||||||
|
bos.write(next)
|
||||||
|
next = bis.read()
|
||||||
|
}
|
||||||
|
val encrypted = bos.toByteArray()
|
||||||
return Pair(iv, encrypted)
|
return Pair(iv, encrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +530,14 @@ object SecretStoringUtils {
|
||||||
val iv = ByteArray(ivSize)
|
val iv = ByteArray(ivSize)
|
||||||
bis.read(iv)
|
bis.read(iv)
|
||||||
|
|
||||||
val encrypted = bis.readBytes()
|
val bos = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
var next = bis.read()
|
||||||
|
while (next != -1) {
|
||||||
|
bos.write(next)
|
||||||
|
next = bis.read()
|
||||||
|
}
|
||||||
|
val encrypted = bos.toByteArray()
|
||||||
return Triple(encryptedKey, iv, encrypted)
|
return Triple(encryptedKey, iv, encrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +579,14 @@ object SecretStoringUtils {
|
||||||
val iv = ByteArray(ivSize)
|
val iv = ByteArray(ivSize)
|
||||||
bis.read(iv)
|
bis.read(iv)
|
||||||
|
|
||||||
val encrypted = bis.readBytes()
|
val bos = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
var next = bis.read()
|
||||||
|
while (next != -1) {
|
||||||
|
bos.write(next)
|
||||||
|
next = bis.read()
|
||||||
|
}
|
||||||
|
val encrypted = bos.toByteArray()
|
||||||
return Triple(salt, iv, encrypted)
|
return Triple(salt, iv, encrypted)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -93,7 +93,7 @@ import kotlin.math.max
|
||||||
* Specially, it tracks all room membership changes events in order to do keys updates.
|
* Specially, it tracks all room membership changes events in order to do keys updates.
|
||||||
*/
|
*/
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class DefaultCryptoService @Inject constructor(
|
internal class CryptoManager @Inject constructor(
|
||||||
// Olm Manager
|
// Olm Manager
|
||||||
private val olmManager: OlmManager,
|
private val olmManager: OlmManager,
|
||||||
// The credentials,
|
// The credentials,
|
||||||
|
@ -1067,6 +1067,6 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "DefaultCryptoService of " + credentials.userId + " (" + credentials.deviceId + ")"
|
return "CryptoManager of " + credentials.userId + " (" + credentials.deviceId + ")"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -105,7 +105,7 @@ internal abstract class CryptoModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindCryptoService(cryptoService: DefaultCryptoService): CryptoService
|
abstract fun bindCryptoService(cryptoManager: CryptoManager): CryptoService
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindDeleteDeviceTask(deleteDeviceTask: DefaultDeleteDeviceTask): DeleteDeviceTask
|
abstract fun bindDeleteDeviceTask(deleteDeviceTask: DefaultDeleteDeviceTask): DeleteDeviceTask
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.matrix.android.internal.crypto
|
package im.vector.matrix.android.internal.crypto
|
||||||
|
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class ObjectSigner @Inject constructor(private val credentials: Credentials,
|
internal class ObjectSigner @Inject constructor(private val credentials: Credentials,
|
||||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.matrix.android.internal.crypto.model.event.OlmPayloadContent
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
import im.vector.matrix.android.internal.util.convertFromUTF8
|
import im.vector.matrix.android.internal.util.convertFromUTF8
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
internal class MXOlmDecryption(
|
internal class MXOlmDecryption(
|
||||||
// The olm device interface
|
// The olm device interface
|
||||||
|
@ -157,14 +158,33 @@ internal class MXOlmDecryption(
|
||||||
* @return payload, if decrypted successfully.
|
* @return payload, if decrypted successfully.
|
||||||
*/
|
*/
|
||||||
private fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
|
private fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
|
||||||
val sessionIds = olmDevice.getSessionIds(theirDeviceIdentityKey) ?: emptySet()
|
val sessionIdsSet = olmDevice.getSessionIds(theirDeviceIdentityKey)
|
||||||
|
|
||||||
val messageBody = message["body"] as? String ?: return null
|
val sessionIds: List<String>
|
||||||
val messageType = when (val typeAsVoid = message["type"]) {
|
|
||||||
is Double -> typeAsVoid.toInt()
|
if (null == sessionIdsSet) {
|
||||||
is Int -> typeAsVoid
|
sessionIds = ArrayList()
|
||||||
is Long -> typeAsVoid.toInt()
|
} else {
|
||||||
else -> return null
|
sessionIds = ArrayList(sessionIdsSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageBody = message["body"] as? String
|
||||||
|
var messageType: Int? = null
|
||||||
|
|
||||||
|
val typeAsVoid = message["type"]
|
||||||
|
|
||||||
|
if (null != typeAsVoid) {
|
||||||
|
if (typeAsVoid is Double) {
|
||||||
|
messageType = typeAsVoid.toInt()
|
||||||
|
} else if (typeAsVoid is Int) {
|
||||||
|
messageType = typeAsVoid
|
||||||
|
} else if (typeAsVoid is Long) {
|
||||||
|
messageType = typeAsVoid.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == messageBody || null == messageType) {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try each session in turn
|
// Try each session in turn
|
||||||
|
|
|
@ -26,6 +26,7 @@ import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
import java.util.*
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
@ -58,7 +59,8 @@ object MXEncryptedAttachments {
|
||||||
// Half of the IV is random, the lower order bits are zeroed
|
// Half of the IV is random, the lower order bits are zeroed
|
||||||
// such that the counter never wraps.
|
// such that the counter never wraps.
|
||||||
// See https://github.com/matrix-org/matrix-ios-kit/blob/3dc0d8e46b4deb6669ed44f72ad79be56471354c/MatrixKit/Models/Room/MXEncryptedAttachments.m#L75
|
// See https://github.com/matrix-org/matrix-ios-kit/blob/3dc0d8e46b4deb6669ed44f72ad79be56471354c/MatrixKit/Models/Room/MXEncryptedAttachments.m#L75
|
||||||
val initVectorBytes = ByteArray(16) { 0.toByte() }
|
val initVectorBytes = ByteArray(16)
|
||||||
|
Arrays.fill(initVectorBytes, 0.toByte())
|
||||||
|
|
||||||
val ivRandomPart = ByteArray(8)
|
val ivRandomPart = ByteArray(8)
|
||||||
secureRandom.nextBytes(ivRandomPart)
|
secureRandom.nextBytes(ivRandomPart)
|
||||||
|
@ -113,7 +115,7 @@ object MXEncryptedAttachments {
|
||||||
encryptedByteArray = outStream.toByteArray()
|
encryptedByteArray = outStream.toByteArray()
|
||||||
)
|
)
|
||||||
|
|
||||||
Timber.v("Encrypt in ${System.currentTimeMillis() - t0} ms")
|
Timber.v("Encrypt in " + (System.currentTimeMillis() - t0) + " ms")
|
||||||
return Try.just(result)
|
return Try.just(result)
|
||||||
} catch (oom: OutOfMemoryError) {
|
} catch (oom: OutOfMemoryError) {
|
||||||
Timber.e(oom, "## encryptAttachment failed")
|
Timber.e(oom, "## encryptAttachment failed")
|
||||||
|
@ -204,13 +206,13 @@ object MXEncryptedAttachments {
|
||||||
val decryptedStream = ByteArrayInputStream(outStream.toByteArray())
|
val decryptedStream = ByteArrayInputStream(outStream.toByteArray())
|
||||||
outStream.close()
|
outStream.close()
|
||||||
|
|
||||||
Timber.v("Decrypt in ${System.currentTimeMillis() - t0} ms")
|
Timber.v("Decrypt in " + (System.currentTimeMillis() - t0) + " ms")
|
||||||
|
|
||||||
return decryptedStream
|
return decryptedStream
|
||||||
} catch (oom: OutOfMemoryError) {
|
} catch (oom: OutOfMemoryError) {
|
||||||
Timber.e(oom, "## decryptAttachment() : failed ${oom.message}")
|
Timber.e(oom, "## decryptAttachment() : failed " + oom.message)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## decryptAttachment() : failed ${e.message}")
|
Timber.e(e, "## decryptAttachment() : failed " + e.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -226,20 +228,34 @@ object MXEncryptedAttachments {
|
||||||
* Base64 URL conversion methods
|
* Base64 URL conversion methods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private fun base64UrlToBase64(base64Url: String): String {
|
private fun base64UrlToBase64(base64Url: String?): String? {
|
||||||
return base64Url.replace('-', '+')
|
var result = base64Url
|
||||||
.replace('_', '/')
|
if (null != result) {
|
||||||
|
result = result.replace("-".toRegex(), "+")
|
||||||
|
result = result.replace("_".toRegex(), "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun base64ToBase64Url(base64: String): String {
|
private fun base64ToBase64Url(base64: String?): String? {
|
||||||
return base64.replace("\n".toRegex(), "")
|
var result = base64
|
||||||
.replace("\\+".toRegex(), "-")
|
if (null != result) {
|
||||||
.replace('/', '_')
|
result = result.replace("\n".toRegex(), "")
|
||||||
.replace("=", "")
|
result = result.replace("\\+".toRegex(), "-")
|
||||||
|
result = result.replace("/".toRegex(), "_")
|
||||||
|
result = result.replace("=".toRegex(), "")
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun base64ToUnpaddedBase64(base64: String): String {
|
private fun base64ToUnpaddedBase64(base64: String?): String? {
|
||||||
return base64.replace("\n".toRegex(), "")
|
var result = base64
|
||||||
.replace("=", "")
|
if (null != result) {
|
||||||
|
result = result.replace("\n".toRegex(), "")
|
||||||
|
result = result.replace("=".toRegex(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,9 @@ import org.matrix.olm.OlmPkEncryption
|
||||||
import org.matrix.olm.OlmPkMessage
|
import org.matrix.olm.OlmPkMessage
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.security.InvalidParameterException
|
import java.security.InvalidParameterException
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.random.Random
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A KeysBackup class instance manage incremental backup of e2e keys (megolm keys)
|
* A KeysBackup class instance manage incremental backup of e2e keys (megolm keys)
|
||||||
|
@ -113,6 +114,8 @@ internal class KeysBackup @Inject constructor(
|
||||||
// The backup key being used.
|
// The backup key being used.
|
||||||
private var backupOlmPkEncryption: OlmPkEncryption? = null
|
private var backupOlmPkEncryption: OlmPkEncryption? = null
|
||||||
|
|
||||||
|
private val random = Random()
|
||||||
|
|
||||||
private var backupAllGroupSessionsCallback: MatrixCallback<Unit>? = null
|
private var backupAllGroupSessionsCallback: MatrixCallback<Unit>? = null
|
||||||
|
|
||||||
private var keysBackupStateListener: KeysBackupStateListener? = null
|
private var keysBackupStateListener: KeysBackupStateListener? = null
|
||||||
|
@ -845,7 +848,7 @@ internal class KeysBackup @Inject constructor(
|
||||||
// Wait between 0 and 10 seconds, to avoid backup requests from
|
// Wait between 0 and 10 seconds, to avoid backup requests from
|
||||||
// different clients hitting the server all at the same time when a
|
// different clients hitting the server all at the same time when a
|
||||||
// new key is sent
|
// new key is sent
|
||||||
val delayInMs = Random.nextLong(KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS)
|
val delayInMs = random.nextInt(KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS).toLong()
|
||||||
|
|
||||||
uiHandler.postDelayed({ backupKeys() }, delayInMs)
|
uiHandler.postDelayed({ backupKeys() }, delayInMs)
|
||||||
}
|
}
|
||||||
|
@ -1304,7 +1307,7 @@ internal class KeysBackup @Inject constructor(
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
storeSessionDataTask
|
storeSessionDataTask
|
||||||
.configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData)) {
|
.configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData)){
|
||||||
this.callback = sendingRequestCallback
|
this.callback = sendingRequestCallback
|
||||||
}
|
}
|
||||||
.executeBy(taskExecutor)
|
.executeBy(taskExecutor)
|
||||||
|
@ -1402,7 +1405,7 @@ internal class KeysBackup @Inject constructor(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Maximum delay in ms in {@link maybeBackupKeys}
|
// Maximum delay in ms in {@link maybeBackupKeys}
|
||||||
private const val KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS = 10_000L
|
private const val KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS = 10000
|
||||||
|
|
||||||
// Maximum number of keys to send at a time to the homeserver.
|
// Maximum number of keys to send at a time to the homeserver.
|
||||||
private const val KEY_BACKUP_SEND_KEYS_MAX_COUNT = 100
|
private const val KEY_BACKUP_SEND_KEYS_MAX_COUNT = 100
|
||||||
|
|
|
@ -22,7 +22,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import im.vector.matrix.android.api.listeners.ProgressListener
|
import im.vector.matrix.android.api.listeners.ProgressListener
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import kotlin.experimental.xor
|
import kotlin.experimental.xor
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.os.Handler
|
||||||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
||||||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener
|
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
internal class KeysBackupStateManager(private val uiHandler: Handler) {
|
internal class KeysBackupStateManager(private val uiHandler: Handler) {
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.squareup.moshi.JsonClass
|
||||||
import im.vector.matrix.android.api.util.JsonDict
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceKeys
|
import im.vector.matrix.android.internal.crypto.model.rest.DeviceKeys
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MXDeviceInfo(
|
data class MXDeviceInfo(
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.crypto.model
|
||||||
|
|
||||||
import im.vector.matrix.android.api.util.JsonDict
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
data class MXKey(
|
data class MXKey(
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +46,11 @@ data class MXKey(
|
||||||
* @return the signed data map
|
* @return the signed data map
|
||||||
*/
|
*/
|
||||||
fun signalableJSONDictionary(): Map<String, Any> {
|
fun signalableJSONDictionary(): Map<String, Any> {
|
||||||
return mapOf("key" to value)
|
val map = HashMap<String, Any>()
|
||||||
|
|
||||||
|
map["key"] = value
|
||||||
|
|
||||||
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.crypto.model
|
package im.vector.matrix.android.internal.crypto.model
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class MXUsersDevicesMap<E> {
|
class MXUsersDevicesMap<E> {
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ class MXUsersDevicesMap<E> {
|
||||||
* @return the user Ids
|
* @return the user Ids
|
||||||
*/
|
*/
|
||||||
val userIds: List<String>
|
val userIds: List<String>
|
||||||
get() = map.keys.toList()
|
get() = ArrayList(map.keys)
|
||||||
|
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
get() = map.isEmpty()
|
get() = map.isEmpty()
|
||||||
|
@ -39,7 +40,7 @@ class MXUsersDevicesMap<E> {
|
||||||
* @return the device ids list
|
* @return the device ids list
|
||||||
*/
|
*/
|
||||||
fun getUserDeviceIds(userId: String?): List<String>? {
|
fun getUserDeviceIds(userId: String?): List<String>? {
|
||||||
return if (!userId.isNullOrBlank() && map.containsKey(userId)) {
|
return if (userId?.isNotBlank() == true && map.containsKey(userId)) {
|
||||||
map[userId]!!.keys.toList()
|
map[userId]!!.keys.toList()
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
|
@ -52,7 +53,7 @@ class MXUsersDevicesMap<E> {
|
||||||
* @return the object
|
* @return the object
|
||||||
*/
|
*/
|
||||||
fun getObject(userId: String?, deviceId: String?): E? {
|
fun getObject(userId: String?, deviceId: String?): E? {
|
||||||
return if (!userId.isNullOrBlank() && !deviceId.isNullOrBlank()) {
|
return if (userId?.isNotBlank() == true && deviceId?.isNotBlank() == true && map.containsKey(userId)) {
|
||||||
map[userId]?.get(deviceId)
|
map[userId]?.get(deviceId)
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
|
@ -66,8 +67,11 @@ class MXUsersDevicesMap<E> {
|
||||||
*/
|
*/
|
||||||
fun setObject(userId: String?, deviceId: String?, o: E?) {
|
fun setObject(userId: String?, deviceId: String?, o: E?) {
|
||||||
if (null != o && userId?.isNotBlank() == true && deviceId?.isNotBlank() == true) {
|
if (null != o && userId?.isNotBlank() == true && deviceId?.isNotBlank() == true) {
|
||||||
val devices = map.getOrPut(userId) { HashMap() }
|
if (map[userId] == null) {
|
||||||
devices[deviceId] = o
|
map[userId] = HashMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
map[userId]?.put(deviceId, o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +82,7 @@ class MXUsersDevicesMap<E> {
|
||||||
* @param userId the user id
|
* @param userId the user id
|
||||||
*/
|
*/
|
||||||
fun setObjects(userId: String?, objectsPerDevices: Map<String, E>?) {
|
fun setObjects(userId: String?, objectsPerDevices: Map<String, E>?) {
|
||||||
if (!userId.isNullOrBlank()) {
|
if (userId?.isNotBlank() == true) {
|
||||||
if (null == objectsPerDevices) {
|
if (null == objectsPerDevices) {
|
||||||
map.remove(userId)
|
map.remove(userId)
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +97,7 @@ class MXUsersDevicesMap<E> {
|
||||||
* @param userId the user id.
|
* @param userId the user id.
|
||||||
*/
|
*/
|
||||||
fun removeUserObjects(userId: String?) {
|
fun removeUserObjects(userId: String?) {
|
||||||
if (!userId.isNullOrBlank()) {
|
if (userId?.isNotBlank() == true) {
|
||||||
map.remove(userId)
|
map.remove(userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.SendToDeviceBody
|
import im.vector.matrix.android.internal.crypto.model.rest.SendToDeviceBody
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
internal interface SendToDeviceTask : Task<SendToDeviceTask.Params, Unit> {
|
internal interface SendToDeviceTask : Task<SendToDeviceTask.Params, Unit> {
|
||||||
data class Params(
|
data class Params(
|
||||||
|
@ -45,7 +45,7 @@ internal class DefaultSendToDeviceTask @Inject constructor(private val cryptoApi
|
||||||
return executeRequest {
|
return executeRequest {
|
||||||
apiCall = cryptoApi.sendToDevice(
|
apiCall = cryptoApi.sendToDevice(
|
||||||
params.eventType,
|
params.eventType,
|
||||||
params.transactionId ?: Random.nextInt(Integer.MAX_VALUE).toString(),
|
params.transactionId ?: Random().nextInt(Integer.MAX_VALUE).toString(),
|
||||||
sendToDeviceBody
|
sendToDeviceBody
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
|
||||||
cancelTransaction(
|
cancelTransaction(
|
||||||
startReq.transactionID!!,
|
startReq.transactionID!!,
|
||||||
otherUserId!!,
|
otherUserId!!,
|
||||||
startReq.fromDevice ?: event.getSenderKey()!!,
|
startReq?.fromDevice ?: event.getSenderKey()!!,
|
||||||
CancelCode.UnknownMethod
|
CancelCode.UnknownMethod
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -388,13 +388,14 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
|
||||||
* This string must be unique for the pair of users performing verification for the duration that the transaction is valid
|
* This string must be unique for the pair of users performing verification for the duration that the transaction is valid
|
||||||
*/
|
*/
|
||||||
private fun createUniqueIDForTransaction(userId: String, deviceID: String): String {
|
private fun createUniqueIDForTransaction(userId: String, deviceID: String): String {
|
||||||
return buildString {
|
val buff = StringBuffer()
|
||||||
append(credentials.userId).append("|")
|
buff
|
||||||
append(credentials.deviceId).append("|")
|
.append(credentials.userId).append("|")
|
||||||
append(userId).append("|")
|
.append(credentials.deviceId).append("|")
|
||||||
append(deviceID).append("|")
|
.append(userId).append("|")
|
||||||
append(UUID.randomUUID().toString())
|
.append(deviceID).append("|")
|
||||||
}
|
.append(UUID.randomUUID().toString())
|
||||||
|
return buff.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RoomSummaryMapper @Inject constructor(
|
internal class RoomSummaryMapper @Inject constructor(
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.security.KeyStore
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.cert.CertificateException
|
import java.security.cert.CertificateException
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
import java.util.*
|
||||||
import javax.net.ssl.*
|
import javax.net.ssl.*
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.net.UnknownHostException
|
||||||
import java.security.KeyManagementException
|
import java.security.KeyManagementException
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
import java.util.*
|
||||||
import javax.net.ssl.SSLContext
|
import javax.net.ssl.SSLContext
|
||||||
import javax.net.ssl.SSLSocket
|
import javax.net.ssl.SSLSocket
|
||||||
import javax.net.ssl.SSLSocketFactory
|
import javax.net.ssl.SSLSocketFactory
|
||||||
|
@ -100,16 +101,25 @@ constructor(trustPinned: Array<TrustManager>, acceptedTlsVersions: List<TlsVersi
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableTLSOnSocket(socket: Socket?): Socket? {
|
private fun enableTLSOnSocket(socket: Socket?): Socket? {
|
||||||
if (socket is SSLSocket) {
|
if (socket != null && socket is SSLSocket) {
|
||||||
val supportedProtocols = socket.supportedProtocols.toSet()
|
val sslSocket = socket as SSLSocket?
|
||||||
val filteredEnabledProtocols = enabledProtocols.filter { it in supportedProtocols }
|
|
||||||
|
|
||||||
if (filteredEnabledProtocols.isNotEmpty()) {
|
val supportedProtocols = Arrays.asList(*sslSocket!!.supportedProtocols)
|
||||||
|
val filteredEnabledProtocols = ArrayList<String>()
|
||||||
|
|
||||||
|
for (protocol in enabledProtocols) {
|
||||||
|
if (supportedProtocols.contains(protocol)) {
|
||||||
|
filteredEnabledProtocols.add(protocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filteredEnabledProtocols.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
socket.enabledProtocols = filteredEnabledProtocols.toTypedArray()
|
sslSocket.enabledProtocols = filteredEnabledProtocols.toTypedArray()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return socket
|
return socket
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package im.vector.matrix.android.internal.session
|
package im.vector.matrix.android.internal.session
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import im.vector.matrix.android.api.session.InitialSyncProgressService
|
import im.vector.matrix.android.api.session.InitialSyncProgressService
|
||||||
|
@ -26,33 +25,31 @@ import javax.inject.Inject
|
||||||
@SessionScope
|
@SessionScope
|
||||||
class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgressService {
|
class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgressService {
|
||||||
|
|
||||||
private var status = MutableLiveData<InitialSyncProgressService.Status>()
|
var status = MutableLiveData<InitialSyncProgressService.Status>()
|
||||||
|
|
||||||
private var rootTask: TaskInfo? = null
|
var rootTask: TaskInfo? = null
|
||||||
|
|
||||||
override fun getInitialSyncProgressStatus(): LiveData<InitialSyncProgressService.Status?> {
|
override fun getLiveStatus(): LiveData<InitialSyncProgressService.Status?> {
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startTask(@StringRes nameRes: Int, totalProgress: Int, parentWeight: Float = 1f) {
|
|
||||||
// Create a rootTask, or add a child to the leaf
|
fun startTask(nameRes: Int, totalProgress: Int, parentWeight: Float = 1f) {
|
||||||
if (rootTask == null) {
|
if (rootTask == null) {
|
||||||
rootTask = TaskInfo(nameRes, totalProgress)
|
rootTask = TaskInfo(nameRes, totalProgress)
|
||||||
} else {
|
} else {
|
||||||
val currentLeaf = rootTask!!.leaf()
|
val currentLeaf = rootTask!!.leaf()
|
||||||
|
val newTask = TaskInfo(nameRes, totalProgress)
|
||||||
val newTask = TaskInfo(nameRes,
|
newTask.parent = currentLeaf
|
||||||
totalProgress,
|
newTask.offset = currentLeaf.currentProgress
|
||||||
currentLeaf,
|
|
||||||
parentWeight)
|
|
||||||
|
|
||||||
currentLeaf.child = newTask
|
currentLeaf.child = newTask
|
||||||
|
newTask.parentWeight = parentWeight
|
||||||
}
|
}
|
||||||
reportProgress(0)
|
reportProgress(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reportProgress(progress: Int) {
|
fun reportProgress(progress: Int) {
|
||||||
rootTask?.leaf()?.setProgress(progress)
|
rootTask?.leaf()?.incrementProgress(progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun endTask(nameRes: Int) {
|
fun endTask(nameRes: Int) {
|
||||||
|
@ -61,7 +58,7 @@ class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgr
|
||||||
//close it
|
//close it
|
||||||
val parent = endedTask.parent
|
val parent = endedTask.parent
|
||||||
parent?.child = null
|
parent?.child = null
|
||||||
parent?.setProgress(endedTask.offset + (endedTask.totalProgress * endedTask.parentWeight).toInt())
|
parent?.incrementProgress(endedTask.offset + (endedTask.totalProgress * endedTask.parentWeight).toInt())
|
||||||
}
|
}
|
||||||
if (endedTask?.parent == null) {
|
if (endedTask?.parent == null) {
|
||||||
status.postValue(null)
|
status.postValue(null)
|
||||||
|
@ -74,17 +71,14 @@ class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private inner class TaskInfo(@StringRes var nameRes: Int,
|
inner class TaskInfo(var nameRes: Int,
|
||||||
var totalProgress: Int,
|
var totalProgress: Int) {
|
||||||
var parent: TaskInfo? = null,
|
var parent: TaskInfo? = null
|
||||||
var parentWeight: Float = 1f,
|
|
||||||
var offset: Int = parent?.currentProgress ?: 0) {
|
|
||||||
var child: TaskInfo? = null
|
var child: TaskInfo? = null
|
||||||
|
var parentWeight: Float = 1f
|
||||||
var currentProgress: Int = 0
|
var currentProgress: Int = 0
|
||||||
|
var offset: Int = 0
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the further child
|
|
||||||
*/
|
|
||||||
fun leaf(): TaskInfo {
|
fun leaf(): TaskInfo {
|
||||||
var last = this
|
var last = this
|
||||||
while (last.child != null) {
|
while (last.child != null) {
|
||||||
|
@ -93,27 +87,26 @@ class DefaultInitialSyncProgressService @Inject constructor() : InitialSyncProgr
|
||||||
return last
|
return last
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun incrementProgress(progress: Int) {
|
||||||
* Set progress of the parent if any (which will post value), or post the value
|
|
||||||
*/
|
|
||||||
fun setProgress(progress: Int) {
|
|
||||||
currentProgress = progress
|
currentProgress = progress
|
||||||
// val newProgress = Math.min(currentProgress + progress, totalProgress)
|
// val newProgress = Math.min(currentProgress + progress, totalProgress)
|
||||||
parent?.let {
|
parent?.let {
|
||||||
val parentProgress = (currentProgress * parentWeight).toInt()
|
val parentProgress = (currentProgress * parentWeight).toInt()
|
||||||
it.setProgress(offset + parentProgress)
|
it.incrementProgress(offset + parentProgress)
|
||||||
} ?: run {
|
}
|
||||||
Timber.e("--- ${leaf().nameRes}: $currentProgress")
|
if (parent == null) {
|
||||||
|
Timber.e("--- ${leaf().nameRes}: ${currentProgress}")
|
||||||
status.postValue(
|
status.postValue(
|
||||||
InitialSyncProgressService.Status(leaf().nameRes, currentProgress)
|
InitialSyncProgressService.Status(leaf().nameRes, currentProgress)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T> reportSubtask(reporter: DefaultInitialSyncProgressService?,
|
inline fun <T> reportSubtask(reporter: DefaultInitialSyncProgressService?,
|
||||||
@StringRes nameRes: Int,
|
nameRes: Int,
|
||||||
totalProgress: Int,
|
totalProgress: Int,
|
||||||
parentWeight: Float = 1f,
|
parentWeight: Float = 1f,
|
||||||
block: () -> T): T {
|
block: () -> T): T {
|
||||||
|
@ -128,11 +121,11 @@ inline fun <K, V, R> Map<out K, V>.mapWithProgress(reporter: DefaultInitialSyncP
|
||||||
taskId: Int,
|
taskId: Int,
|
||||||
weight: Float,
|
weight: Float,
|
||||||
transform: (Map.Entry<K, V>) -> R): List<R> {
|
transform: (Map.Entry<K, V>) -> R): List<R> {
|
||||||
val total = count().toFloat()
|
val total = count()
|
||||||
var current = 0
|
var current = 0
|
||||||
reporter?.startTask(taskId, 100, weight)
|
reporter?.startTask(taskId, 100, weight)
|
||||||
return map {
|
return this.map {
|
||||||
reporter?.reportProgress((current / total * 100).toInt())
|
reporter?.reportProgress((current / total.toFloat() * 100).toInt())
|
||||||
current++
|
current++
|
||||||
transform.invoke(it)
|
transform.invoke(it)
|
||||||
}.also {
|
}.also {
|
||||||
|
|
|
@ -40,7 +40,7 @@ import im.vector.matrix.android.api.session.sync.FilterService
|
||||||
import im.vector.matrix.android.api.session.sync.SyncState
|
import im.vector.matrix.android.api.session.sync.SyncState
|
||||||
import im.vector.matrix.android.api.session.user.UserService
|
import im.vector.matrix.android.api.session.user.UserService
|
||||||
import im.vector.matrix.android.api.util.MatrixCallbackDelegate
|
import im.vector.matrix.android.api.util.MatrixCallbackDelegate
|
||||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
||||||
|
@ -63,7 +63,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||||
private val signOutService: Lazy<SignOutService>,
|
private val signOutService: Lazy<SignOutService>,
|
||||||
private val pushRuleService: Lazy<PushRuleService>,
|
private val pushRuleService: Lazy<PushRuleService>,
|
||||||
private val pushersService: Lazy<PushersService>,
|
private val pushersService: Lazy<PushersService>,
|
||||||
private val cryptoService: Lazy<DefaultCryptoService>,
|
private val cryptoService: Lazy<CryptoManager>,
|
||||||
private val fileService: Lazy<FileService>,
|
private val fileService: Lazy<FileService>,
|
||||||
private val syncThreadProvider: Provider<SyncThread>,
|
private val syncThreadProvider: Provider<SyncThread>,
|
||||||
private val contentUrlResolver: ContentUrlResolver,
|
private val contentUrlResolver: ContentUrlResolver,
|
||||||
|
|
|
@ -30,8 +30,9 @@ internal class DefaultContentUploadStateTracker @Inject constructor() : ContentU
|
||||||
private val listeners = mutableMapOf<String, MutableList<ContentUploadStateTracker.UpdateListener>>()
|
private val listeners = mutableMapOf<String, MutableList<ContentUploadStateTracker.UpdateListener>>()
|
||||||
|
|
||||||
override fun track(key: String, updateListener: ContentUploadStateTracker.UpdateListener) {
|
override fun track(key: String, updateListener: ContentUploadStateTracker.UpdateListener) {
|
||||||
val listeners = listeners.getOrPut(key) { ArrayList() }
|
val listeners = listeners[key] ?: ArrayList()
|
||||||
listeners.add(updateListener)
|
listeners.add(updateListener)
|
||||||
|
this.listeners[key] = listeners
|
||||||
val currentState = states[key] ?: ContentUploadStateTracker.State.Idle
|
val currentState = states[key] ?: ContentUploadStateTracker.State.Idle
|
||||||
mainHandler.post { updateListener.onUpdate(currentState) }
|
mainHandler.post { updateListener.onUpdate(currentState) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import im.vector.matrix.android.internal.task.configureWith
|
||||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil
|
import im.vector.matrix.android.internal.worker.WorkManagerUtil
|
||||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
|
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
|
||||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||||
import im.vector.matrix.android.internal.util.StringProvider
|
import im.vector.matrix.android.internal.util.StringProvider
|
||||||
import org.commonmark.parser.Parser
|
import org.commonmark.parser.Parser
|
||||||
import org.commonmark.renderer.html.HtmlRenderer
|
import org.commonmark.renderer.html.HtmlRenderer
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,22 +304,17 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildReplyFallback(body: TextContent, originalSenderId: String?, newBodyText: String): String {
|
private fun buildReplyFallback(body: TextContent, originalSenderId: String?, newBodyText: String): String {
|
||||||
return buildString {
|
val lines = body.text.split("\n")
|
||||||
append("> <")
|
val replyFallback = StringBuffer("> <$originalSenderId>")
|
||||||
append(originalSenderId)
|
lines.forEachIndexed { index, s ->
|
||||||
append(">")
|
if (index == 0) {
|
||||||
|
replyFallback.append(" $s")
|
||||||
val lines = body.text.split("\n")
|
} else {
|
||||||
lines.forEachIndexed { index, s ->
|
replyFallback.append("\n> $s")
|
||||||
if (index == 0) {
|
|
||||||
append(" $s")
|
|
||||||
} else {
|
|
||||||
append("\n> $s")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
append("\n\n")
|
|
||||||
append(newBodyText)
|
|
||||||
}
|
}
|
||||||
|
replyFallback.append("\n\n").append(newBodyText)
|
||||||
|
return replyFallback.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||||
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
||||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
||||||
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
|
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
|
||||||
|
@ -33,7 +33,7 @@ import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
internal class CryptoSyncHandler @Inject constructor(private val cryptoService: DefaultCryptoService,
|
internal class CryptoSyncHandler @Inject constructor(private val cryptoManager: CryptoManager,
|
||||||
private val sasVerificationService: DefaultSasVerificationService) {
|
private val sasVerificationService: DefaultSasVerificationService) {
|
||||||
|
|
||||||
fun handleToDevice(toDevice: ToDeviceSyncResponse, initialSyncProgressService: DefaultInitialSyncProgressService? = null) {
|
fun handleToDevice(toDevice: ToDeviceSyncResponse, initialSyncProgressService: DefaultInitialSyncProgressService? = null) {
|
||||||
|
@ -47,13 +47,13 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
|
||||||
Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.content)
|
Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.content)
|
||||||
} else {
|
} else {
|
||||||
sasVerificationService.onToDeviceEvent(event)
|
sasVerificationService.onToDeviceEvent(event)
|
||||||
cryptoService.onToDeviceEvent(event)
|
cryptoManager.onToDeviceEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSyncCompleted(syncResponse: SyncResponse) {
|
fun onSyncCompleted(syncResponse: SyncResponse) {
|
||||||
cryptoService.onSyncCompleted(syncResponse)
|
cryptoManager.onSyncCompleted(syncResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
|
||||||
if (event.getClearType() == EventType.ENCRYPTED) {
|
if (event.getClearType() == EventType.ENCRYPTED) {
|
||||||
var result: MXEventDecryptionResult? = null
|
var result: MXEventDecryptionResult? = null
|
||||||
try {
|
try {
|
||||||
result = cryptoService.decryptEvent(event, timelineId ?: "")
|
result = cryptoManager.decryptEvent(event, timelineId ?: "")
|
||||||
} catch (exception: MXCryptoError) {
|
} catch (exception: MXCryptoError) {
|
||||||
event.mCryptoError = (exception as? MXCryptoError.Base)?.errorType //setCryptoError(exception.cryptoError)
|
event.mCryptoError = (exception as? MXCryptoError.Base)?.errorType //setCryptoError(exception.cryptoError)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent
|
import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent
|
||||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||||
import im.vector.matrix.android.internal.database.helper.*
|
import im.vector.matrix.android.internal.database.helper.*
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||||
|
@ -50,7 +50,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
private val readReceiptHandler: ReadReceiptHandler,
|
private val readReceiptHandler: ReadReceiptHandler,
|
||||||
private val roomSummaryUpdater: RoomSummaryUpdater,
|
private val roomSummaryUpdater: RoomSummaryUpdater,
|
||||||
private val roomTagHandler: RoomTagHandler,
|
private val roomTagHandler: RoomTagHandler,
|
||||||
private val cryptoService: DefaultCryptoService,
|
private val cryptoManager: CryptoManager,
|
||||||
private val tokenStore: SyncTokenStore,
|
private val tokenStore: SyncTokenStore,
|
||||||
private val pushRuleService: DefaultPushRuleService,
|
private val pushRuleService: DefaultPushRuleService,
|
||||||
private val processForPushTask: ProcessEventForPushTask,
|
private val processForPushTask: ProcessEventForPushTask,
|
||||||
|
@ -97,12 +97,12 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
handleJoinedRoom(realm, it.key, it.value, isInitialSync)
|
handleJoinedRoom(realm, it.key, it.value, isInitialSync)
|
||||||
}
|
}
|
||||||
is HandlingStrategy.INVITED ->
|
is HandlingStrategy.INVITED ->
|
||||||
handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_invited_rooms, 0.1f) {
|
handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_invited_rooms, 0.4f) {
|
||||||
handleInvitedRoom(realm, it.key, it.value)
|
handleInvitedRoom(realm, it.key, it.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
is HandlingStrategy.LEFT -> {
|
is HandlingStrategy.LEFT -> {
|
||||||
handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_left_rooms, 0.3f) {
|
handlingStrategy.data.mapWithProgress(reporter, R.string.initial_sync_start_importing_account_left_rooms, 0.2f) {
|
||||||
handleLeftRoom(realm, it.key, it.value)
|
handleLeftRoom(realm, it.key, it.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,8 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
handleRoomAccountDataEvents(realm, roomId, roomSync.accountData)
|
handleRoomAccountDataEvents(realm, roomId, roomSync.accountData)
|
||||||
}
|
}
|
||||||
|
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||||
|
?: realm.createObject(roomId)
|
||||||
|
|
||||||
if (roomEntity.membership == Membership.INVITE) {
|
if (roomEntity.membership == Membership.INVITE) {
|
||||||
roomEntity.chunks.deleteAllFromRealm()
|
roomEntity.chunks.deleteAllFromRealm()
|
||||||
|
@ -134,12 +135,13 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
|
|
||||||
// State event
|
// State event
|
||||||
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
||||||
val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt() ?: Int.MIN_VALUE
|
val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt()
|
||||||
|
?: Int.MIN_VALUE
|
||||||
val untimelinedStateIndex = minStateIndex + 1
|
val untimelinedStateIndex = minStateIndex + 1
|
||||||
roomSync.state.events.forEach { event ->
|
roomSync.state.events.forEach { event ->
|
||||||
roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
||||||
// Give info to crypto module
|
// Give info to crypto module
|
||||||
cryptoService.onStateEvent(roomId, event)
|
cryptoManager.onStateEvent(roomId, event)
|
||||||
UserEntityFactory.createOrNull(event)?.also {
|
UserEntityFactory.createOrNull(event)?.also {
|
||||||
realm.insertOrUpdate(it)
|
realm.insertOrUpdate(it)
|
||||||
}
|
}
|
||||||
|
@ -165,7 +167,8 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
roomSync:
|
roomSync:
|
||||||
InvitedRoomSync): RoomEntity {
|
InvitedRoomSync): RoomEntity {
|
||||||
Timber.v("Handle invited sync for room $roomId")
|
Timber.v("Handle invited sync for room $roomId")
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||||
|
?: realm.createObject(roomId)
|
||||||
roomEntity.membership = Membership.INVITE
|
roomEntity.membership = Membership.INVITE
|
||||||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
||||||
val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events)
|
val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events)
|
||||||
|
@ -178,7 +181,8 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
private fun handleLeftRoom(realm: Realm,
|
private fun handleLeftRoom(realm: Realm,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
roomSync: RoomSync): RoomEntity {
|
roomSync: RoomSync): RoomEntity {
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||||
|
?: realm.createObject(roomId)
|
||||||
|
|
||||||
roomEntity.membership = Membership.LEAVE
|
roomEntity.membership = Membership.LEAVE
|
||||||
roomEntity.chunks.deleteAllFromRealm()
|
roomEntity.chunks.deleteAllFromRealm()
|
||||||
|
@ -210,7 +214,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
||||||
event.eventId?.also { eventIds.add(it) }
|
event.eventId?.also { eventIds.add(it) }
|
||||||
chunkEntity.add(roomEntity.roomId, event, PaginationDirection.FORWARDS, stateIndexOffset)
|
chunkEntity.add(roomEntity.roomId, event, PaginationDirection.FORWARDS, stateIndexOffset)
|
||||||
// Give info to crypto module
|
// Give info to crypto module
|
||||||
cryptoService.onLiveEvent(roomEntity.roomId, event)
|
cryptoManager.onLiveEvent(roomEntity.roomId, event)
|
||||||
// Try to remove local echo
|
// Try to remove local echo
|
||||||
event.unsignedData?.transactionId?.also {
|
event.unsignedData?.transactionId?.also {
|
||||||
val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it)
|
val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
import im.vector.matrix.android.internal.database.model.RoomTagEntity
|
import im.vector.matrix.android.internal.database.model.RoomTagEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RoomTagHandler @Inject constructor() {
|
internal class RoomTagHandler @Inject constructor() {
|
||||||
|
@ -29,8 +30,16 @@ internal class RoomTagHandler @Inject constructor() {
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val tags = content.tags.entries.map { (tagName, params) ->
|
val tags = ArrayList<RoomTagEntity>()
|
||||||
RoomTagEntity(tagName, params["order"] as? Double)
|
for (tagName in content.tags.keys) {
|
||||||
|
val params = content.tags[tagName]
|
||||||
|
val order = params?.get("order")
|
||||||
|
val tag = if (order is Double) {
|
||||||
|
RoomTagEntity(tagName, order)
|
||||||
|
} else {
|
||||||
|
RoomTagEntity(tagName, null)
|
||||||
|
}
|
||||||
|
tags.add(tag)
|
||||||
}
|
}
|
||||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||||
?: RoomSummaryEntity(roomId)
|
?: RoomSummaryEntity(roomId)
|
||||||
|
|
|
@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.session.sync
|
||||||
|
|
||||||
import arrow.core.Try
|
import arrow.core.Try
|
||||||
import im.vector.matrix.android.R
|
import im.vector.matrix.android.R
|
||||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||||
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
|
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
|
||||||
import im.vector.matrix.android.internal.session.reportSubtask
|
import im.vector.matrix.android.internal.session.reportSubtask
|
||||||
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
||||||
|
@ -30,7 +30,7 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl
|
||||||
private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
|
private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
|
||||||
private val groupSyncHandler: GroupSyncHandler,
|
private val groupSyncHandler: GroupSyncHandler,
|
||||||
private val cryptoSyncHandler: CryptoSyncHandler,
|
private val cryptoSyncHandler: CryptoSyncHandler,
|
||||||
private val cryptoService: DefaultCryptoService,
|
private val cryptoManager: CryptoManager,
|
||||||
private val initialSyncProgressService: DefaultInitialSyncProgressService) {
|
private val initialSyncProgressService: DefaultInitialSyncProgressService) {
|
||||||
|
|
||||||
fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try<SyncResponse> {
|
fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try<SyncResponse> {
|
||||||
|
@ -40,12 +40,12 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl
|
||||||
val reporter = initialSyncProgressService.takeIf { isInitialSync }
|
val reporter = initialSyncProgressService.takeIf { isInitialSync }
|
||||||
|
|
||||||
measureTimeMillis {
|
measureTimeMillis {
|
||||||
if (!cryptoService.isStarted()) {
|
if (!cryptoManager.isStarted()) {
|
||||||
Timber.v("Should start cryptoService")
|
Timber.v("Should start cryptoManager")
|
||||||
cryptoService.start(isInitialSync)
|
cryptoManager.start(isInitialSync)
|
||||||
}
|
}
|
||||||
}.also {
|
}.also {
|
||||||
Timber.v("Finish handling start cryptoService in $it ms")
|
Timber.v("Finish handling start cryptoManager in $it ms")
|
||||||
}
|
}
|
||||||
val measure = measureTimeMillis {
|
val measure = measureTimeMillis {
|
||||||
// Handle the to device events before the room ones
|
// Handle the to device events before the room ones
|
||||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.matrix.android.internal.util
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
|
|
||||||
internal class CancelableWork(private val context: Context,
|
internal class CancelableWork(private val context: Context,
|
||||||
private val workId: UUID) : Cancelable {
|
private val workId: UUID) : Cancelable {
|
||||||
|
|
|
@ -34,7 +34,7 @@ import java.security.*
|
||||||
import java.security.cert.CertificateException
|
import java.security.cert.CertificateException
|
||||||
import java.security.spec.AlgorithmParameterSpec
|
import java.security.spec.AlgorithmParameterSpec
|
||||||
import java.security.spec.RSAKeyGenParameterSpec
|
import java.security.spec.RSAKeyGenParameterSpec
|
||||||
import java.util.Calendar
|
import java.util.*
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import javax.crypto.*
|
import javax.crypto.*
|
||||||
import javax.crypto.spec.GCMParameterSpec
|
import javax.crypto.spec.GCMParameterSpec
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.TreeSet
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build canonical Json
|
* Build canonical Json
|
||||||
|
@ -60,33 +60,43 @@ object JsonCanonicalizer {
|
||||||
when (any) {
|
when (any) {
|
||||||
is JSONArray -> {
|
is JSONArray -> {
|
||||||
// Canonicalize each element of the array
|
// Canonicalize each element of the array
|
||||||
return (0 until any.length()).joinToString(separator = ",", prefix = "[", postfix = "]") {
|
val result = StringBuilder("[")
|
||||||
canonicalizeRecursive(any.get(it))
|
|
||||||
|
for (i in 0 until any.length()) {
|
||||||
|
result.append(canonicalizeRecursive(any.get(i)))
|
||||||
|
if (i < any.length() - 1) {
|
||||||
|
result.append(",")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.append("]")
|
||||||
|
|
||||||
|
return result.toString()
|
||||||
}
|
}
|
||||||
is JSONObject -> {
|
is JSONObject -> {
|
||||||
// Sort the attributes by name, and the canonicalize each element of the JSONObject
|
// Sort the attributes by name, and the canonicalize each element of the JSONObject
|
||||||
|
val result = StringBuilder("{")
|
||||||
|
|
||||||
val attributes = TreeSet<String>()
|
val attributes = TreeSet<String>()
|
||||||
for (entry in any.keys()) {
|
for (entry in any.keys()) {
|
||||||
attributes.add(entry)
|
attributes.add(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildString {
|
for (attribute in attributes.withIndex()) {
|
||||||
append("{")
|
result.append("\"")
|
||||||
for ((index, value) in attributes.withIndex()) {
|
.append(attribute.value)
|
||||||
append("\"")
|
.append("\"")
|
||||||
append(value)
|
.append(":")
|
||||||
append("\"")
|
.append(canonicalizeRecursive(any[attribute.value]))
|
||||||
append(":")
|
|
||||||
append(canonicalizeRecursive(any[value]))
|
|
||||||
|
|
||||||
if (index < attributes.size - 1) {
|
if (attribute.index < attributes.size - 1) {
|
||||||
append(",")
|
result.append(",")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
append("}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.append("}")
|
||||||
|
|
||||||
|
return result.toString()
|
||||||
}
|
}
|
||||||
is String -> return JSONObject.quote(any)
|
is String -> return JSONObject.quote(any)
|
||||||
else -> return any.toString()
|
else -> return any.toString()
|
||||||
|
|
|
@ -15,7 +15,7 @@ androidExtensions {
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.versionMajor = 0
|
ext.versionMajor = 0
|
||||||
ext.versionMinor = 5
|
ext.versionMinor = 4
|
||||||
ext.versionPatch = 0
|
ext.versionPatch = 0
|
||||||
|
|
||||||
static def getGitTimestamp() {
|
static def getGitTimestamp() {
|
||||||
|
@ -51,7 +51,7 @@ static def gitRevisionDate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static def gitBranchName() {
|
static def gitBranchName() {
|
||||||
def cmd = "git rev-parse --abbrev-ref HEAD"
|
def cmd = "git name-rev --name-only HEAD"
|
||||||
return cmd.execute().text.trim()
|
return cmd.execute().text.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,9 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
||||||
vectorComponent = DaggerVectorComponent.factory().create(this)
|
vectorComponent = DaggerVectorComponent.factory().create(this)
|
||||||
vectorComponent.inject(this)
|
vectorComponent.inject(this)
|
||||||
vectorUncaughtExceptionHandler.activate(this)
|
vectorUncaughtExceptionHandler.activate(this)
|
||||||
|
// Log
|
||||||
if (BuildConfig.DEBUG) {
|
VectorFileLogger.init(this)
|
||||||
Timber.plant(Timber.DebugTree())
|
Timber.plant(Timber.DebugTree(), VectorFileLogger)
|
||||||
}
|
|
||||||
Timber.plant(vectorComponent.vectorFileLogger())
|
|
||||||
|
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Stetho.initializeWithDefaults(this)
|
Stetho.initializeWithDefaults(this)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
|
||||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||||
import im.vector.riotx.features.rageshake.BugReporter
|
import im.vector.riotx.features.rageshake.BugReporter
|
||||||
import im.vector.riotx.features.rageshake.VectorFileLogger
|
|
||||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
import im.vector.riotx.features.settings.VectorPreferences
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -102,8 +101,6 @@ interface VectorComponent {
|
||||||
|
|
||||||
fun vectorPreferences(): VectorPreferences
|
fun vectorPreferences(): VectorPreferences
|
||||||
|
|
||||||
fun vectorFileLogger(): VectorFileLogger
|
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(@BindsInstance context: Context): VectorComponent
|
fun create(@BindsInstance context: Context): VectorComponent
|
||||||
|
|
|
@ -26,6 +26,7 @@ import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import com.airbnb.mvrx.viewModel
|
import com.airbnb.mvrx.viewModel
|
||||||
|
@ -35,10 +36,12 @@ import im.vector.riotx.core.di.ScreenComponent
|
||||||
import im.vector.riotx.core.extensions.hideKeyboard
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
import im.vector.riotx.core.extensions.observeEvent
|
import im.vector.riotx.core.extensions.observeEvent
|
||||||
import im.vector.riotx.core.extensions.replaceFragment
|
import im.vector.riotx.core.extensions.replaceFragment
|
||||||
|
import im.vector.riotx.core.platform.OnBackPressed
|
||||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotx.core.pushers.PushersManager
|
import im.vector.riotx.core.pushers.PushersManager
|
||||||
import im.vector.riotx.features.disclaimer.showDisclaimerDialog
|
import im.vector.riotx.features.disclaimer.showDisclaimerDialog
|
||||||
|
import im.vector.riotx.features.navigation.Navigator
|
||||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
||||||
|
@ -116,22 +119,22 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
|
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
|
||||||
}
|
}
|
||||||
|
|
||||||
activeSessionHolder.getSafeActiveSession()?.getInitialSyncProgressStatus()?.observe(this, Observer { status ->
|
activeSessionHolder.getSafeActiveSession()?.getLiveStatus()?.observe(this, Observer { sprogress ->
|
||||||
if (status == null) {
|
Timber.e("${sprogress?.statusText?.let { getString(it) }} ${sprogress?.percentProgress}")
|
||||||
|
if (sprogress == null) {
|
||||||
waiting_view.isVisible = false
|
waiting_view.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
Timber.e("${getString(status.statusText)} ${status.percentProgress}")
|
|
||||||
waiting_view.setOnClickListener {
|
waiting_view.setOnClickListener {
|
||||||
//block interactions
|
//block interactions
|
||||||
}
|
}
|
||||||
waiting_view_status_horizontal_progress.apply {
|
waiting_view_status_horizontal_progress.apply {
|
||||||
isIndeterminate = false
|
isIndeterminate = false
|
||||||
max = 100
|
max = 100
|
||||||
progress = status.percentProgress
|
progress = sprogress.percentProgress
|
||||||
isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
waiting_view_status_text.apply {
|
waiting_view_status_text.apply {
|
||||||
text = getString(status.statusText)
|
text = sprogress.statusText?.let { getString(it) }
|
||||||
isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
waiting_view.isVisible = true
|
waiting_view.isVisible = true
|
||||||
|
@ -210,6 +213,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_CLEAR_EXISTING_NOTIFICATION = "EXTRA_CLEAR_EXISTING_NOTIFICATION"
|
private const val EXTRA_CLEAR_EXISTING_NOTIFICATION = "EXTRA_CLEAR_EXISTING_NOTIFICATION"
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,15 @@ import im.vector.matrix.android.api.permalinks.MatrixLinkify
|
||||||
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
|
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan
|
||||||
import im.vector.matrix.android.api.session.events.model.RelationType
|
import im.vector.matrix.android.api.session.events.model.RelationType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.room.model.message.*
|
import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.getFileUrl
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
||||||
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
||||||
|
@ -39,12 +47,26 @@ import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotx.core.linkify.VectorLinkify
|
import im.vector.riotx.core.linkify.VectorLinkify
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.*
|
import im.vector.riotx.features.home.room.detail.timeline.helper.senderAvatar
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.BlankItem_
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.DefaultItem
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.DefaultItem_
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageFileItem
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageFileItem_
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageImageVideoItem
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageImageVideoItem_
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageTextItem
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageTextItem_
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.NoticeItem_
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.RedactedMessageItem
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.item.RedactedMessageItem_
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
import im.vector.riotx.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||||
import im.vector.riotx.features.html.EventHtmlRenderer
|
import im.vector.riotx.features.html.EventHtmlRenderer
|
||||||
import im.vector.riotx.features.media.ImageContentRenderer
|
import im.vector.riotx.features.media.ImageContentRenderer
|
||||||
|
@ -81,28 +103,32 @@ class MessageItemFactory @Inject constructor(
|
||||||
|
|
||||||
val messageContent: MessageContent =
|
val messageContent: MessageContent =
|
||||||
event.getLastMessageContent()
|
event.getLastMessageContent()
|
||||||
?: //Malformed content, we should echo something on screen
|
?: //Malformed content, we should echo something on screen
|
||||||
return buildNotHandledMessageItem(stringProvider.getString(R.string.malformed_message),
|
return DefaultItem_().text(stringProvider.getString(R.string.malformed_message))
|
||||||
informationData, highlight, callback)
|
|
||||||
|
|
||||||
if (messageContent.relatesTo?.type == RelationType.REPLACE
|
if (messageContent.relatesTo?.type == RelationType.REPLACE
|
||||||
|| event.isEncrypted() && event.root.content.toModel<EncryptedEventContent>()?.relatesTo?.type == RelationType.REPLACE
|
|| event.isEncrypted() && event.root.content.toModel<EncryptedEventContent>()?.relatesTo?.type == RelationType.REPLACE
|
||||||
) {
|
) {
|
||||||
// This is an edit event, we should display it when debugging as a notice event
|
// This is an edit event, we should it when debugging as a notice event
|
||||||
return noticeItemFactory.create(event, highlight, callback)
|
return noticeItemFactory.create(event, highlight, callback)
|
||||||
}
|
}
|
||||||
// val all = event.root.toContent()
|
// val all = event.root.toContent()
|
||||||
// val ev = all.toModel<Event>()
|
// val ev = all.toModel<Event>()
|
||||||
return when (messageContent) {
|
return when (messageContent) {
|
||||||
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, highlight, callback)
|
is MessageEmoteContent -> buildEmoteMessageItem(messageContent,
|
||||||
is MessageTextContent -> buildTextMessageItem(messageContent, informationData, highlight, callback)
|
informationData,
|
||||||
|
highlight,
|
||||||
|
callback)
|
||||||
|
is MessageTextContent -> buildTextMessageItem(messageContent,
|
||||||
|
informationData,
|
||||||
|
highlight,
|
||||||
|
callback)
|
||||||
is MessageImageContent -> buildImageMessageItem(messageContent, informationData, highlight, callback)
|
is MessageImageContent -> buildImageMessageItem(messageContent, informationData, highlight, callback)
|
||||||
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, highlight, callback)
|
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, highlight, callback)
|
||||||
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, highlight, callback)
|
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, highlight, callback)
|
||||||
is MessageFileContent -> buildFileMessageItem(messageContent, informationData, highlight, callback)
|
is MessageFileContent -> buildFileMessageItem(messageContent, informationData, highlight, callback)
|
||||||
is MessageAudioContent -> buildAudioMessageItem(messageContent, informationData, highlight, callback)
|
is MessageAudioContent -> buildAudioMessageItem(messageContent, informationData, highlight, callback)
|
||||||
else -> buildNotHandledMessageItem("${messageContent.type} message events are not yet handled",
|
else -> buildNotHandledMessageItem(messageContent, highlight)
|
||||||
informationData, highlight, callback)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +157,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +182,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
.clickListener(
|
.clickListener(
|
||||||
DebouncedClickListener(View.OnClickListener { _ ->
|
DebouncedClickListener(View.OnClickListener { _ ->
|
||||||
|
@ -164,17 +190,11 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNotHandledMessageItem(text: String,
|
private fun buildNotHandledMessageItem(messageContent: MessageContent, highlight: Boolean): DefaultItem? {
|
||||||
informationData: MessageInformationData,
|
val text = "${messageContent.type} message events are not yet handled"
|
||||||
highlight: Boolean,
|
|
||||||
callback: TimelineEventController.Callback?): DefaultItem? {
|
|
||||||
return DefaultItem_()
|
return DefaultItem_()
|
||||||
.text(text)
|
.text(text)
|
||||||
.avatarRenderer(avatarRenderer)
|
|
||||||
.highlighted(highlight)
|
.highlighted(highlight)
|
||||||
.informationData(informationData)
|
|
||||||
.baseCallback(callback)
|
|
||||||
.readReceiptsCallback(callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
||||||
|
@ -217,7 +237,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +250,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
val thumbnailData = ImageContentRenderer.Data(
|
val thumbnailData = ImageContentRenderer.Data(
|
||||||
filename = messageContent.body,
|
filename = messageContent.body,
|
||||||
url = messageContent.videoInfo?.thumbnailFile?.url
|
url = messageContent.videoInfo?.thumbnailFile?.url
|
||||||
?: messageContent.videoInfo?.thumbnailUrl,
|
?: messageContent.videoInfo?.thumbnailUrl,
|
||||||
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
height = messageContent.videoInfo?.height,
|
height = messageContent.videoInfo?.height,
|
||||||
maxHeight = maxHeight,
|
maxHeight = maxHeight,
|
||||||
|
@ -266,7 +286,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
.clickListener { view -> callback?.onVideoMessageClicked(messageContent, videoData, view) }
|
.clickListener { view -> callback?.onVideoMessageClicked(messageContent, videoData, view) }
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +326,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,9 +356,9 @@ class MessageItemFactory @Inject constructor(
|
||||||
//nop
|
//nop
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
editStart,
|
editStart,
|
||||||
editEnd,
|
editEnd,
|
||||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
|
||||||
return spannable
|
return spannable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +396,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +433,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +453,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, null, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, null, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.riotx.features.home.room.detail.timeline.format
|
package im.vector.riotx.features.home.room.detail.timeline.format
|
||||||
|
|
||||||
|
import android.text.TextUtils
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
@ -23,14 +24,12 @@ import im.vector.matrix.android.api.session.room.model.*
|
||||||
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
import im.vector.matrix.android.api.session.room.model.call.CallInviteContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.senderName
|
import im.vector.riotx.features.home.room.detail.timeline.helper.senderName
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class NoticeEventFormatter @Inject constructor(private val sessionHolder: ActiveSessionHolder,
|
class NoticeEventFormatter @Inject constructor(private val stringProvider: StringProvider) {
|
||||||
private val stringProvider: StringProvider) {
|
|
||||||
|
|
||||||
fun format(timelineEvent: TimelineEvent): CharSequence? {
|
fun format(timelineEvent: TimelineEvent): CharSequence? {
|
||||||
return when (val type = timelineEvent.root.getClearType()) {
|
return when (val type = timelineEvent.root.getClearType()) {
|
||||||
|
@ -75,10 +74,10 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
|
|
||||||
private fun formatRoomNameEvent(event: Event, senderName: String?): CharSequence? {
|
private fun formatRoomNameEvent(event: Event, senderName: String?): CharSequence? {
|
||||||
val content = event.getClearContent().toModel<RoomNameContent>() ?: return null
|
val content = event.getClearContent().toModel<RoomNameContent>() ?: return null
|
||||||
return if (content.name.isNullOrBlank()) {
|
return if (!TextUtils.isEmpty(content.name)) {
|
||||||
stringProvider.getString(R.string.notice_room_name_removed, senderName)
|
|
||||||
} else {
|
|
||||||
stringProvider.getString(R.string.notice_room_name_changed, senderName, content.name)
|
stringProvider.getString(R.string.notice_room_name_changed, senderName, content.name)
|
||||||
|
} else {
|
||||||
|
stringProvider.getString(R.string.notice_room_name_removed, senderName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +95,8 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?): CharSequence? {
|
private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?): CharSequence? {
|
||||||
val historyVisibility = event.getClearContent().toModel<RoomHistoryVisibilityContent>()?.historyVisibility ?: return null
|
val historyVisibility = event.getClearContent().toModel<RoomHistoryVisibilityContent>()?.historyVisibility
|
||||||
|
?: return null
|
||||||
|
|
||||||
val formattedVisibility = when (historyVisibility) {
|
val formattedVisibility = when (historyVisibility) {
|
||||||
RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared)
|
RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared)
|
||||||
|
@ -138,7 +138,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
private fun buildProfileNotice(event: Event, senderName: String?, eventContent: RoomMember?, prevEventContent: RoomMember?): String? {
|
private fun buildProfileNotice(event: Event, senderName: String?, eventContent: RoomMember?, prevEventContent: RoomMember?): String? {
|
||||||
val displayText = StringBuilder()
|
val displayText = StringBuilder()
|
||||||
// Check display name has been changed
|
// Check display name has been changed
|
||||||
if (eventContent?.displayName != prevEventContent?.displayName) {
|
if (!TextUtils.equals(eventContent?.displayName, prevEventContent?.displayName)) {
|
||||||
val displayNameText = when {
|
val displayNameText = when {
|
||||||
prevEventContent?.displayName.isNullOrEmpty() ->
|
prevEventContent?.displayName.isNullOrEmpty() ->
|
||||||
stringProvider.getString(R.string.notice_display_name_set, event.senderId, eventContent?.displayName)
|
stringProvider.getString(R.string.notice_display_name_set, event.senderId, eventContent?.displayName)
|
||||||
|
@ -146,12 +146,12 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
stringProvider.getString(R.string.notice_display_name_removed, event.senderId, prevEventContent?.displayName)
|
stringProvider.getString(R.string.notice_display_name_removed, event.senderId, prevEventContent?.displayName)
|
||||||
else ->
|
else ->
|
||||||
stringProvider.getString(R.string.notice_display_name_changed_from,
|
stringProvider.getString(R.string.notice_display_name_changed_from,
|
||||||
event.senderId, prevEventContent?.displayName, eventContent?.displayName)
|
event.senderId, prevEventContent?.displayName, eventContent?.displayName)
|
||||||
}
|
}
|
||||||
displayText.append(displayNameText)
|
displayText.append(displayNameText)
|
||||||
}
|
}
|
||||||
// Check whether the avatar has been changed
|
// Check whether the avatar has been changed
|
||||||
if (eventContent?.avatarUrl != prevEventContent?.avatarUrl) {
|
if (!TextUtils.equals(eventContent?.avatarUrl, prevEventContent?.avatarUrl)) {
|
||||||
val displayAvatarText = if (displayText.isNotEmpty()) {
|
val displayAvatarText = if (displayText.isNotEmpty()) {
|
||||||
displayText.append(" ")
|
displayText.append(" ")
|
||||||
stringProvider.getString(R.string.notice_avatar_changed_too)
|
stringProvider.getString(R.string.notice_avatar_changed_too)
|
||||||
|
@ -168,18 +168,17 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
val targetDisplayName = eventContent?.displayName ?: prevEventContent?.displayName ?: ""
|
val targetDisplayName = eventContent?.displayName ?: prevEventContent?.displayName ?: ""
|
||||||
return when {
|
return when {
|
||||||
Membership.INVITE == eventContent?.membership -> {
|
Membership.INVITE == eventContent?.membership -> {
|
||||||
val selfUserId = sessionHolder.getSafeActiveSession()?.myUserId
|
// TODO get userId
|
||||||
|
val selfUserId = ""
|
||||||
when {
|
when {
|
||||||
eventContent.thirdPartyInvite != null -> {
|
eventContent.thirdPartyInvite != null ->
|
||||||
val userWhoHasAccepted = eventContent.thirdPartyInvite?.signed?.mxid ?: event.stateKey
|
|
||||||
stringProvider.getString(R.string.notice_room_third_party_registered_invite,
|
stringProvider.getString(R.string.notice_room_third_party_registered_invite,
|
||||||
userWhoHasAccepted, eventContent.thirdPartyInvite?.displayName)
|
targetDisplayName, eventContent.thirdPartyInvite?.displayName)
|
||||||
}
|
TextUtils.equals(event.stateKey, selfUserId) ->
|
||||||
event.stateKey == selfUserId ->
|
|
||||||
stringProvider.getString(R.string.notice_room_invite_you, senderDisplayName)
|
stringProvider.getString(R.string.notice_room_invite_you, senderDisplayName)
|
||||||
event.stateKey.isNullOrEmpty() ->
|
event.stateKey.isNullOrEmpty() ->
|
||||||
stringProvider.getString(R.string.notice_room_invite_no_invitee, senderDisplayName)
|
stringProvider.getString(R.string.notice_room_invite_no_invitee, senderDisplayName)
|
||||||
else ->
|
else ->
|
||||||
stringProvider.getString(R.string.notice_room_invite, senderDisplayName, targetDisplayName)
|
stringProvider.getString(R.string.notice_room_invite, senderDisplayName, targetDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +186,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active
|
||||||
stringProvider.getString(R.string.notice_room_join, senderDisplayName)
|
stringProvider.getString(R.string.notice_room_join, senderDisplayName)
|
||||||
Membership.LEAVE == eventContent?.membership ->
|
Membership.LEAVE == eventContent?.membership ->
|
||||||
// 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked
|
// 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked
|
||||||
return if (event.senderId == event.stateKey) {
|
return if (TextUtils.equals(event.senderId, event.stateKey)) {
|
||||||
if (prevEventContent?.membership == Membership.INVITE) {
|
if (prevEventContent?.membership == Membership.INVITE) {
|
||||||
stringProvider.getString(R.string.notice_room_reject, senderDisplayName)
|
stringProvider.getString(R.string.notice_room_reject, senderDisplayName)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -52,8 +52,7 @@ import javax.inject.Singleton
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
|
class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
|
||||||
private val versionProvider: VersionProvider,
|
private val versionProvider: VersionProvider) {
|
||||||
private val vectorFileLogger : VectorFileLogger) {
|
|
||||||
var inMultiWindowMode = false
|
var inMultiWindowMode = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -163,7 +162,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
|
||||||
val gzippedFiles = ArrayList<File>()
|
val gzippedFiles = ArrayList<File>()
|
||||||
|
|
||||||
if (withDevicesLogs) {
|
if (withDevicesLogs) {
|
||||||
val files = vectorFileLogger.getLogFiles()
|
val files = VectorFileLogger.getLogFiles()
|
||||||
|
|
||||||
for (f in files) {
|
for (f in files) {
|
||||||
if (!mIsCancelled) {
|
if (!mIsCancelled) {
|
||||||
|
@ -349,20 +348,20 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
|
||||||
} else if (null == response || null == response.body()) {
|
} else if (null == response || null == response.body()) {
|
||||||
serverError = "Failed with error $responseCode"
|
serverError = "Failed with error $responseCode"
|
||||||
} else {
|
} else {
|
||||||
var inputStream: InputStream? = null
|
var `is`: InputStream? = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
inputStream = response.body()!!.byteStream()
|
`is` = response.body()!!.byteStream()
|
||||||
|
|
||||||
if (null != inputStream) {
|
if (null != `is`) {
|
||||||
var ch = inputStream.read()
|
var ch = `is`.read()
|
||||||
val b = StringBuilder()
|
val b = StringBuilder()
|
||||||
while (ch != -1) {
|
while (ch != -1) {
|
||||||
b.append(ch.toChar())
|
b.append(ch.toChar())
|
||||||
ch = inputStream.read()
|
ch = `is`.read()
|
||||||
}
|
}
|
||||||
serverError = b.toString()
|
serverError = b.toString()
|
||||||
inputStream.close()
|
`is`.close()
|
||||||
|
|
||||||
// check if the error message
|
// check if the error message
|
||||||
try {
|
try {
|
||||||
|
@ -381,7 +380,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes
|
||||||
Timber.e(e, "## sendBugReport() : failed to parse error " + e.message)
|
Timber.e(e, "## sendBugReport() : failed to parse error " + e.message)
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
inputStream?.close()
|
`is`?.close()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## sendBugReport() : failed to close the error stream " + e.message)
|
Timber.e(e, "## sendBugReport() : failed to close the error stream " + e.message)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,74 +17,43 @@
|
||||||
package im.vector.riotx.features.rageshake
|
package im.vector.riotx.features.rageshake
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.text.TextUtils
|
||||||
import im.vector.riotx.features.settings.VectorPreferences
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.logging.*
|
import java.util.logging.*
|
||||||
import java.util.logging.Formatter
|
import java.util.logging.Formatter
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
private const val LOG_SIZE_BYTES = 20 * 1024 * 1024 // 20MB
|
object VectorFileLogger : Timber.DebugTree() {
|
||||||
|
|
||||||
private const val LOG_ROTATION_COUNT = 3
|
private const val LOG_SIZE_BYTES = 50 * 1024 * 1024 // 50MB
|
||||||
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class VectorFileLogger @Inject constructor(val context: Context, private val vectorPreferences: VectorPreferences) : Timber.DebugTree() {
|
|
||||||
|
|
||||||
|
// relatively large rotation count because closing > opening the app rotates the log (!)
|
||||||
|
private const val LOG_ROTATION_COUNT = 15
|
||||||
|
|
||||||
private val sLogger = Logger.getLogger("im.vector.riotx")
|
private val sLogger = Logger.getLogger("im.vector.riotx")
|
||||||
private var sFileHandler: FileHandler? = null
|
private lateinit var sFileHandler: FileHandler
|
||||||
private var sCacheDirectory: File? = null
|
private lateinit var sCacheDirectory: File
|
||||||
private var sFileName = "riotxlogs"
|
private var sFileName = "riotx"
|
||||||
|
|
||||||
private val prioPrefixes = mapOf(
|
fun init(context: Context) {
|
||||||
Log.VERBOSE to "V/ ",
|
|
||||||
Log.DEBUG to "D/ ",
|
|
||||||
Log.INFO to "I/ ",
|
|
||||||
Log.WARN to "W/ ",
|
|
||||||
Log.ERROR to "E/ ",
|
|
||||||
Log.ASSERT to "WTF/ "
|
|
||||||
)
|
|
||||||
|
|
||||||
init {
|
|
||||||
val logsDirectoryFile = context.cacheDir.absolutePath + "/logs"
|
val logsDirectoryFile = context.cacheDir.absolutePath + "/logs"
|
||||||
|
|
||||||
setLogDirectory(File(logsDirectoryFile))
|
setLogDirectory(File(logsDirectoryFile))
|
||||||
try {
|
init("RiotXLog")
|
||||||
if (sCacheDirectory != null) {
|
|
||||||
sFileHandler = FileHandler(sCacheDirectory!!.absolutePath + "/" + sFileName + ".%g.txt", LOG_SIZE_BYTES, LOG_ROTATION_COUNT)
|
|
||||||
sFileHandler?.formatter = LogFormatter()
|
|
||||||
sLogger.useParentHandlers = false
|
|
||||||
sLogger.level = Level.ALL
|
|
||||||
sLogger.addHandler(sFileHandler)
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "Failed to initialize FileLogger")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||||
if (sFileHandler == null) return
|
|
||||||
if (skipLog(priority)) return
|
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
logToFile(t)
|
logToFile(t)
|
||||||
}
|
}
|
||||||
logToFile(prioPrefixes[priority] ?: "$priority ", tag ?: "Tag", message)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun skipLog(priority: Int): Boolean {
|
logToFile("$priority ", tag ?: "Tag", message)
|
||||||
return if (vectorPreferences.labAllowedExtendedLogging()) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
priority < Log.ERROR
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +68,24 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
|
||||||
sCacheDirectory = cacheDir
|
sCacheDirectory = cacheDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the logger. Should be called AFTER [Log.setLogDirectory].
|
||||||
|
*
|
||||||
|
* @param fileName the base file name
|
||||||
|
*/
|
||||||
|
private fun init(fileName: String) {
|
||||||
|
try {
|
||||||
|
if (!TextUtils.isEmpty(fileName)) {
|
||||||
|
sFileName = fileName
|
||||||
|
}
|
||||||
|
sFileHandler = FileHandler(sCacheDirectory.absolutePath + "/" + sFileName + ".%g.txt", LOG_SIZE_BYTES, LOG_ROTATION_COUNT)
|
||||||
|
sFileHandler.formatter = LogFormatter()
|
||||||
|
sLogger.useParentHandlers = false
|
||||||
|
sLogger.level = Level.ALL
|
||||||
|
sLogger.addHandler(sFileHandler)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds our own log files to the provided list of files.
|
* Adds our own log files to the provided list of files.
|
||||||
|
@ -112,8 +99,8 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
|
||||||
try {
|
try {
|
||||||
// reported by GA
|
// reported by GA
|
||||||
if (null != sFileHandler) {
|
if (null != sFileHandler) {
|
||||||
sFileHandler!!.flush()
|
sFileHandler.flush()
|
||||||
val absPath = sCacheDirectory?.absolutePath ?: return emptyList()
|
val absPath = sCacheDirectory.absolutePath
|
||||||
|
|
||||||
for (i in 0..LOG_ROTATION_COUNT) {
|
for (i in 0..LOG_ROTATION_COUNT) {
|
||||||
val filepath = "$absPath/$sFileName.$i.txt"
|
val filepath = "$absPath/$sFileName.$i.txt"
|
||||||
|
@ -124,7 +111,7 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## addLogFiles() failed : %s", e.message)
|
Timber.e(e, "## addLogFiles() failed : " + e.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
|
@ -149,8 +149,6 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
private const val SETTINGS_USE_NATIVE_CAMERA_PREFERENCE_KEY = "SETTINGS_USE_NATIVE_CAMERA_PREFERENCE_KEY"
|
private const val SETTINGS_USE_NATIVE_CAMERA_PREFERENCE_KEY = "SETTINGS_USE_NATIVE_CAMERA_PREFERENCE_KEY"
|
||||||
private const val SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY = "SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY"
|
private const val SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY = "SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY"
|
||||||
|
|
||||||
const val SETTINGS_LABS_ALLOW_EXTENDED_LOGS = "SETTINGS_LABS_ALLOW_EXTENDED_LOGS"
|
|
||||||
|
|
||||||
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
||||||
private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
||||||
|
|
||||||
|
@ -259,10 +257,6 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY, true)
|
return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun labAllowedExtendedLogging(): Boolean {
|
|
||||||
return defaultPrefs.getBoolean(SETTINGS_LABS_ALLOW_EXTENDED_LOGS, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if we have already asked the user to disable battery optimisations on android >= M devices.
|
* Tells if we have already asked the user to disable battery optimisations on android >= M devices.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,7 +2,5 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!-- Strings not defined in Riot -->
|
<!-- Strings not defined in Riot -->
|
||||||
<string name="labs_allow_extended_logging">Enable verbose logs.</string>
|
|
||||||
<string name="labs_allow_extended_logging_summary">Verbose logs will help developers by providing more logs when you send a RageShake. Even when enabled, the application does not log message contents or any other private data.</string>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -45,13 +45,6 @@
|
||||||
android:key="SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
android:key="SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
||||||
android:title="@string/labs_swipe_to_reply_in_timeline" />
|
android:title="@string/labs_swipe_to_reply_in_timeline" />
|
||||||
|
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorSwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="SETTINGS_LABS_ALLOW_EXTENDED_LOGS"
|
|
||||||
android:summary="@string/labs_allow_extended_logging_summary"
|
|
||||||
android:title="@string/labs_allow_extended_logging" />
|
|
||||||
|
|
||||||
<!--</im.vector.riotx.core.preference.VectorPreferenceCategory>-->
|
<!--</im.vector.riotx.core.preference.VectorPreferenceCategory>-->
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue