Merge pull request #321 from vector-im/feature/workManager_clean

Fix bug on WorkManager: clean by tag
This commit is contained in:
Benoit Marty 2019-07-09 18:30:07 +02:00 committed by GitHub
commit f66739491a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 150 additions and 149 deletions

View File

@ -33,6 +33,8 @@ android {
targetSdkVersion 28 targetSdkVersion 28
versionCode 1 versionCode 1
versionName "0.0.1" versionName "0.0.1"
// Multidex is useful for tests
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"


buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
@ -66,6 +68,11 @@ android {
lintOptions { lintOptions {
lintConfig file("lint.xml") lintConfig file("lint.xml")
} }

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
} }


static def gitRevision() { static def gitRevision() {

View File

@ -52,7 +52,7 @@ internal class JsonCanonicalizerTest : InstrumentedTest {


@Test @Test
fun realSampleTest() { fun realSampleTest() {
assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""", assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}""")) JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}"""))
} }



View File

@ -59,7 +59,7 @@ internal class ChunkEntityTest : InstrumentedTest {
val chunk: ChunkEntity = realm.createObject() val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent() val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.events.size shouldEqual 1 chunk.timelineEvents.size shouldEqual 1
} }
} }


@ -70,7 +70,7 @@ internal class ChunkEntityTest : InstrumentedTest {
val fakeEvent = createFakeMessageEvent() val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.events.size shouldEqual 1 chunk.timelineEvents.size shouldEqual 1
} }
} }


@ -126,7 +126,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS) chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.events.size shouldEqual 60 chunk1.timelineEvents.size shouldEqual 60
} }
} }


@ -142,7 +142,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS) chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS) chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS) chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.events.size shouldEqual 40 chunk1.timelineEvents.size shouldEqual 40
chunk1.isLastForward.shouldBeTrue() chunk1.isLastForward.shouldBeTrue()
} }
} }

View File

@ -48,7 +48,6 @@ import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAct
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
@ -74,12 +73,12 @@ import im.vector.matrix.android.internal.session.room.membership.RoomMembers
import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import im.vector.matrix.android.internal.util.fetchCopied import im.vector.matrix.android.internal.util.fetchCopied
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.matrix.olm.OlmManager import org.matrix.olm.OlmManager
import timber.log.Timber import timber.log.Timber
import java.io.File
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject import javax.inject.Inject
@ -766,7 +765,7 @@ internal class CryptoManager @Inject constructor(
private suspend fun uploadDeviceKeys(): Try<KeysUploadResponse> { private suspend fun uploadDeviceKeys(): Try<KeysUploadResponse> {
// Prepare the device keys data to send // Prepare the device keys data to send
// Sign it // Sign it
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
getMyDevice().signatures = objectSigner.signObject(canonicalJson) getMyDevice().signatures = objectSigner.signObject(canonicalJson)


// For now, we set the device id explicitly, as we may not be using the // For now, we set the device id explicitly, as we may not be using the

View File

@ -28,6 +28,7 @@ import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.convertFromUTF8 import im.vector.matrix.android.internal.util.convertFromUTF8
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import org.matrix.olm.* import org.matrix.olm.*
@ -728,7 +729,7 @@ internal class MXOlmDevice @Inject constructor(
@Throws(Exception::class) @Throws(Exception::class)
fun verifySignature(key: String, jsonDictionary: Map<String, Any>, signature: String) { fun verifySignature(key: String, jsonDictionary: Map<String, Any>, signature: String) {
// Check signature on the canonical version of the JSON // Check signature on the canonical version of the JSON
olmUtility!!.verifyEd25519Signature(signature, key, MoshiProvider.getCanonicalJson<Map<*, *>>(Map::class.java, jsonDictionary)) olmUtility!!.verifyEd25519Signature(signature, key, JsonCanonicalizer.getCanonicalJson(Map::class.java, jsonDictionary))
} }


/** /**

View File

@ -22,8 +22,8 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.crypto.model.MXKey import im.vector.matrix.android.internal.crypto.model.MXKey
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import org.matrix.olm.OlmAccount import org.matrix.olm.OlmAccount
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -158,7 +158,7 @@ internal class OneTimeKeysUploader @Inject constructor(
k["key"] = curve25519Map.getValue(key_id) k["key"] = curve25519Map.getValue(key_id)


// the key is also signed // the key is also signed
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, k) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, k)


k["signatures"] = objectSigner.signObject(canonicalJson) k["signatures"] = objectSigner.signObject(canonicalJson)



View File

@ -22,8 +22,7 @@ import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_OLM
import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.MXOlmDevice
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.EncryptedMessage import im.vector.matrix.android.internal.crypto.model.rest.EncryptedMessage
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -81,7 +80,7 @@ internal class MessageEncrypter @Inject constructor(private val credentials: Cre
recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!! recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!!
payloadJson["recipient_keys"] = recipientsKeysMap payloadJson["recipient_keys"] = recipientsKeysMap


val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson)) val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!! ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!!
} }
} }

View File

@ -36,7 +36,7 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -263,7 +263,7 @@ internal class MXMegolmEncryption(


// Get canonical Json from // Get canonical Json from


val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson)) val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString!!) val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString!!)


val map = HashMap<String, Any>() val map = HashMap<String, Any>()

View File

@ -55,6 +55,7 @@ import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -176,7 +177,7 @@ internal class KeysBackup @Inject constructor(
megolmBackupAuthData.publicKey = publicKey megolmBackupAuthData.publicKey = publicKey
} }


val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())


megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson) megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson)


@ -456,7 +457,7 @@ internal class KeysBackup @Inject constructor(


if (trust) { if (trust) {
// Add current device signature // Add current device signature
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary())


val deviceSignatures = objectSigner.signObject(canonicalJson) val deviceSignatures = objectSigner.signObject(canonicalJson)



View File

@ -29,8 +29,8 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import timber.log.Timber import timber.log.Timber


internal class IncomingSASVerificationTransaction( internal class IncomingSASVerificationTransaction(
@ -147,7 +147,7 @@ internal class IncomingSASVerificationTransaction(


//The hash commitment is the hash (using the selected hash algorithm) of the unpadded base64 representation of QB, //The hash commitment is the hash (using the selected hash algorithm) of the unpadded base64 representation of QB,
// concatenated with the canonical JSON representation of the content of the m.key.verification.start message // concatenated with the canonical JSON representation of the content of the m.key.verification.start message
val concat = getSAS().publicKey + MoshiProvider.getCanonicalJson(KeyVerificationStart::class.java, startReq!!) val concat = getSAS().publicKey + JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, startReq!!)
accept.commitment = hashUsingAgreedHashMethod(concat) ?: "" accept.commitment = hashUsingAgreedHashMethod(concat) ?: ""
//we need to send this to other device now //we need to send this to other device now
state = SasVerificationTxState.SendingAccept state = SasVerificationTxState.SendingAccept

View File

@ -27,8 +27,8 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import timber.log.Timber import timber.log.Timber


internal class OutgoingSASVerificationRequest( internal class OutgoingSASVerificationRequest(
@ -164,7 +164,7 @@ internal class OutgoingSASVerificationRequest(
// in Bobs m.key.verification.key and the content of Alices m.key.verification.start message. // in Bobs m.key.verification.key and the content of Alices m.key.verification.start message.


//check commitment //check commitment
val concat = vKey.key + MoshiProvider.getCanonicalJson(KeyVerificationStart::class.java, startReq!!) val concat = vKey.key + JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, startReq!!)
val otherCommitment = hashUsingAgreedHashMethod(concat) ?: "" val otherCommitment = hashUsingAgreedHashMethod(concat) ?: ""


if (accepted!!.commitment.equals(otherCommitment)) { if (accepted!!.commitment.equals(otherCommitment)) {

View File

@ -16,6 +16,7 @@


package im.vector.matrix.android.internal.database.helper package im.vector.matrix.android.internal.database.helper


import androidx.annotation.VisibleForTesting
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.room.send.SendState import im.vector.matrix.android.api.session.room.send.SendState
@ -102,11 +103,12 @@ internal fun ChunkEntity.updateSenderDataFor(eventIds: List<String>) {
} }
} }


private fun ChunkEntity.add(roomId: String, @VisibleForTesting
event: Event, internal fun ChunkEntity.add(roomId: String,
direction: PaginationDirection, event: Event,
stateIndexOffset: Int = 0, direction: PaginationDirection,
isUnlinked: Boolean = false) { stateIndexOffset: Int = 0,
isUnlinked: Boolean = false) {


assertIsManaged() assertIsManaged()
if (event.eventId != null && timelineEvents.find(event.eventId) != null) { if (event.eventId != null && timelineEvents.find(event.eventId) != null) {
@ -149,14 +151,14 @@ private fun ChunkEntity.add(roomId: String,


internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
return when (direction) { return when (direction) {
PaginationDirection.FORWARDS -> forwardsDisplayIndex PaginationDirection.FORWARDS -> forwardsDisplayIndex
PaginationDirection.BACKWARDS -> backwardsDisplayIndex PaginationDirection.BACKWARDS -> backwardsDisplayIndex
} ?: defaultValue } ?: defaultValue
} }


internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
return when (direction) { return when (direction) {
PaginationDirection.FORWARDS -> forwardsStateIndex PaginationDirection.FORWARDS -> forwardsStateIndex
PaginationDirection.BACKWARDS -> backwardsStateIndex PaginationDirection.BACKWARDS -> backwardsStateIndex
} ?: defaultValue } ?: defaultValue
} }

View File

@ -23,7 +23,6 @@ import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
import im.vector.matrix.android.internal.session.sync.model.UserAccountData import im.vector.matrix.android.internal.session.sync.model.UserAccountData
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback
import im.vector.matrix.android.internal.util.JsonCanonicalizer




object MoshiProvider { object MoshiProvider {
@ -50,19 +49,6 @@ object MoshiProvider {
return moshi return moshi
} }


// TODO Move
fun <T> getCanonicalJson(type: Class<T>, o: T): String {
val adapter = moshi.adapter<T>(type)

val json = adapter.toJson(o)

// Canonicalize manually
val can = JsonCanonicalizer.canonicalize(json)

val jsonSafe = can.replace("\\/", "/")

return jsonSafe
}
} }





View File

@ -20,7 +20,6 @@ import android.content.Context
import android.os.Looper import android.os.Looper
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.work.WorkManager
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.pushrules.PushRuleService import im.vector.matrix.android.api.pushrules.PushRuleService
@ -44,6 +43,7 @@ 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
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject


@ -150,10 +150,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
Timber.w("SIGN_OUT: clear cache -> SUCCESS: clear crypto cache") Timber.w("SIGN_OUT: clear cache -> SUCCESS: clear crypto cache")
cryptoService.clearCryptoCache(MatrixCallbackDelegate(callback)) cryptoService.clearCryptoCache(MatrixCallbackDelegate(callback))


WorkManager.getInstance(context).also { WorkManagerUtil.cancelAllWorks(context)
it.cancelAllWork()
it.pruneWork()
}
} }


override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {

View File

@ -17,10 +17,7 @@
package im.vector.matrix.android.internal.session.group package im.vector.matrix.android.internal.session.group


import android.content.Context import android.content.Context
import androidx.work.Constraints
import androidx.work.ExistingWorkPolicy import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
@ -28,6 +25,8 @@ import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.worker.WorkManagerUtil
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 io.realm.RealmConfiguration import io.realm.RealmConfiguration
import javax.inject.Inject import javax.inject.Inject
@ -41,18 +40,14 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont


override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) } override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) }


private val workConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()

override fun processChanges(inserted: List<GroupEntity>, updated: List<GroupEntity>, deleted: List<GroupEntity>) { override fun processChanges(inserted: List<GroupEntity>, updated: List<GroupEntity>, deleted: List<GroupEntity>) {
val newGroupIds = inserted.map { it.groupId } val newGroupIds = inserted.map { it.groupId }
val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, newGroupIds) val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, newGroupIds)
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams) val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)


val sendWork = OneTimeWorkRequestBuilder<GetGroupDataWorker>() val sendWork = matrixOneTimeWorkRequestBuilder<GetGroupDataWorker>()
.setInputData(workData) .setInputData(workData)
.setConstraints(workConstraints) .setConstraints(WorkManagerUtil.workConstraints)
.build() .build()


WorkManager.getInstance(context) WorkManager.getInstance(context)

View File

@ -18,23 +18,19 @@ package im.vector.matrix.android.internal.session.pushers
import android.content.Context import android.content.Context
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.work.BackoffPolicy import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.pushers.Pusher import im.vector.matrix.android.api.session.pushers.Pusher
import im.vector.matrix.android.api.session.pushers.PusherState
import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.PusherEntity import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.model.PusherEntityFields
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.worker.WorkManagerUtil
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.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -76,10 +72,8 @@ internal class DefaultPusherService @Inject constructor(


val params = AddHttpPusherWorker.Params(pusher, sessionParam.credentials.userId) val params = AddHttpPusherWorker.Params(pusher, sessionParam.credentials.userId)


val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() val request = matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()

.setConstraints(WorkManagerUtil.workConstraints)
val request = OneTimeWorkRequestBuilder<AddHttpPusherWorker>()
.setConstraints(constraints)
.setInputData(WorkerParamsFactory.toData(params)) .setInputData(WorkerParamsFactory.toData(params))
.setBackoffCriteria(BackoffPolicy.LINEAR, 10_000L, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, 10_000L, TimeUnit.MILLISECONDS)
.build() .build()

View File

@ -17,7 +17,10 @@
package im.vector.matrix.android.internal.session.room.send package im.vector.matrix.android.internal.session.room.send


import android.content.Context import android.content.Context
import androidx.work.* import androidx.work.BackoffPolicy
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.content.ContentAttachmentData import im.vector.matrix.android.api.session.content.ContentAttachmentData
@ -29,6 +32,8 @@ import im.vector.matrix.android.api.util.CancelableBag
import im.vector.matrix.android.internal.session.content.UploadContentWorker import im.vector.matrix.android.internal.session.content.UploadContentWorker
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
import im.vector.matrix.android.internal.util.CancelableWork import im.vector.matrix.android.internal.util.CancelableWork
import im.vector.matrix.android.internal.worker.WorkManagerUtil
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 timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -37,10 +42,6 @@ import javax.inject.Inject
private const val UPLOAD_WORK = "UPLOAD_WORK" private const val UPLOAD_WORK = "UPLOAD_WORK"
private const val BACKOFF_DELAY = 10_000L private const val BACKOFF_DELAY = 10_000L


private val WORK_CONSTRAINTS = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()

internal class DefaultSendService @Inject constructor(private val context: Context, internal class DefaultSendService @Inject constructor(private val context: Context,
private val credentials: Credentials, private val credentials: Credentials,
private val roomId: String, private val roomId: String,
@ -135,8 +136,8 @@ internal class DefaultSendService @Inject constructor(private val context: Conte
val params = EncryptEventWorker.Params(credentials.userId, roomId, event) val params = EncryptEventWorker.Params(credentials.userId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(params) val sendWorkData = WorkerParamsFactory.toData(params)


return OneTimeWorkRequestBuilder<EncryptEventWorker>() return matrixOneTimeWorkRequestBuilder<EncryptEventWorker>()
.setConstraints(WORK_CONSTRAINTS) .setConstraints(WorkManagerUtil.workConstraints)
.setInputData(sendWorkData) .setInputData(sendWorkData)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
.build() .build()
@ -162,8 +163,8 @@ internal class DefaultSendService @Inject constructor(private val context: Conte
val uploadMediaWorkerParams = UploadContentWorker.Params(credentials.userId, roomId, event, attachment, isRoomEncrypted) val uploadMediaWorkerParams = UploadContentWorker.Params(credentials.userId, roomId, event, attachment, isRoomEncrypted)
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams) val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)


return OneTimeWorkRequestBuilder<UploadContentWorker>() return matrixOneTimeWorkRequestBuilder<UploadContentWorker>()
.setConstraints(WORK_CONSTRAINTS) .setConstraints(WorkManagerUtil.workConstraints)
.setInputData(uploadWorkData) .setInputData(uploadWorkData)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
.build() .build()

View File

@ -17,16 +17,14 @@ package im.vector.matrix.android.internal.session.room.timeline


import android.content.Context import android.content.Context
import androidx.work.* import androidx.work.*
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit




private const val SEND_WORK = "SEND_WORK" private const val SEND_WORK = "SEND_WORK"
private const val BACKOFF_DELAY = 10_000L private const val BACKOFF_DELAY = 10_000L


private val WORK_CONSTRAINTS = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()

/** /**
* Helper class for sending event related works. * Helper class for sending event related works.
* All send event from a room are using the same workchain, in order to ensure order. * All send event from a room are using the same workchain, in order to ensure order.
@ -60,8 +58,8 @@ internal object TimelineSendEventWorkCommon {
} }


inline fun <reified W : ListenableWorker> createWork(data: Data): OneTimeWorkRequest { inline fun <reified W : ListenableWorker> createWork(data: Data): OneTimeWorkRequest {
return OneTimeWorkRequestBuilder<W>() return matrixOneTimeWorkRequestBuilder<W>()
.setConstraints(WORK_CONSTRAINTS) .setConstraints(WorkManagerUtil.workConstraints)
.setInputData(data) .setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
.build() .build()

View File

@ -24,6 +24,8 @@ import im.vector.matrix.android.internal.session.sync.SyncTask
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.worker.WorkManagerUtil
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 im.vector.matrix.android.internal.worker.getSessionComponent import im.vector.matrix.android.internal.worker.getSessionComponent
import timber.log.Timber import timber.log.Timber
@ -86,11 +88,9 @@ internal class SyncWorker(context: Context,


fun requireBackgroundSync(context: Context, userId: String, serverTimeout: Long = 0) { fun requireBackgroundSync(context: Context, userId: String, serverTimeout: Long = 0) {
val data = WorkerParamsFactory.toData(Params(userId, serverTimeout, false)) val data = WorkerParamsFactory.toData(Params(userId, serverTimeout, false))
val workRequest = OneTimeWorkRequestBuilder<SyncWorker>() val workRequest = matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setInputData(data) .setInputData(data)
.setConstraints(Constraints.Builder() .setConstraints(WorkManagerUtil.workConstraints)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS)
.build() .build()
WorkManager.getInstance(context).enqueueUniqueWork("BG_SYNCP", ExistingWorkPolicy.REPLACE, workRequest) WorkManager.getInstance(context).enqueueUniqueWork("BG_SYNCP", ExistingWorkPolicy.REPLACE, workRequest)
@ -98,11 +98,9 @@ internal class SyncWorker(context: Context,


fun automaticallyBackgroundSync(context: Context, userId: String, serverTimeout: Long = 0, delay: Long = 30_000) { fun automaticallyBackgroundSync(context: Context, userId: String, serverTimeout: Long = 0, delay: Long = 30_000) {
val data = WorkerParamsFactory.toData(Params(userId, serverTimeout, true)) val data = WorkerParamsFactory.toData(Params(userId, serverTimeout, true))
val workRequest = OneTimeWorkRequestBuilder<SyncWorker>() val workRequest = matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setInputData(data) .setInputData(data)
.setConstraints(Constraints.Builder() .setConstraints(WorkManagerUtil.workConstraints)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.setBackoffCriteria(BackoffPolicy.LINEAR, delay, TimeUnit.MILLISECONDS) .setBackoffCriteria(BackoffPolicy.LINEAR, delay, TimeUnit.MILLISECONDS)
.build() .build()
WorkManager.getInstance(context).enqueueUniqueWork("BG_SYNCP", ExistingWorkPolicy.REPLACE, workRequest) WorkManager.getInstance(context).enqueueUniqueWork("BG_SYNCP", ExistingWorkPolicy.REPLACE, workRequest)

View File

@ -16,6 +16,8 @@


package im.vector.matrix.android.internal.util package im.vector.matrix.android.internal.util


import androidx.annotation.VisibleForTesting
import im.vector.matrix.android.internal.di.MoshiProvider
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
@ -28,45 +30,41 @@ import java.util.*
*/ */
object JsonCanonicalizer { object JsonCanonicalizer {


fun canonicalize(json: String): String { fun <T> getCanonicalJson(type: Class<T>, o: T): String {
var can: String? = null val adapter = MoshiProvider.providesMoshi().adapter<T>(type)
try {
val _json = JSONObject(json)


can = _canonicalize(_json) // Canonicalize manually
return canonicalize(adapter.toJson(o))
.replace("\\/", "/")
}

@VisibleForTesting
fun canonicalize(jsonString: String): String {
return try {
val jsonObject = JSONObject(jsonString)

canonicalizeRecursive(jsonObject)
} catch (e: JSONException) { } catch (e: JSONException) {
Timber.e(e, "Unable to canonicalize") Timber.e(e, "Unable to canonicalize")
jsonString
} }

if (can == null) {
Timber.e("Error")
return json
}

return can
} }


/** /**
* Canonicalize a JsonElement element * Canonicalize a JSON element
* *
* @param src the src * @param src the src
* @return the canonicalize element * @return the canonicalize element
*/ */
private fun _canonicalize(src: Any?): String? { private fun canonicalizeRecursive(any: Any): String {
// sanity check when (any) {
if (null == src) {
return null
}

when (src) {
is JSONArray -> { is JSONArray -> {
// Canonicalize each element of the array // Canonicalize each element of the array
val srcArray = src as JSONArray?
val result = StringBuilder("[") val result = StringBuilder("[")


for (i in 0 until srcArray!!.length()) { for (i in 0 until any.length()) {
result.append(_canonicalize(srcArray.get(i))) result.append(canonicalizeRecursive(any.get(i)))
if (i < srcArray.length() - 1) { if (i < any.length() - 1) {
result.append(",") result.append(",")
} }
} }
@ -76,11 +74,11 @@ object JsonCanonicalizer {
return result.toString() return result.toString()
} }
is JSONObject -> { is JSONObject -> {
// Sort the attributes by name, and the canonicalize each element of the object // Sort the attributes by name, and the canonicalize each element of the JSONObject
val result = StringBuilder("{") val result = StringBuilder("{")


val attributes = TreeSet<String>() val attributes = TreeSet<String>()
for (entry in src.keys()) { for (entry in any.keys()) {
attributes.add(entry) attributes.add(entry)
} }


@ -89,7 +87,7 @@ object JsonCanonicalizer {
.append(attribute.value) .append(attribute.value)
.append("\"") .append("\"")
.append(":") .append(":")
.append(_canonicalize(src[attribute.value])) .append(canonicalizeRecursive(any[attribute.value]))


if (attribute.index < attributes.size - 1) { if (attribute.index < attributes.size - 1) {
result.append(",") result.append(",")
@ -100,8 +98,8 @@ object JsonCanonicalizer {


return result.toString() return result.toString()
} }
is String -> return JSONObject.quote(src) is String -> return JSONObject.quote(any)
else -> return src.toString() else -> return any.toString()
} }
} }



View File

@ -0,0 +1,48 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.worker

import android.content.Context
import androidx.work.*

internal object WorkManagerUtil {
private const val MATRIX_SDK_TAG = "MatrixSDK"

/**
* Default constraints: connected network
*/
val workConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()

/**
* Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
*/
inline fun <reified W : ListenableWorker> matrixOneTimeWorkRequestBuilder() =
OneTimeWorkRequestBuilder<W>()
.addTag(MATRIX_SDK_TAG)

/**
* Cancel all works instantiated by the Matrix SDK and not those from the SDK client
*/
fun cancelAllWorks(context: Context) {
WorkManager.getInstance(context).also {
it.cancelAllWorkByTag(MATRIX_SDK_TAG)
it.pruneWork()
}
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.worker

import androidx.work.ListenableWorker
import dagger.MapKey
import kotlin.reflect.KClass

@MapKey
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class WorkerKey(val value: KClass<out ListenableWorker>)

View File

@ -147,3 +147,6 @@ android\.app\.AlertDialog


### Use JsonUtils.getBasicGson() ### Use JsonUtils.getBasicGson()
new Gson\(\) new Gson\(\)

### Use matrixOneTimeWorkRequestBuilder
import androidx.work.OneTimeWorkRequestBuilder===1