mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge branch 'develop' into feature/fga/timeline_chunks_rework
This commit is contained in:
commit
49eee0dc38
1
changelog.d/4546.bugfix
Normal file
1
changelog.d/4546.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fix lots of integration tests by introducing TestMatrix class and MatrixWorkerFactory.
|
1
changelog.d/4621.bugfix
Normal file
1
changelog.d/4621.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fix for outgoing voip call via sip bridge failing after 1 minute.
|
1
changelog.d/4626.misc
Normal file
1
changelog.d/4626.misc
Normal file
@ -0,0 +1 @@
|
||||
Introducing feature flagging to the login and notification settings flows
|
@ -20,9 +20,10 @@ import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
|
||||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@ -30,7 +31,6 @@ import kotlinx.coroutines.withTimeout
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.matrix.android.sdk.api.Matrix
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||
@ -45,7 +45,7 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
|
||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||
import java.util.ArrayList
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -56,13 +56,14 @@ import java.util.concurrent.TimeUnit
|
||||
*/
|
||||
class CommonTestHelper(context: Context) {
|
||||
|
||||
val matrix: Matrix
|
||||
internal val matrix: TestMatrix
|
||||
val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
|
||||
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestNetworkModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
|
||||
fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
|
||||
|
||||
init {
|
||||
UiThreadStatement.runOnUiThread {
|
||||
Matrix.initialize(
|
||||
TestMatrix.initialize(
|
||||
context,
|
||||
MatrixConfiguration(
|
||||
applicationFlavor = "TestFlavor",
|
||||
@ -70,7 +71,7 @@ class CommonTestHelper(context: Context) {
|
||||
)
|
||||
)
|
||||
}
|
||||
matrix = Matrix.getInstance(context)
|
||||
matrix = TestMatrix.getInstance(context)
|
||||
}
|
||||
|
||||
fun createAccount(userNamePrefix: String, testParams: SessionTestParams): Session {
|
||||
@ -95,33 +96,47 @@ class CommonTestHelper(context: Context) {
|
||||
*
|
||||
* @param session the session to sync
|
||||
*/
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis) {
|
||||
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) {
|
||||
val lock = CountDownLatch(1)
|
||||
|
||||
val job = GlobalScope.launch(Dispatchers.Main) {
|
||||
session.open()
|
||||
}
|
||||
runBlocking { job.join() }
|
||||
|
||||
session.startSync(true)
|
||||
|
||||
val syncLiveData = runBlocking(Dispatchers.Main) {
|
||||
session.getSyncStateLive()
|
||||
}
|
||||
val syncObserver = object : Observer<SyncState> {
|
||||
override fun onChanged(t: SyncState?) {
|
||||
if (session.hasAlreadySynced()) {
|
||||
lock.countDown()
|
||||
syncLiveData.removeObserver(this)
|
||||
coroutineScope.launch {
|
||||
session.startSync(true)
|
||||
val syncLiveData = session.getSyncStateLive()
|
||||
val syncObserver = object : Observer<SyncState> {
|
||||
override fun onChanged(t: SyncState?) {
|
||||
if (session.hasAlreadySynced()) {
|
||||
lock.countDown()
|
||||
syncLiveData.removeObserver(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
syncLiveData.observeForever(syncObserver)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.Main) { syncLiveData.observeForever(syncObserver) }
|
||||
|
||||
await(lock, timeout)
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods clear the cache and waits for initialSync
|
||||
*
|
||||
* @param session the session to sync
|
||||
*/
|
||||
fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) {
|
||||
waitWithLatch(timeout) { latch ->
|
||||
session.clearCache()
|
||||
val syncLiveData = session.getSyncStateLive()
|
||||
val syncObserver = object : Observer<SyncState> {
|
||||
override fun onChanged(t: SyncState?) {
|
||||
if (session.hasAlreadySynced()) {
|
||||
Timber.v("Clear cache and synced")
|
||||
syncLiveData.removeObserver(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
syncLiveData.observeForever(syncObserver)
|
||||
session.startSync(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends text messages in a room
|
||||
*
|
||||
@ -130,46 +145,57 @@ class CommonTestHelper(context: Context) {
|
||||
* @param nbOfMessages the number of time the message will be sent
|
||||
*/
|
||||
fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> {
|
||||
val timeline = room.createTimeline(null, TimelineSettings(10))
|
||||
val sentEvents = ArrayList<TimelineEvent>(nbOfMessages)
|
||||
val latch = CountDownLatch(1)
|
||||
val timelineListener = object : Timeline.Listener {
|
||||
override fun onTimelineFailure(throwable: Throwable) {
|
||||
}
|
||||
val timeline = room.createTimeline(null, TimelineSettings(10))
|
||||
timeline.start()
|
||||
waitWithLatch(timeout + 1_000L * nbOfMessages) { latch ->
|
||||
val timelineListener = object : Timeline.Listener {
|
||||
override fun onTimelineFailure(throwable: Throwable) {
|
||||
}
|
||||
|
||||
override fun onNewTimelineEvents(eventIds: List<String>) {
|
||||
// noop
|
||||
}
|
||||
override fun onNewTimelineEvents(eventIds: List<String>) {
|
||||
// noop
|
||||
}
|
||||
|
||||
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
|
||||
val newMessages = snapshot
|
||||
.filter { it.root.sendState == SendState.SYNCED }
|
||||
.filter { it.root.getClearType() == EventType.MESSAGE }
|
||||
.filter { it.root.getClearContent().toModel<MessageContent>()?.body?.startsWith(message) == true }
|
||||
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
|
||||
val newMessages = snapshot
|
||||
.filter { it.root.sendState == SendState.SYNCED }
|
||||
.filter { it.root.getClearType() == EventType.MESSAGE }
|
||||
.filter { it.root.getClearContent().toModel<MessageContent>()?.body?.startsWith(message) == true }
|
||||
|
||||
if (newMessages.size == nbOfMessages) {
|
||||
sentEvents.addAll(newMessages)
|
||||
// Remove listener now, if not at the next update sendEvents could change
|
||||
timeline.removeListener(this)
|
||||
latch.countDown()
|
||||
Timber.v("New synced message size: ${newMessages.size}")
|
||||
if (newMessages.size == nbOfMessages) {
|
||||
sentEvents.addAll(newMessages)
|
||||
// Remove listener now, if not at the next update sendEvents could change
|
||||
timeline.removeListener(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
timeline.addListener(timelineListener)
|
||||
sendTextMessagesBatched(room, message, nbOfMessages)
|
||||
}
|
||||
timeline.start()
|
||||
timeline.addListener(timelineListener)
|
||||
for (i in 0 until nbOfMessages) {
|
||||
room.sendTextMessage(message + " #" + (i + 1))
|
||||
}
|
||||
// Wait 3 second more per message
|
||||
await(latch, timeout = timeout + 3_000L * nbOfMessages)
|
||||
timeline.dispose()
|
||||
|
||||
// Check that all events has been created
|
||||
assertEquals("Message number do not match $sentEvents", nbOfMessages.toLong(), sentEvents.size.toLong())
|
||||
|
||||
return sentEvents
|
||||
}
|
||||
|
||||
/**
|
||||
* Will send nb of messages provided by count parameter but waits a bit every 10 messages to avoid gap in sync
|
||||
*/
|
||||
private fun sendTextMessagesBatched(room: Room, message: String, count: Int) {
|
||||
(1 until count + 1)
|
||||
.map { "$message #$it" }
|
||||
.chunked(10)
|
||||
.forEach { batchedMessages ->
|
||||
batchedMessages.forEach { formattedMessage ->
|
||||
room.sendTextMessage(formattedMessage)
|
||||
}
|
||||
Thread.sleep(1_000L)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
/**
|
||||
@ -239,10 +265,10 @@ class CommonTestHelper(context: Context) {
|
||||
|
||||
assertTrue(registrationResult is RegistrationResult.Success)
|
||||
val session = (registrationResult as RegistrationResult.Success).session
|
||||
session.open()
|
||||
if (sessionTestParams.withInitialSync) {
|
||||
syncSession(session, 60_000)
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
@ -267,7 +293,7 @@ class CommonTestHelper(context: Context) {
|
||||
.getLoginWizard()
|
||||
.login(userName, password, "myDevice")
|
||||
}
|
||||
|
||||
session.open()
|
||||
if (sessionTestParams.withInitialSync) {
|
||||
syncSession(session)
|
||||
}
|
||||
@ -332,22 +358,21 @@ class CommonTestHelper(context: Context) {
|
||||
assertTrue(latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
|
||||
GlobalScope.launch {
|
||||
while (true) {
|
||||
delay(1000)
|
||||
if (condition()) {
|
||||
latch.countDown()
|
||||
return@launch
|
||||
}
|
||||
suspend fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
|
||||
while (true) {
|
||||
delay(1000)
|
||||
if (condition()) {
|
||||
latch.countDown()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun waitWithLatch(timeout: Long? = TestConstants.timeOutMillis, block: (CountDownLatch) -> Unit) {
|
||||
fun waitWithLatch(timeout: Long? = TestConstants.timeOutMillis, dispatcher: CoroutineDispatcher = Dispatchers.Main, block: suspend (CountDownLatch) -> Unit) {
|
||||
val latch = CountDownLatch(1)
|
||||
block(latch)
|
||||
coroutineScope.launch(dispatcher) {
|
||||
block(latch)
|
||||
}
|
||||
await(latch, timeout)
|
||||
}
|
||||
|
||||
|
@ -19,10 +19,6 @@ package org.matrix.android.sdk.common
|
||||
import android.os.SystemClock
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.Observer
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
@ -31,6 +27,7 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
|
||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||
import org.matrix.android.sdk.api.auth.UserPasswordAuth
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.OutgoingSasVerificationTransaction
|
||||
@ -44,16 +41,16 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
class CryptoTestHelper(private val testHelper: CommonTestHelper) {
|
||||
|
||||
private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
|
||||
private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
|
||||
@ -64,27 +61,33 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
* @return alice session
|
||||
*/
|
||||
fun doE2ETestWithAliceInARoom(encryptedRoom: Boolean = true): CryptoTestData {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
|
||||
|
||||
val roomId = mTestHelper.runBlockingTest {
|
||||
val roomId = testHelper.runBlockingTest {
|
||||
aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" })
|
||||
}
|
||||
|
||||
if (encryptedRoom) {
|
||||
val room = aliceSession.getRoom(roomId)!!
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
val room = aliceSession.getRoom(roomId)!!
|
||||
room.enableEncryption()
|
||||
val roomSummaryLive = room.getRoomSummaryLive()
|
||||
val roomSummaryObserver = object : Observer<Optional<RoomSummary>> {
|
||||
override fun onChanged(roomSummary: Optional<RoomSummary>) {
|
||||
if (roomSummary.getOrNull()?.isEncrypted.orFalse()) {
|
||||
roomSummaryLive.removeObserver(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
roomSummaryLive.observeForever(roomSummaryObserver)
|
||||
}
|
||||
}
|
||||
|
||||
return CryptoTestData(roomId, listOf(aliceSession))
|
||||
}
|
||||
|
||||
/**
|
||||
* @return alice and bob sessions
|
||||
*/
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun doE2ETestWithAliceAndBobInARoom(encryptedRoom: Boolean = true): CryptoTestData {
|
||||
val cryptoTestData = doE2ETestWithAliceInARoom(encryptedRoom)
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
@ -92,54 +95,37 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
|
||||
val aliceRoom = aliceSession.getRoom(aliceRoomId)!!
|
||||
|
||||
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
|
||||
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
|
||||
|
||||
val lock1 = CountDownLatch(1)
|
||||
|
||||
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
|
||||
bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
}
|
||||
|
||||
val newRoomObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(t: List<RoomSummary>?) {
|
||||
if (t?.isNotEmpty() == true) {
|
||||
lock1.countDown()
|
||||
bobRoomSummariesLive.removeObserver(this)
|
||||
testHelper.waitWithLatch { latch ->
|
||||
val bobRoomSummariesLive = bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
val newRoomObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(t: List<RoomSummary>?) {
|
||||
if (t?.isNotEmpty() == true) {
|
||||
bobRoomSummariesLive.removeObserver(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
bobRoomSummariesLive.observeForever(newRoomObserver)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
aliceRoom.invite(bobSession.myUserId)
|
||||
}
|
||||
|
||||
mTestHelper.await(lock1)
|
||||
|
||||
val lock = CountDownLatch(1)
|
||||
|
||||
val roomJoinedObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(t: List<RoomSummary>?) {
|
||||
if (bobSession.getRoom(aliceRoomId)
|
||||
?.getRoomMember(aliceSession.myUserId)
|
||||
?.membership == Membership.JOIN) {
|
||||
lock.countDown()
|
||||
bobRoomSummariesLive.removeObserver(this)
|
||||
testHelper.waitWithLatch { latch ->
|
||||
val bobRoomSummariesLive = bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
val roomJoinedObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(t: List<RoomSummary>?) {
|
||||
if (bobSession.getRoom(aliceRoomId)
|
||||
?.getRoomMember(bobSession.myUserId)
|
||||
?.membership == Membership.JOIN) {
|
||||
bobRoomSummariesLive.removeObserver(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
bobRoomSummariesLive.observeForever(roomJoinedObserver)
|
||||
bobSession.joinRoom(aliceRoomId)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest { bobSession.joinRoom(aliceRoomId) }
|
||||
|
||||
mTestHelper.await(lock)
|
||||
|
||||
// Ensure bob can send messages to the room
|
||||
// val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
|
||||
// assertNotNull(roomFromBobPOV.powerLevels)
|
||||
@ -171,13 +157,13 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
* @Return Sam session
|
||||
*/
|
||||
fun createSamAccountAndInviteToTheRoom(room: Room): Session {
|
||||
val samSession = mTestHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
|
||||
val samSession = testHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
room.invite(samSession.myUserId, null)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
samSession.joinRoom(room.roomId, null, emptyList())
|
||||
}
|
||||
|
||||
@ -194,23 +180,20 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
||||
bobSession.cryptoService().setWarnOnUnknownDevices(false)
|
||||
|
||||
aliceSession.cryptoService().setWarnOnUnknownDevices(false)
|
||||
|
||||
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
|
||||
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
|
||||
|
||||
// Alice sends a message
|
||||
mTestHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[0], 1)
|
||||
// roomFromAlicePOV.sendTextMessage(messagesFromAlice[0])
|
||||
testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[0], 1)
|
||||
|
||||
// Bob send 3 messages
|
||||
mTestHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[0], 1)
|
||||
mTestHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[1], 1)
|
||||
mTestHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[2], 1)
|
||||
testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[0], 1)
|
||||
testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[1], 1)
|
||||
testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[2], 1)
|
||||
// Alice sends a message
|
||||
mTestHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[1], 1)
|
||||
|
||||
testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[1], 1)
|
||||
return cryptoTestData
|
||||
}
|
||||
|
||||
@ -256,60 +239,44 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun createDM(alice: Session, bob: Session): String {
|
||||
val roomId = mTestHelper.runBlockingTest {
|
||||
alice.createDirectRoom(bob.myUserId)
|
||||
}
|
||||
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
|
||||
bob.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
}
|
||||
|
||||
var roomId: String = ""
|
||||
testHelper.waitWithLatch { latch ->
|
||||
roomId = alice.createDirectRoom(bob.myUserId)
|
||||
val bobRoomSummariesLive = bob.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
val newRoomObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(t: List<RoomSummary>?) {
|
||||
val indexOfFirst = t?.indexOfFirst { it.roomId == roomId } ?: -1
|
||||
if (indexOfFirst != -1) {
|
||||
latch.countDown()
|
||||
bobRoomSummariesLive.removeObserver(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
bobRoomSummariesLive.observeForever(newRoomObserver)
|
||||
}
|
||||
bobRoomSummariesLive.observeForever(newRoomObserver)
|
||||
}
|
||||
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
|
||||
bob.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
}
|
||||
|
||||
testHelper.waitWithLatch { latch ->
|
||||
val bobRoomSummariesLive = bob.getRoomSummariesLive(roomSummaryQueryParams { })
|
||||
val newRoomObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(t: List<RoomSummary>?) {
|
||||
if (bob.getRoom(roomId)
|
||||
?.getRoomMember(bob.myUserId)
|
||||
?.membership == Membership.JOIN) {
|
||||
latch.countDown()
|
||||
bobRoomSummariesLive.removeObserver(this)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
bobRoomSummariesLive.observeForever(newRoomObserver)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest { bob.joinRoom(roomId) }
|
||||
bobRoomSummariesLive.observeForever(newRoomObserver)
|
||||
bob.joinRoom(roomId)
|
||||
}
|
||||
|
||||
return roomId
|
||||
}
|
||||
|
||||
fun initializeCrossSigning(session: Session) {
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
session.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -346,8 +313,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
var bobPovTx: IncomingSasVerificationTransaction? = null
|
||||
|
||||
// wait for alice to get the ready
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID) as? IncomingSasVerificationTransaction
|
||||
Log.v("TEST", "== bobPovTx is ${alicePovTx?.uxState}")
|
||||
if (bobPovTx?.state == VerificationTxState.OnStarted) {
|
||||
@ -359,16 +326,16 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
}
|
||||
}
|
||||
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
alicePovTx = aliceVerificationService.getExistingTransaction(bob.myUserId, requestID) as? OutgoingSasVerificationTransaction
|
||||
Log.v("TEST", "== alicePovTx is ${alicePovTx?.uxState}")
|
||||
alicePovTx?.state == VerificationTxState.ShortCodeReady
|
||||
}
|
||||
}
|
||||
// wait for alice to get the ready
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID) as? IncomingSasVerificationTransaction
|
||||
Log.v("TEST", "== bobPovTx is ${alicePovTx?.uxState}")
|
||||
if (bobPovTx?.state == VerificationTxState.OnStarted) {
|
||||
@ -383,38 +350,38 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
||||
bobPovTx!!.userHasVerifiedShortCode()
|
||||
alicePovTx!!.userHasVerifiedShortCode()
|
||||
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
alice.cryptoService().crossSigningService().isUserTrusted(bob.myUserId)
|
||||
}
|
||||
}
|
||||
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
alice.cryptoService().crossSigningService().isUserTrusted(bob.myUserId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun doE2ETestWithManyMembers(numberOfMembers: Int): CryptoTestData {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
|
||||
aliceSession.cryptoService().setWarnOnUnknownDevices(false)
|
||||
|
||||
val roomId = mTestHelper.runBlockingTest {
|
||||
val roomId = testHelper.runBlockingTest {
|
||||
aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" })
|
||||
}
|
||||
val room = aliceSession.getRoom(roomId)!!
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
room.enableEncryption()
|
||||
}
|
||||
|
||||
val sessions = mutableListOf(aliceSession)
|
||||
for (index in 1 until numberOfMembers) {
|
||||
val session = mTestHelper.createAccount("User_$index", defaultSessionParams)
|
||||
mTestHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) }
|
||||
val session = testHelper.createAccount("User_$index", defaultSessionParams)
|
||||
testHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) }
|
||||
println("TEST -> " + session.myUserId + " invited")
|
||||
mTestHelper.runBlockingTest { session.joinRoom(room.roomId, null, emptyList()) }
|
||||
testHelper.runBlockingTest { session.joinRoom(room.roomId, null, emptyList()) }
|
||||
println("TEST -> " + session.myUserId + " joined")
|
||||
sessions.add(session)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,13 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.worker
|
||||
package org.matrix.android.sdk.common
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.ListenableWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
|
||||
interface DelegateWorkerFactory {
|
||||
/**
|
||||
* Force foreground for testing
|
||||
*/
|
||||
internal class TestBackgroundDetectionObserver : BackgroundDetectionObserver {
|
||||
|
||||
fun create(context: Context, params: WorkerParameters): ListenableWorker
|
||||
override val isInBackground: Boolean = false
|
||||
|
||||
override fun register(listener: BackgroundDetectionObserver.Listener) = Unit
|
||||
|
||||
override fun unregister(listener: BackgroundDetectionObserver.Listener) = Unit
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api
|
||||
package org.matrix.android.sdk.common
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
@ -24,27 +24,27 @@ import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
||||
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
|
||||
import org.matrix.android.sdk.api.network.ApiInterceptorListener
|
||||
import org.matrix.android.sdk.api.network.ApiPath
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.common.DaggerTestMatrixComponent
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.network.ApiInterceptor
|
||||
import org.matrix.android.sdk.internal.network.UserAgentHolder
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This is the main entry point to the matrix sdk.
|
||||
* To get the singleton instance, use getInstance static method.
|
||||
* This mimics the Matrix class but using TestMatrixComponent internally instead of regular MatrixComponent.
|
||||
*/
|
||||
class Matrix private constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
|
||||
internal class TestMatrix constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
|
||||
|
||||
@Inject internal lateinit var legacySessionImporter: LegacySessionImporter
|
||||
@Inject internal lateinit var authenticationService: AuthenticationService
|
||||
@ -55,15 +55,18 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
@Inject internal lateinit var sessionManager: SessionManager
|
||||
@Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService
|
||||
@Inject internal lateinit var apiInterceptor: ApiInterceptor
|
||||
@Inject internal lateinit var matrixWorkerFactory: MatrixWorkerFactory
|
||||
|
||||
private val uiHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
init {
|
||||
Monarchy.init(context)
|
||||
DaggerTestMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
|
||||
if (context.applicationContext !is Configuration.Provider) {
|
||||
WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build())
|
||||
}
|
||||
val configuration = Configuration.Builder()
|
||||
.setExecutor(Executors.newCachedThreadPool())
|
||||
.setWorkerFactory(matrixWorkerFactory)
|
||||
.build()
|
||||
WorkManager.initialize(context, configuration)
|
||||
uiHandler.post {
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
|
||||
}
|
||||
@ -93,21 +96,21 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
|
||||
companion object {
|
||||
|
||||
private lateinit var instance: Matrix
|
||||
private lateinit var instance: TestMatrix
|
||||
private val isInit = AtomicBoolean(false)
|
||||
|
||||
fun initialize(context: Context, matrixConfiguration: MatrixConfiguration) {
|
||||
if (isInit.compareAndSet(false, true)) {
|
||||
instance = Matrix(context.applicationContext, matrixConfiguration)
|
||||
instance = TestMatrix(context.applicationContext, matrixConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
fun getInstance(context: Context): Matrix {
|
||||
fun getInstance(context: Context): TestMatrix {
|
||||
if (isInit.compareAndSet(false, true)) {
|
||||
val appContext = context.applicationContext
|
||||
if (appContext is MatrixConfiguration.Provider) {
|
||||
val matrixConfiguration = (appContext as MatrixConfiguration.Provider).providesMatrixConfiguration()
|
||||
instance = Matrix(appContext, matrixConfiguration)
|
||||
instance = TestMatrix(appContext, matrixConfiguration)
|
||||
} else {
|
||||
throw IllegalStateException("Matrix is not initialized properly." +
|
||||
" You should call Matrix.initialize or let your application implements MatrixConfiguration.Provider.")
|
@ -34,12 +34,13 @@ import org.matrix.android.sdk.internal.util.system.SystemModule
|
||||
NetworkModule::class,
|
||||
AuthModule::class,
|
||||
RawModule::class,
|
||||
SystemModule::class,
|
||||
TestNetworkModule::class
|
||||
SystemModule::class
|
||||
])
|
||||
@MatrixScope
|
||||
internal interface TestMatrixComponent : MatrixComponent {
|
||||
|
||||
fun inject(matrix: TestMatrix)
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(@BindsInstance context: Context,
|
||||
|
@ -18,10 +18,39 @@ package org.matrix.android.sdk.common
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.internal.di.MatrixComponent
|
||||
import org.matrix.android.sdk.internal.di.MatrixScope
|
||||
import org.matrix.android.sdk.internal.session.MockHttpInterceptor
|
||||
import org.matrix.android.sdk.internal.session.TestInterceptor
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
|
||||
@Module
|
||||
internal abstract class TestModule {
|
||||
@Binds
|
||||
abstract fun providesMatrixComponent(testMatrixComponent: TestMatrixComponent): MatrixComponent
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
|
||||
val interceptors = ArrayList<TestInterceptor>()
|
||||
|
||||
fun interceptorForSession(sessionId: String): TestInterceptor? = interceptors.firstOrNull { it.sessionId == sessionId }
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@MockHttpInterceptor
|
||||
fun providesTestInterceptor(): TestInterceptor? {
|
||||
return MockOkHttpInterceptor().also {
|
||||
interceptors.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@MatrixScope
|
||||
fun providesBackgroundDetectionObserver(): BackgroundDetectionObserver {
|
||||
return TestBackgroundDetectionObserver()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.common
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.internal.session.MockHttpInterceptor
|
||||
import org.matrix.android.sdk.internal.session.TestInterceptor
|
||||
|
||||
@Module
|
||||
internal object TestNetworkModule {
|
||||
|
||||
val interceptors = ArrayList<TestInterceptor>()
|
||||
|
||||
fun interceptorForSession(sessionId: String): TestInterceptor? = interceptors.firstOrNull { it.sessionId == sessionId }
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@MockHttpInterceptor
|
||||
fun providesTestInterceptor(): TestInterceptor? {
|
||||
return MockOkHttpInterceptor().also {
|
||||
interceptors.add(it)
|
||||
}
|
||||
}
|
||||
}
|
@ -36,12 +36,12 @@ import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyContent
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class PreShareKeysTest : InstrumentedTest {
|
||||
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
fun ensure_outbound_session_happy_path() {
|
||||
val testData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
|
||||
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
|
||||
val e2eRoomID = testData.roomId
|
||||
val aliceSession = testData.firstSession
|
||||
val bobSession = testData.secondSession!!
|
||||
@ -58,12 +58,12 @@ class PreShareKeysTest : InstrumentedTest {
|
||||
Log.d("#Test", "Room Key Received from alice $preShareCount")
|
||||
|
||||
// Force presharing of new outbound key
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
aliceSession.cryptoService().prepareToEncrypt(e2eRoomID, it)
|
||||
}
|
||||
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val newGossipCount = bobSession.cryptoService().getGossipingEvents().count {
|
||||
it.senderId == aliceSession.myUserId &&
|
||||
it.getClearType() == EventType.ROOM_KEY
|
||||
@ -88,16 +88,16 @@ class PreShareKeysTest : InstrumentedTest {
|
||||
assertEquals("The session received by bob should match what alice sent", 0, sharedIndex)
|
||||
|
||||
// Just send a real message as test
|
||||
val sentEvent = mTestHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()
|
||||
val sentEvent = testHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()
|
||||
|
||||
assertEquals(megolmSessionId, sentEvent.root.content.toModel<EncryptedEventContent>()?.sessionId, "Unexpected megolm session")
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
bobSession.getRoom(e2eRoomID)?.getTimeLineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE
|
||||
}
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
}
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ import kotlin.coroutines.resume
|
||||
class UnwedgingTest : InstrumentedTest {
|
||||
|
||||
private lateinit var messagesReceivedByBob: List<TimelineEvent>
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Before
|
||||
fun init() {
|
||||
@ -85,7 +85,7 @@ class UnwedgingTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun testUnwedging() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val aliceRoomId = cryptoTestData.roomId
|
||||
@ -133,7 +133,7 @@ class UnwedgingTest : InstrumentedTest {
|
||||
roomFromAlicePOV.sendTextMessage("First message")
|
||||
|
||||
// Wait for the message to be received by Bob
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
bobTimeline.removeListener(bobEventsListener)
|
||||
|
||||
messagesReceivedByBob.size shouldBe 1
|
||||
@ -161,7 +161,7 @@ class UnwedgingTest : InstrumentedTest {
|
||||
roomFromAlicePOV.sendTextMessage("Second message")
|
||||
|
||||
// Wait for the message to be received by Bob
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
bobTimeline.removeListener(bobEventsListener)
|
||||
|
||||
messagesReceivedByBob.size shouldBe 2
|
||||
@ -179,7 +179,7 @@ class UnwedgingTest : InstrumentedTest {
|
||||
aliceSession.cryptoService().discardOutboundSession(roomFromAlicePOV.roomId)
|
||||
|
||||
// Wait for the message to be received by Bob
|
||||
mTestHelper.waitWithLatch {
|
||||
testHelper.waitWithLatch {
|
||||
bobEventsListener = createEventListener(it, 3)
|
||||
bobTimeline.addListener(bobEventsListener)
|
||||
messagesReceivedByBob = emptyList()
|
||||
@ -201,11 +201,11 @@ class UnwedgingTest : InstrumentedTest {
|
||||
Assert.assertEquals(EventType.MESSAGE, messagesReceivedByBob[1].root.getClearType())
|
||||
Assert.assertEquals(EventType.MESSAGE, messagesReceivedByBob[2].root.getClearType())
|
||||
// Bob Should not be able to decrypt last message, because session could not be sent as the olm channel was wedged
|
||||
mTestHelper.await(bobFinalLatch)
|
||||
testHelper.await(bobFinalLatch)
|
||||
bobTimeline.removeListener(bobHasThreeDecryptedEventsListener)
|
||||
|
||||
// It's a trick to force key request on fail to decrypt
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
bobSession.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -222,8 +222,8 @@ class UnwedgingTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Wait until we received back the key
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
// we should get back the key and be able to decrypt
|
||||
val result = tryOrNull {
|
||||
bobSession.cryptoService().decryptEvent(messagesReceivedByBob[0].root, "")
|
||||
@ -235,7 +235,7 @@ class UnwedgingTest : InstrumentedTest {
|
||||
|
||||
bobTimeline.dispose()
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
private fun createEventListener(latch: CountDownLatch, expectedNumberOfMessages: Int): Timeline.Listener {
|
||||
|
@ -45,14 +45,14 @@ import kotlin.coroutines.resume
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class XSigningTest : InstrumentedTest {
|
||||
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
fun test_InitializeAndStoreKeys() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
aliceSession.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||
@ -79,12 +79,12 @@ class XSigningTest : InstrumentedTest {
|
||||
|
||||
assertTrue("Signing Keys should be trusted", aliceSession.cryptoService().crossSigningService().checkUserTrust(aliceSession.myUserId).isVerified())
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_CrossSigningCheckBobSeesTheKeys() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -98,21 +98,21 @@ class XSigningTest : InstrumentedTest {
|
||||
password = TestConstants.PASSWORD
|
||||
)
|
||||
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||
promise.resume(aliceAuthParams)
|
||||
}
|
||||
}, it)
|
||||
}
|
||||
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
testHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||
promise.resume(bobAuthParams)
|
||||
}
|
||||
}, it) }
|
||||
|
||||
// Check that alice can see bob keys
|
||||
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) }
|
||||
testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) }
|
||||
|
||||
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobSession.myUserId)
|
||||
assertNotNull("Alice can see bob Master key", bobKeysFromAlicePOV!!.masterKey())
|
||||
@ -124,13 +124,13 @@ class XSigningTest : InstrumentedTest {
|
||||
|
||||
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_CrossSigningTestAliceTrustBobNewDevice() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -144,12 +144,12 @@ class XSigningTest : InstrumentedTest {
|
||||
password = TestConstants.PASSWORD
|
||||
)
|
||||
|
||||
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
testHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||
promise.resume(aliceAuthParams)
|
||||
}
|
||||
}, it) }
|
||||
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
testHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor {
|
||||
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
|
||||
promise.resume(bobAuthParams)
|
||||
}
|
||||
@ -157,21 +157,21 @@ class XSigningTest : InstrumentedTest {
|
||||
|
||||
// Check that alice can see bob keys
|
||||
val bobUserId = bobSession.myUserId
|
||||
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it) }
|
||||
testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it) }
|
||||
|
||||
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobUserId)
|
||||
assertTrue("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV?.isTrusted() == false)
|
||||
|
||||
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, it) }
|
||||
testHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, it) }
|
||||
|
||||
// Now bobs logs in on a new device and verifies it
|
||||
// We will want to test that in alice POV, this new device would be trusted by cross signing
|
||||
|
||||
val bobSession2 = mTestHelper.logIntoAccount(bobUserId, SessionTestParams(true))
|
||||
val bobSession2 = testHelper.logIntoAccount(bobUserId, SessionTestParams(true))
|
||||
val bobSecondDeviceId = bobSession2.sessionParams.deviceId!!
|
||||
|
||||
// Check that bob first session sees the new login
|
||||
val data = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
val data = testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
bobSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
|
||||
}
|
||||
|
||||
@ -183,12 +183,12 @@ class XSigningTest : InstrumentedTest {
|
||||
assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice)
|
||||
|
||||
// Manually mark it as trusted from first session
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
bobSession.cryptoService().crossSigningService().trustDevice(bobSecondDeviceId, it)
|
||||
}
|
||||
|
||||
// Now alice should cross trust bob's second device
|
||||
val data2 = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
val data2 = testHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
|
||||
}
|
||||
|
||||
@ -200,8 +200,8 @@ class XSigningTest : InstrumentedTest {
|
||||
val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null)
|
||||
assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified())
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
mTestHelper.signOutAndClose(bobSession2)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(bobSession2)
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,9 @@ import java.util.concurrent.CountDownLatch
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class EncryptionTest : InstrumentedTest {
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
fun test_EncryptionEvent() {
|
||||
@ -69,7 +70,7 @@ class EncryptionTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
private fun performTest(roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false)
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false)
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val room = aliceSession.getRoom(cryptoTestData.roomId)!!
|
||||
@ -101,12 +102,12 @@ class EncryptionTest : InstrumentedTest {
|
||||
timeline.addListener(timelineListener)
|
||||
|
||||
action.invoke(room)
|
||||
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
timeline.dispose()
|
||||
|
||||
room.isEncrypted() shouldBe roomShouldBeEncrypted
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
testHelper.waitWithLatch {
|
||||
room.isEncrypted() shouldBe roomShouldBeEncrypted
|
||||
it.countDown()
|
||||
}
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.common.CommonTestHelper
|
||||
import org.matrix.android.sdk.common.CryptoTestHelper
|
||||
import org.matrix.android.sdk.common.SessionTestParams
|
||||
import org.matrix.android.sdk.common.TestConstants
|
||||
import org.matrix.android.sdk.internal.crypto.GossipingRequestState
|
||||
@ -55,7 +54,6 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
|
||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
@ -63,15 +61,14 @@ import kotlin.coroutines.resume
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class KeyShareTests : InstrumentedTest {
|
||||
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
@Test
|
||||
fun test_DoNotSelfShareIfNotTrusted() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
// Create an encrypted room and add a message
|
||||
val roomId = mTestHelper.runBlockingTest {
|
||||
val roomId = commonTestHelper.runBlockingTest {
|
||||
aliceSession.createRoom(
|
||||
CreateRoomParams().apply {
|
||||
visibility = RoomDirectoryVisibility.PRIVATE
|
||||
@ -83,11 +80,11 @@ class KeyShareTests : InstrumentedTest {
|
||||
assertNotNull(room)
|
||||
Thread.sleep(4_000)
|
||||
assertTrue(room?.isEncrypted() == true)
|
||||
val sentEventId = mTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId
|
||||
val sentEventId = commonTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId
|
||||
|
||||
// Open a new sessionx
|
||||
|
||||
val aliceSession2 = mTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
|
||||
val aliceSession2 = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
|
||||
|
||||
val roomSecondSessionPOV = aliceSession2.getRoom(roomId)
|
||||
|
||||
@ -105,25 +102,24 @@ class KeyShareTests : InstrumentedTest {
|
||||
// Try to request
|
||||
aliceSession2.cryptoService().requestRoomKeyForEvent(receivedEvent.root)
|
||||
|
||||
val waitLatch = CountDownLatch(1)
|
||||
val eventMegolmSessionId = receivedEvent.root.content.toModel<EncryptedEventContent>()?.sessionId
|
||||
|
||||
var outGoingRequestId: String? = null
|
||||
|
||||
mTestHelper.retryPeriodicallyWithLatch(waitLatch) {
|
||||
aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
|
||||
.filter { req ->
|
||||
// filter out request that was known before
|
||||
!outgoingRequestsBefore.any { req.requestId == it.requestId }
|
||||
}
|
||||
.let {
|
||||
val outgoing = it.firstOrNull { it.sessionId == eventMegolmSessionId }
|
||||
outGoingRequestId = outgoing?.requestId
|
||||
outgoing != null
|
||||
}
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
|
||||
.filter { req ->
|
||||
// filter out request that was known before
|
||||
!outgoingRequestsBefore.any { req.requestId == it.requestId }
|
||||
}
|
||||
.let {
|
||||
val outgoing = it.firstOrNull { it.sessionId == eventMegolmSessionId }
|
||||
outGoingRequestId = outgoing?.requestId
|
||||
outgoing != null
|
||||
}
|
||||
}
|
||||
}
|
||||
mTestHelper.await(waitLatch)
|
||||
|
||||
Log.v("TEST", "=======> Outgoing requet Id is $outGoingRequestId")
|
||||
|
||||
val outgoingRequestAfter = aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
|
||||
@ -134,8 +130,8 @@ class KeyShareTests : InstrumentedTest {
|
||||
|
||||
// The first session should see an incoming request
|
||||
// the request should be refused, because the device is not trusted
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
// DEBUG LOGS
|
||||
aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
|
||||
Log.v("TEST", "Incoming request Session 1 (looking for $outGoingRequestId)")
|
||||
@ -164,8 +160,8 @@ class KeyShareTests : InstrumentedTest {
|
||||
// Re request
|
||||
aliceSession2.cryptoService().reRequestRoomKeyForEvent(receivedEvent.root)
|
||||
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
|
||||
Log.v("TEST", "Incoming request Session 1")
|
||||
Log.v("TEST", "=========================")
|
||||
@ -180,8 +176,8 @@ class KeyShareTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
Thread.sleep(6_000)
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
aliceSession2.cryptoService().getOutgoingRoomKeyRequests().let {
|
||||
it.any { it.requestBody?.sessionId == eventMegolmSessionId && it.state == OutgoingGossipingRequestState.CANCELLED }
|
||||
}
|
||||
@ -194,15 +190,15 @@ class KeyShareTests : InstrumentedTest {
|
||||
fail("should have been able to decrypt")
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
mTestHelper.signOutAndClose(aliceSession2)
|
||||
commonTestHelper.signOutAndClose(aliceSession)
|
||||
commonTestHelper.signOutAndClose(aliceSession2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_ShareSSSSSecret() {
|
||||
val aliceSession1 = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession1 = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
mTestHelper.doSync<Unit> {
|
||||
commonTestHelper.doSync<Unit> {
|
||||
aliceSession1.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -218,25 +214,25 @@ class KeyShareTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Also bootstrap keybackup on first session
|
||||
val creationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
|
||||
val creationInfo = commonTestHelper.doSync<MegolmBackupCreationInfo> {
|
||||
aliceSession1.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it)
|
||||
}
|
||||
val version = mTestHelper.doSync<KeysVersion> {
|
||||
val version = commonTestHelper.doSync<KeysVersion> {
|
||||
aliceSession1.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it)
|
||||
}
|
||||
// Save it for gossiping
|
||||
aliceSession1.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
|
||||
|
||||
val aliceSession2 = mTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true))
|
||||
val aliceSession2 = commonTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true))
|
||||
|
||||
val aliceVerificationService1 = aliceSession1.cryptoService().verificationService()
|
||||
val aliceVerificationService2 = aliceSession2.cryptoService().verificationService()
|
||||
|
||||
// force keys download
|
||||
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
commonTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
aliceSession1.cryptoService().downloadKeys(listOf(aliceSession1.myUserId), true, it)
|
||||
}
|
||||
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
commonTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
|
||||
aliceSession2.cryptoService().downloadKeys(listOf(aliceSession2.myUserId), true, it)
|
||||
}
|
||||
|
||||
@ -276,8 +272,8 @@ class KeyShareTests : InstrumentedTest {
|
||||
aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.deviceId
|
||||
?: "", txId)
|
||||
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
aliceSession1.cryptoService().getDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.deviceId ?: "")?.isVerified == true
|
||||
}
|
||||
}
|
||||
@ -290,31 +286,31 @@ class KeyShareTests : InstrumentedTest {
|
||||
|
||||
// SSK and USK private keys should have been shared
|
||||
|
||||
mTestHelper.waitWithLatch(60_000) { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
commonTestHelper.waitWithLatch(60_000) { latch ->
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
Log.d("#TEST", "CAN XS :${aliceSession2.cryptoService().crossSigningService().getMyCrossSigningKeys()}")
|
||||
aliceSession2.cryptoService().crossSigningService().canCrossSign()
|
||||
}
|
||||
}
|
||||
|
||||
// Test that key backup key has been shared to
|
||||
mTestHelper.waitWithLatch(60_000) { latch ->
|
||||
commonTestHelper.waitWithLatch(60_000) { latch ->
|
||||
val keysBackupService = aliceSession2.cryptoService().keysBackupService()
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
commonTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
Log.d("#TEST", "Recovery :${keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey}")
|
||||
keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey == creationInfo.recoveryKey
|
||||
}
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession1)
|
||||
mTestHelper.signOutAndClose(aliceSession2)
|
||||
commonTestHelper.signOutAndClose(aliceSession1)
|
||||
commonTestHelper.signOutAndClose(aliceSession2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_ImproperKeyShareBug() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
mTestHelper.doSync<Unit> {
|
||||
commonTestHelper.doSync<Unit> {
|
||||
aliceSession.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -331,7 +327,7 @@ class KeyShareTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Create an encrypted room and send a couple of messages
|
||||
val roomId = mTestHelper.runBlockingTest {
|
||||
val roomId = commonTestHelper.runBlockingTest {
|
||||
aliceSession.createRoom(
|
||||
CreateRoomParams().apply {
|
||||
visibility = RoomDirectoryVisibility.PRIVATE
|
||||
@ -343,12 +339,12 @@ class KeyShareTests : InstrumentedTest {
|
||||
assertNotNull(roomAlicePov)
|
||||
Thread.sleep(1_000)
|
||||
assertTrue(roomAlicePov?.isEncrypted() == true)
|
||||
val secondEventId = mTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId
|
||||
val secondEventId = commonTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId
|
||||
|
||||
// Create bob session
|
||||
|
||||
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
|
||||
mTestHelper.doSync<Unit> {
|
||||
val bobSession = commonTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
|
||||
commonTestHelper.doSync<Unit> {
|
||||
bobSession.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -365,11 +361,11 @@ class KeyShareTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Let alice invite bob
|
||||
mTestHelper.runBlockingTest {
|
||||
commonTestHelper.runBlockingTest {
|
||||
roomAlicePov.invite(bobSession.myUserId, null)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
commonTestHelper.runBlockingTest {
|
||||
bobSession.joinRoom(roomAlicePov.roomId, null, emptyList())
|
||||
}
|
||||
|
||||
@ -377,7 +373,7 @@ class KeyShareTests : InstrumentedTest {
|
||||
aliceSession.cryptoService().discardOutboundSession(roomAlicePov.roomId)
|
||||
|
||||
// and now resend a new message to reset index to 0
|
||||
mTestHelper.sendTextMessage(roomAlicePov, "After", 1)
|
||||
commonTestHelper.sendTextMessage(roomAlicePov, "After", 1)
|
||||
|
||||
val roomRoomBobPov = aliceSession.getRoom(roomId)
|
||||
val beforeJoin = roomRoomBobPov!!.getTimeLineEvent(secondEventId)
|
||||
|
@ -41,8 +41,8 @@ import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class WithHeldTests : InstrumentedTest {
|
||||
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
fun test_WithHeldUnverifiedReason() {
|
||||
@ -50,19 +50,19 @@ class WithHeldTests : InstrumentedTest {
|
||||
// ARRANGE
|
||||
// =============================
|
||||
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
|
||||
|
||||
// Initialize cross signing on both
|
||||
mCryptoTestHelper.initializeCrossSigning(aliceSession)
|
||||
mCryptoTestHelper.initializeCrossSigning(bobSession)
|
||||
cryptoTestHelper.initializeCrossSigning(aliceSession)
|
||||
cryptoTestHelper.initializeCrossSigning(bobSession)
|
||||
|
||||
val roomId = mCryptoTestHelper.createDM(aliceSession, bobSession)
|
||||
mCryptoTestHelper.verifySASCrossSign(aliceSession, bobSession, roomId)
|
||||
val roomId = cryptoTestHelper.createDM(aliceSession, bobSession)
|
||||
cryptoTestHelper.verifySASCrossSign(aliceSession, bobSession, roomId)
|
||||
|
||||
val roomAlicePOV = aliceSession.getRoom(roomId)!!
|
||||
|
||||
val bobUnverifiedSession = mTestHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(true))
|
||||
val bobUnverifiedSession = testHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(true))
|
||||
|
||||
// =============================
|
||||
// ACT
|
||||
@ -71,11 +71,11 @@ class WithHeldTests : InstrumentedTest {
|
||||
// Alice decide to not send to unverified sessions
|
||||
aliceSession.cryptoService().setGlobalBlacklistUnverifiedDevices(true)
|
||||
|
||||
val timelineEvent = mTestHelper.sendTextMessage(roomAlicePOV, "Hello Bob", 1).first()
|
||||
val timelineEvent = testHelper.sendTextMessage(roomAlicePOV, "Hello Bob", 1).first()
|
||||
|
||||
// await for bob unverified session to get the message
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
bobUnverifiedSession.getRoom(roomId)?.getTimeLineEvent(timelineEvent.eventId) != null
|
||||
}
|
||||
}
|
||||
@ -101,10 +101,10 @@ class WithHeldTests : InstrumentedTest {
|
||||
// enable back sending to unverified
|
||||
aliceSession.cryptoService().setGlobalBlacklistUnverifiedDevices(false)
|
||||
|
||||
val secondEvent = mTestHelper.sendTextMessage(roomAlicePOV, "Verify your device!!", 1).first()
|
||||
val secondEvent = testHelper.sendTextMessage(roomAlicePOV, "Verify your device!!", 1).first()
|
||||
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val ev = bobUnverifiedSession.getRoom(roomId)?.getTimeLineEvent(secondEvent.eventId)
|
||||
// wait until it's decrypted
|
||||
ev?.root?.getClearType() == EventType.MESSAGE
|
||||
@ -123,17 +123,17 @@ class WithHeldTests : InstrumentedTest {
|
||||
Assert.assertEquals("Cause should be unverified", WithHeldCode.UNVERIFIED.value, technicalMessage)
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
mTestHelper.signOutAndClose(bobUnverifiedSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(bobUnverifiedSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_WithHeldNoOlm() {
|
||||
val testData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val aliceSession = testData.firstSession
|
||||
val bobSession = testData.secondSession!!
|
||||
val aliceInterceptor = mTestHelper.getTestInterceptor(aliceSession)
|
||||
val aliceInterceptor = testHelper.getTestInterceptor(aliceSession)
|
||||
|
||||
// Simulate no OTK
|
||||
aliceInterceptor!!.addRule(MockOkHttpInterceptor.SimpleRule(
|
||||
@ -147,11 +147,11 @@ class WithHeldTests : InstrumentedTest {
|
||||
|
||||
val roomAlicePov = aliceSession.getRoom(testData.roomId)!!
|
||||
|
||||
val eventId = mTestHelper.sendTextMessage(roomAlicePov, "first message", 1).first().eventId
|
||||
val eventId = testHelper.sendTextMessage(roomAlicePov, "first message", 1).first().eventId
|
||||
|
||||
// await for bob session to get the message
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
bobSession.getRoom(testData.roomId)?.getTimeLineEvent(eventId) != null
|
||||
}
|
||||
}
|
||||
@ -177,14 +177,14 @@ class WithHeldTests : InstrumentedTest {
|
||||
// Add a new device for bob
|
||||
|
||||
aliceInterceptor.clearRules()
|
||||
val bobSecondSession = mTestHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(withInitialSync = true))
|
||||
val bobSecondSession = testHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(withInitialSync = true))
|
||||
// send a second message
|
||||
val secondMessageId = mTestHelper.sendTextMessage(roomAlicePov, "second message", 1).first().eventId
|
||||
val secondMessageId = testHelper.sendTextMessage(roomAlicePov, "second message", 1).first().eventId
|
||||
|
||||
// Check that the
|
||||
// await for bob SecondSession session to get the message
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
bobSecondSession.getRoom(testData.roomId)?.getTimeLineEvent(secondMessageId) != null
|
||||
}
|
||||
}
|
||||
@ -194,27 +194,27 @@ class WithHeldTests : InstrumentedTest {
|
||||
Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2)
|
||||
|
||||
aliceInterceptor.clearRules()
|
||||
testData.cleanUp(mTestHelper)
|
||||
mTestHelper.signOutAndClose(bobSecondSession)
|
||||
testData.cleanUp(testHelper)
|
||||
testHelper.signOutAndClose(bobSecondSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_WithHeldKeyRequest() {
|
||||
val testData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val aliceSession = testData.firstSession
|
||||
val bobSession = testData.secondSession!!
|
||||
|
||||
val roomAlicePov = aliceSession.getRoom(testData.roomId)!!
|
||||
|
||||
val eventId = mTestHelper.sendTextMessage(roomAlicePov, "first message", 1).first().eventId
|
||||
val eventId = testHelper.sendTextMessage(roomAlicePov, "first message", 1).first().eventId
|
||||
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
|
||||
// Create a new session for bob
|
||||
|
||||
val bobSecondSession = mTestHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(true))
|
||||
val bobSecondSession = testHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(true))
|
||||
// initialize to force request keys if missing
|
||||
mCryptoTestHelper.initializeCrossSigning(bobSecondSession)
|
||||
cryptoTestHelper.initializeCrossSigning(bobSecondSession)
|
||||
|
||||
// Trust bob second device from Alice POV
|
||||
aliceSession.cryptoService().crossSigningService().trustDevice(bobSecondSession.sessionParams.deviceId!!, NoOpMatrixCallback())
|
||||
@ -223,8 +223,8 @@ class WithHeldTests : InstrumentedTest {
|
||||
var sessionId: String? = null
|
||||
// Check that the
|
||||
// await for bob SecondSession session to get the message
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val timeLineEvent = bobSecondSession.getRoom(testData.roomId)?.getTimeLineEvent(eventId)?.also {
|
||||
// try to decrypt and force key request
|
||||
tryOrNull { bobSecondSession.cryptoService().decryptEvent(it.root, "") }
|
||||
@ -235,8 +235,8 @@ class WithHeldTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Check that bob second session requested the key
|
||||
mTestHelper.waitWithLatch { latch ->
|
||||
mTestHelper.retryPeriodicallyWithLatch(latch) {
|
||||
testHelper.waitWithLatch { latch ->
|
||||
testHelper.retryPeriodicallyWithLatch(latch) {
|
||||
val wc = bobSecondSession.cryptoService().getWithHeldMegolmSession(roomAlicePov.roomId, sessionId!!)
|
||||
wc?.code == WithHeldCode.UNAUTHORISED
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@ -43,7 +42,6 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreat
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
|
||||
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@ -51,9 +49,9 @@ import java.util.concurrent.CountDownLatch
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val mKeysBackupTestHelper = KeysBackupTestHelper(mTestHelper, mCryptoTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
private val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
|
||||
|
||||
/**
|
||||
* - From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys
|
||||
@ -62,7 +60,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun roomKeysTest_testBackupStore_ok() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
// From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys
|
||||
val cryptoStore = (cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService).store
|
||||
@ -92,7 +90,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(sessionsCount, cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(false))
|
||||
assertEquals(0, cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(true))
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,7 +98,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun prepareKeysBackupVersionTest() {
|
||||
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
|
||||
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
|
||||
|
||||
assertNotNull(bobSession.cryptoService().keysBackupService())
|
||||
|
||||
@ -110,7 +108,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
|
||||
val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
|
||||
keysBackup.prepareKeysBackupVersion(null, null, it)
|
||||
}
|
||||
|
||||
@ -120,7 +118,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertNotNull(megolmBackupCreationInfo.recoveryKey)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,7 +126,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun createKeysBackupVersionTest() {
|
||||
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
|
||||
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
|
||||
|
||||
val keysBackup = bobSession.cryptoService().keysBackupService()
|
||||
|
||||
@ -136,14 +134,14 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
|
||||
val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
|
||||
keysBackup.prepareKeysBackupVersion(null, null, it)
|
||||
}
|
||||
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
// Create the version
|
||||
mTestHelper.doSync<KeysVersion> {
|
||||
testHelper.doSync<KeysVersion> {
|
||||
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
|
||||
}
|
||||
|
||||
@ -151,7 +149,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertTrue(keysBackup.isEnabled)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
mTestHelper.signOutAndClose(bobSession)
|
||||
testHelper.signOutAndClose(bobSession)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,8 +158,9 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun backupAfterCreateKeysBackupVersionTest() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
keysBackupTestHelper.waitForKeybackUpBatching()
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
val latch = CountDownLatch(1)
|
||||
@ -171,9 +170,9 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
val stateObserver = StateObserver(keysBackup, latch, 5)
|
||||
|
||||
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
|
||||
val nbOfKeys = cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(false)
|
||||
val backedUpKeys = cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(true)
|
||||
@ -191,7 +190,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
KeysBackupState.ReadyToBackUp
|
||||
)
|
||||
)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,13 +198,13 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun backupAllGroupSessionsTest() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
val stateObserver = StateObserver(keysBackup)
|
||||
|
||||
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
// Check that backupAllGroupSessions returns valid data
|
||||
val nbOfKeys = cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(false)
|
||||
@ -214,7 +213,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
var lastBackedUpKeysProgress = 0
|
||||
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
keysBackup.backupAllGroupSessions(object : ProgressListener {
|
||||
override fun onProgress(progress: Int, total: Int) {
|
||||
assertEquals(nbOfKeys, total)
|
||||
@ -230,7 +229,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals("All keys must have been marked as backed up", nbOfKeys, backedUpKeys)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,7 +242,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun testEncryptAndDecryptKeysBackupData() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService
|
||||
|
||||
@ -252,7 +251,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
// - Pick a megolm key
|
||||
val session = keysBackup.store.inboundGroupSessionsToBackup(1)[0]
|
||||
|
||||
val keyBackupCreationInfo = mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup).megolmBackupCreationInfo
|
||||
val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup).megolmBackupCreationInfo
|
||||
|
||||
// - Check encryptGroupSession() returns stg
|
||||
val keyBackupData = keysBackup.encryptGroupSession(session)
|
||||
@ -270,10 +269,10 @@ class KeysBackupTest : InstrumentedTest {
|
||||
decryption!!)
|
||||
assertNotNull(sessionData)
|
||||
// - Compare the decrypted megolm key with the original one
|
||||
mKeysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)
|
||||
keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -284,10 +283,10 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun restoreKeysBackupTest() {
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
// - Restore the e2e backup from the homeserver
|
||||
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
|
||||
val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
|
||||
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
|
||||
null,
|
||||
@ -297,9 +296,9 @@ class KeysBackupTest : InstrumentedTest {
|
||||
)
|
||||
}
|
||||
|
||||
mKeysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
|
||||
keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
|
||||
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -369,7 +368,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
fun trustKeyBackupVersionTest() {
|
||||
// - Do an e2e backup to the homeserver with a recovery key
|
||||
// - And log Alice on a new device
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
val stateObserver = StateObserver(testData.aliceSession2.cryptoService().keysBackupService())
|
||||
|
||||
@ -379,7 +378,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
|
||||
|
||||
// - Trust the backup from the new device
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersion(
|
||||
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
|
||||
true,
|
||||
@ -388,21 +387,21 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Wait for backup state to be ReadyToBackUp
|
||||
mKeysBackupTestHelper.waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
|
||||
keysBackupTestHelper.waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
|
||||
|
||||
// - Backup must be enabled on the new device, on the same version
|
||||
assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
|
||||
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
|
||||
|
||||
// - Retrieve the last version from the server
|
||||
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
|
||||
val keysVersionResult = testHelper.doSync<KeysVersionResult?> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
|
||||
}
|
||||
|
||||
// - It must be the same
|
||||
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
|
||||
|
||||
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
|
||||
val keysBackupVersionTrust = testHelper.doSync<KeysBackupVersionTrust> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
|
||||
}
|
||||
|
||||
@ -411,7 +410,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(2, keysBackupVersionTrust.signatures.size)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -428,7 +427,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
fun trustKeyBackupVersionWithRecoveryKeyTest() {
|
||||
// - Do an e2e backup to the homeserver with a recovery key
|
||||
// - And log Alice on a new device
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
val stateObserver = StateObserver(testData.aliceSession2.cryptoService().keysBackupService())
|
||||
|
||||
@ -438,7 +437,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
|
||||
|
||||
// - Trust the backup from the new device with the recovery key
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithRecoveryKey(
|
||||
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
|
||||
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
|
||||
@ -447,21 +446,21 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Wait for backup state to be ReadyToBackUp
|
||||
mKeysBackupTestHelper.waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
|
||||
keysBackupTestHelper.waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
|
||||
|
||||
// - Backup must be enabled on the new device, on the same version
|
||||
assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
|
||||
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
|
||||
|
||||
// - Retrieve the last version from the server
|
||||
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
|
||||
val keysVersionResult = testHelper.doSync<KeysVersionResult?> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
|
||||
}
|
||||
|
||||
// - It must be the same
|
||||
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
|
||||
|
||||
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
|
||||
val keysBackupVersionTrust = testHelper.doSync<KeysBackupVersionTrust> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
|
||||
}
|
||||
|
||||
@ -470,7 +469,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(2, keysBackupVersionTrust.signatures.size)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -485,7 +484,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
fun trustKeyBackupVersionWithWrongRecoveryKeyTest() {
|
||||
// - Do an e2e backup to the homeserver with a recovery key
|
||||
// - And log Alice on a new device
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
val stateObserver = StateObserver(testData.aliceSession2.cryptoService().keysBackupService())
|
||||
|
||||
@ -501,7 +500,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
"Bad recovery key",
|
||||
TestMatrixCallback(latch, false)
|
||||
)
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
|
||||
// - The new device must still see the previous backup as not trusted
|
||||
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
|
||||
@ -509,7 +508,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -528,7 +527,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
// - Do an e2e backup to the homeserver with a password
|
||||
// - And log Alice on a new device
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
|
||||
val stateObserver = StateObserver(testData.aliceSession2.cryptoService().keysBackupService())
|
||||
|
||||
@ -538,7 +537,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
|
||||
|
||||
// - Trust the backup from the new device with the password
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithPassphrase(
|
||||
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
|
||||
password,
|
||||
@ -547,21 +546,21 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
// Wait for backup state to be ReadyToBackUp
|
||||
mKeysBackupTestHelper.waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
|
||||
keysBackupTestHelper.waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
|
||||
|
||||
// - Backup must be enabled on the new device, on the same version
|
||||
assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
|
||||
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
|
||||
|
||||
// - Retrieve the last version from the server
|
||||
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
|
||||
val keysVersionResult = testHelper.doSync<KeysVersionResult?> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
|
||||
}
|
||||
|
||||
// - It must be the same
|
||||
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
|
||||
|
||||
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
|
||||
val keysBackupVersionTrust = testHelper.doSync<KeysBackupVersionTrust> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
|
||||
}
|
||||
|
||||
@ -570,7 +569,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(2, keysBackupVersionTrust.signatures.size)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -588,7 +587,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
// - Do an e2e backup to the homeserver with a password
|
||||
// - And log Alice on a new device
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
|
||||
val stateObserver = StateObserver(testData.aliceSession2.cryptoService().keysBackupService())
|
||||
|
||||
@ -604,7 +603,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
badPassword,
|
||||
TestMatrixCallback(latch, false)
|
||||
)
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
|
||||
// - The new device must still see the previous backup as not trusted
|
||||
assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
|
||||
@ -612,7 +611,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -623,7 +622,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun restoreKeysBackupWithAWrongRecoveryKeyTest() {
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
// - Try to restore the e2e backup with a wrong recovery key
|
||||
val latch2 = CountDownLatch(1)
|
||||
@ -640,12 +639,12 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
}
|
||||
)
|
||||
mTestHelper.await(latch2)
|
||||
testHelper.await(latch2)
|
||||
|
||||
// onSuccess may not have been called
|
||||
assertNull(importRoomKeysResult)
|
||||
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -658,12 +657,12 @@ class KeysBackupTest : InstrumentedTest {
|
||||
fun testBackupWithPassword() {
|
||||
val password = "password"
|
||||
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
|
||||
// - Restore the e2e backup with the password
|
||||
val steps = ArrayList<StepProgressListener.Step>()
|
||||
|
||||
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
|
||||
val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
|
||||
password,
|
||||
null,
|
||||
@ -698,9 +697,9 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(50, (steps[103] as StepProgressListener.Step.ImportingKey).progress)
|
||||
assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress)
|
||||
|
||||
mKeysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
|
||||
keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
|
||||
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -714,7 +713,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
val password = "password"
|
||||
val wrongPassword = "passw0rd"
|
||||
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
|
||||
// - Try to restore the e2e backup with a wrong password
|
||||
val latch2 = CountDownLatch(1)
|
||||
@ -731,12 +730,12 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
}
|
||||
)
|
||||
mTestHelper.await(latch2)
|
||||
testHelper.await(latch2)
|
||||
|
||||
// onSuccess may not have been called
|
||||
assertNull(importRoomKeysResult)
|
||||
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -749,10 +748,10 @@ class KeysBackupTest : InstrumentedTest {
|
||||
fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() {
|
||||
val password = "password"
|
||||
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||
|
||||
// - Restore the e2e backup with the recovery key.
|
||||
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
|
||||
val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
|
||||
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
|
||||
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
|
||||
null,
|
||||
@ -762,9 +761,9 @@ class KeysBackupTest : InstrumentedTest {
|
||||
)
|
||||
}
|
||||
|
||||
mKeysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
|
||||
keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
|
||||
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,7 +774,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() {
|
||||
val testData = mKeysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
|
||||
|
||||
// - Try to restore the e2e backup with a password
|
||||
val latch2 = CountDownLatch(1)
|
||||
@ -792,12 +791,12 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
}
|
||||
)
|
||||
mTestHelper.await(latch2)
|
||||
testHelper.await(latch2)
|
||||
|
||||
// onSuccess may not have been called
|
||||
assertNull(importRoomKeysResult)
|
||||
|
||||
testData.cleanUp(mTestHelper)
|
||||
testData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -807,22 +806,22 @@ class KeysBackupTest : InstrumentedTest {
|
||||
@Test
|
||||
fun testIsKeysBackupTrusted() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
val stateObserver = StateObserver(keysBackup)
|
||||
|
||||
// - Do an e2e backup to the homeserver
|
||||
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
// Get key backup version from the homeserver
|
||||
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
|
||||
val keysVersionResult = testHelper.doSync<KeysVersionResult?> {
|
||||
keysBackup.getCurrentVersion(it)
|
||||
}
|
||||
|
||||
// - Check the returned KeyBackupVersion is trusted
|
||||
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
|
||||
val keysBackupVersionTrust = testHelper.doSync<KeysBackupVersionTrust> {
|
||||
keysBackup.getKeysBackupTrust(keysVersionResult!!, it)
|
||||
}
|
||||
|
||||
@ -837,7 +836,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
assertEquals(signature.device!!.deviceId, cryptoTestData.firstSession.sessionParams.deviceId)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -849,9 +848,8 @@ class KeysBackupTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun testCheckAndStartKeysBackupWhenRestartingAMatrixSession() {
|
||||
fail("This test still fail. To investigate")
|
||||
// - Create a backup version
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
@ -859,15 +857,15 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
val keyBackupCreationInfo = mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
assertTrue(keysBackup.isEnabled)
|
||||
|
||||
// - Restart alice session
|
||||
// - Log Alice on a new device
|
||||
val aliceSession2 = mTestHelper.logIntoAccount(cryptoTestData.firstSession.myUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
|
||||
val aliceSession2 = testHelper.logIntoAccount(cryptoTestData.firstSession.myUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
|
||||
val keysBackup2 = aliceSession2.cryptoService().keysBackupService()
|
||||
|
||||
@ -891,13 +889,13 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
}
|
||||
})
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
|
||||
assertEquals(keyBackupCreationInfo.version, keysBackup2.currentBackupVersion)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
stateObserver2.stopAndCheckStates(null)
|
||||
mTestHelper.signOutAndClose(aliceSession2)
|
||||
testHelper.signOutAndClose(aliceSession2)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -911,7 +909,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
@Test
|
||||
fun testBackupWhenAnotherBackupWasCreated() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
@ -939,15 +937,15 @@ class KeysBackupTest : InstrumentedTest {
|
||||
})
|
||||
|
||||
// - Make alice back up her keys to her homeserver
|
||||
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
assertTrue(keysBackup.isEnabled)
|
||||
|
||||
mTestHelper.await(latch0)
|
||||
testHelper.await(latch0)
|
||||
|
||||
// - Create a new backup with fake data on the homeserver, directly using the rest client
|
||||
val megolmBackupCreationInfo = mCryptoTestHelper.createFakeMegolmBackupCreationInfo()
|
||||
mTestHelper.doSync<KeysVersion> {
|
||||
val megolmBackupCreationInfo = cryptoTestHelper.createFakeMegolmBackupCreationInfo()
|
||||
testHelper.doSync<KeysVersion> {
|
||||
(keysBackup as DefaultKeysBackupService).createFakeKeysBackupVersion(megolmBackupCreationInfo, it)
|
||||
}
|
||||
|
||||
@ -957,14 +955,14 @@ class KeysBackupTest : InstrumentedTest {
|
||||
// - Make alice back up all her keys again
|
||||
val latch2 = CountDownLatch(1)
|
||||
keysBackup.backupAllGroupSessions(null, TestMatrixCallback(latch2, false))
|
||||
mTestHelper.await(latch2)
|
||||
testHelper.await(latch2)
|
||||
|
||||
// -> That must fail and her backup state must be WrongBackUpVersion
|
||||
assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.state)
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -982,17 +980,17 @@ class KeysBackupTest : InstrumentedTest {
|
||||
@Test
|
||||
fun testBackupAfterVerifyingADevice() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
val stateObserver = StateObserver(keysBackup)
|
||||
|
||||
// - Make alice back up her keys to her homeserver
|
||||
mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
// Wait for keys backup to finish by asking again to backup keys.
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
keysBackup.backupAllGroupSessions(null, it)
|
||||
}
|
||||
|
||||
@ -1001,14 +999,14 @@ class KeysBackupTest : InstrumentedTest {
|
||||
val aliceUserId = cryptoTestData.firstSession.myUserId
|
||||
|
||||
// - Log Alice on a new device
|
||||
val aliceSession2 = mTestHelper.logIntoAccount(aliceUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
|
||||
val aliceSession2 = testHelper.logIntoAccount(aliceUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
|
||||
|
||||
// - Post a message to have a new megolm session
|
||||
aliceSession2.cryptoService().setWarnOnUnknownDevices(false)
|
||||
|
||||
val room2 = aliceSession2.getRoom(cryptoTestData.roomId)!!
|
||||
|
||||
mTestHelper.sendTextMessage(room2, "New key", 1)
|
||||
testHelper.sendTextMessage(room2, "New key", 1)
|
||||
|
||||
// - Try to backup all in aliceSession2, it must fail
|
||||
val keysBackup2 = aliceSession2.cryptoService().keysBackupService()
|
||||
@ -1025,7 +1023,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
super.onSuccess(data)
|
||||
}
|
||||
})
|
||||
mTestHelper.await(latch2)
|
||||
testHelper.await(latch2)
|
||||
|
||||
assertFalse(isSuccessful)
|
||||
|
||||
@ -1049,12 +1047,12 @@ class KeysBackupTest : InstrumentedTest {
|
||||
}
|
||||
}
|
||||
})
|
||||
mTestHelper.await(latch4)
|
||||
testHelper.await(latch4)
|
||||
|
||||
// -> It must use the same backup version
|
||||
assertEquals(oldKeyBackupVersion, aliceSession2.cryptoService().keysBackupService().currentBackupVersion)
|
||||
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
aliceSession2.cryptoService().keysBackupService().backupAllGroupSessions(null, it)
|
||||
}
|
||||
|
||||
@ -1063,8 +1061,8 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
stateObserver2.stopAndCheckStates(null)
|
||||
mTestHelper.signOutAndClose(aliceSession2)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
testHelper.signOutAndClose(aliceSession2)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1074,7 +1072,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||
@Test
|
||||
fun deleteKeysBackupTest() {
|
||||
// - Create a backup version
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
|
||||
@ -1082,17 +1080,17 @@ class KeysBackupTest : InstrumentedTest {
|
||||
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
val keyBackupCreationInfo = mKeysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
|
||||
|
||||
assertTrue(keysBackup.isEnabled)
|
||||
|
||||
// Delete the backup
|
||||
mTestHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) }
|
||||
testHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) }
|
||||
|
||||
// Backup is now disabled
|
||||
assertFalse(keysBackup.isEnabled)
|
||||
|
||||
stateObserver.stopAndCheckStates(null)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,12 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
class KeysBackupTestHelper(
|
||||
private val mTestHelper: CommonTestHelper,
|
||||
private val mCryptoTestHelper: CryptoTestHelper) {
|
||||
private val testHelper: CommonTestHelper,
|
||||
private val cryptoTestHelper: CryptoTestHelper) {
|
||||
|
||||
fun waitForKeybackUpBatching() {
|
||||
Thread.sleep(400)
|
||||
}
|
||||
|
||||
/**
|
||||
* Common initial condition
|
||||
@ -43,7 +47,9 @@ class KeysBackupTestHelper(
|
||||
* @param password optional password
|
||||
*/
|
||||
fun createKeysBackupScenarioWithPassword(password: String?): KeysBackupScenarioData {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
|
||||
|
||||
waitForKeybackUpBatching()
|
||||
|
||||
val cryptoStore = (cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService).store
|
||||
val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
|
||||
@ -57,7 +63,7 @@ class KeysBackupTestHelper(
|
||||
|
||||
var lastProgress = 0
|
||||
var lastTotal = 0
|
||||
mTestHelper.doSync<Unit> {
|
||||
testHelper.doSync<Unit> {
|
||||
keysBackup.backupAllGroupSessions(object : ProgressListener {
|
||||
override fun onProgress(progress: Int, total: Int) {
|
||||
lastProgress = progress
|
||||
@ -72,7 +78,7 @@ class KeysBackupTestHelper(
|
||||
val aliceUserId = cryptoTestData.firstSession.myUserId
|
||||
|
||||
// - Log Alice on a new device
|
||||
val aliceSession2 = mTestHelper.logIntoAccount(aliceUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
|
||||
val aliceSession2 = testHelper.logIntoAccount(aliceUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
|
||||
|
||||
// Test check: aliceSession2 has no keys at login
|
||||
Assert.assertEquals(0, aliceSession2.cryptoService().inboundGroupSessionsCount(false))
|
||||
@ -92,7 +98,7 @@ class KeysBackupTestHelper(
|
||||
password: String? = null): PrepareKeysBackupDataResult {
|
||||
val stateObserver = StateObserver(keysBackup)
|
||||
|
||||
val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
|
||||
val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
|
||||
keysBackup.prepareKeysBackupVersion(password, null, it)
|
||||
}
|
||||
|
||||
@ -101,7 +107,7 @@ class KeysBackupTestHelper(
|
||||
Assert.assertFalse(keysBackup.isEnabled)
|
||||
|
||||
// Create the version
|
||||
val keysVersion = mTestHelper.doSync<KeysVersion> {
|
||||
val keysVersion = testHelper.doSync<KeysVersion> {
|
||||
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
|
||||
}
|
||||
|
||||
@ -136,7 +142,7 @@ class KeysBackupTestHelper(
|
||||
}
|
||||
})
|
||||
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
}
|
||||
|
||||
fun assertKeysEquals(keys1: MegolmSessionData?, keys2: MegolmSessionData?) {
|
||||
|
@ -18,10 +18,6 @@ package org.matrix.android.sdk.internal.crypto.ssss
|
||||
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
@ -36,6 +32,7 @@ import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent
|
||||
import org.matrix.android.sdk.api.session.securestorage.KeySigner
|
||||
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
|
||||
import org.matrix.android.sdk.api.session.securestorage.SecretStorageKeyContent
|
||||
import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageError
|
||||
import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
|
||||
import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
@ -45,13 +42,12 @@ import org.matrix.android.sdk.common.TestConstants
|
||||
import org.matrix.android.sdk.internal.crypto.SSSS_ALGORITHM_AES_HMAC_SHA2
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
|
||||
import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorageService
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class QuadSTests : InstrumentedTest {
|
||||
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
|
||||
private val emptyKeySigner = object : KeySigner {
|
||||
override fun sign(canonicalJson: String): Map<String, Map<String, String>>? {
|
||||
@ -60,35 +56,29 @@ class QuadSTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun test_Generate4SKey() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
val quadS = aliceSession.sharedSecretStorageService
|
||||
|
||||
val TEST_KEY_ID = "my.test.Key"
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
quadS.generateKey(TEST_KEY_ID, null, "Test Key", emptyKeySigner)
|
||||
}
|
||||
|
||||
// Assert Account data is updated
|
||||
val accountDataLock = CountDownLatch(1)
|
||||
var accountData: UserAccountDataEvent? = null
|
||||
|
||||
val liveAccountData = runBlocking(Dispatchers.Main) {
|
||||
aliceSession.accountDataService().getLiveUserAccountDataEvent("${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID")
|
||||
}
|
||||
val accountDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
|
||||
if (t?.getOrNull()?.type == "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID") {
|
||||
accountData = t.getOrNull()
|
||||
accountDataLock.countDown()
|
||||
// Assert Account data is updated
|
||||
testHelper.waitWithLatch {
|
||||
val liveAccountData = aliceSession.accountDataService().getLiveUserAccountDataEvent("${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID")
|
||||
val accountDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
|
||||
if (t?.getOrNull()?.type == "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$TEST_KEY_ID") {
|
||||
accountData = t.getOrNull()
|
||||
}
|
||||
it.countDown()
|
||||
}
|
||||
liveAccountData.observeForever(accountDataObserver)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.Main) { liveAccountData.observeForever(accountDataObserver) }
|
||||
|
||||
mTestHelper.await(accountDataLock)
|
||||
|
||||
assertNotNull("Key should be stored in account data", accountData)
|
||||
val parsed = SecretStorageKeyContent.fromJson(accountData!!.content)
|
||||
assertNotNull("Key Content cannot be parsed", parsed)
|
||||
@ -96,36 +86,29 @@ class QuadSTests : InstrumentedTest {
|
||||
assertEquals("Unexpected key name", "Test Key", parsed.name)
|
||||
assertNull("Key was not generated from passphrase", parsed.passphrase)
|
||||
|
||||
// Set as default key
|
||||
GlobalScope.launch {
|
||||
quadS.setDefaultKey(TEST_KEY_ID)
|
||||
}
|
||||
|
||||
var defaultKeyAccountData: UserAccountDataEvent? = null
|
||||
val defaultDataLock = CountDownLatch(1)
|
||||
|
||||
val liveDefAccountData = runBlocking(Dispatchers.Main) {
|
||||
aliceSession.accountDataService().getLiveUserAccountDataEvent(DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
|
||||
}
|
||||
val accountDefDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
|
||||
if (t?.getOrNull()?.type == DefaultSharedSecretStorageService.DEFAULT_KEY_ID) {
|
||||
defaultKeyAccountData = t.getOrNull()!!
|
||||
defaultDataLock.countDown()
|
||||
// Set as default key
|
||||
testHelper.waitWithLatch { latch ->
|
||||
quadS.setDefaultKey(TEST_KEY_ID)
|
||||
val liveDefAccountData =
|
||||
aliceSession.accountDataService().getLiveUserAccountDataEvent(DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
|
||||
val accountDefDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
|
||||
if (t?.getOrNull()?.type == DefaultSharedSecretStorageService.DEFAULT_KEY_ID) {
|
||||
defaultKeyAccountData = t.getOrNull()!!
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
liveDefAccountData.observeForever(accountDefDataObserver)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.Main) { liveDefAccountData.observeForever(accountDefDataObserver) }
|
||||
|
||||
mTestHelper.await(defaultDataLock)
|
||||
|
||||
assertNotNull(defaultKeyAccountData?.content)
|
||||
assertEquals("Unexpected default key ${defaultKeyAccountData?.content}", TEST_KEY_ID, defaultKeyAccountData?.content?.get("key"))
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_StoreSecret() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val keyId = "My.Key"
|
||||
val info = generatedSecret(aliceSession, keyId, true)
|
||||
|
||||
@ -133,7 +116,7 @@ class QuadSTests : InstrumentedTest {
|
||||
|
||||
// Store a secret
|
||||
val clearSecret = "42".toByteArray().toBase64NoPadding()
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.storeSecret(
|
||||
"secret.of.life",
|
||||
clearSecret,
|
||||
@ -154,7 +137,7 @@ class QuadSTests : InstrumentedTest {
|
||||
|
||||
// Try to decrypt??
|
||||
|
||||
val decryptedSecret = mTestHelper.runBlockingTest {
|
||||
val decryptedSecret = testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.getSecret(
|
||||
"secret.of.life",
|
||||
null, // default key
|
||||
@ -163,32 +146,32 @@ class QuadSTests : InstrumentedTest {
|
||||
}
|
||||
|
||||
assertEquals("Secret mismatch", clearSecret, decryptedSecret)
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_SetDefaultLocalEcho() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
|
||||
val quadS = aliceSession.sharedSecretStorageService
|
||||
|
||||
val TEST_KEY_ID = "my.test.Key"
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
quadS.generateKey(TEST_KEY_ID, null, "Test Key", emptyKeySigner)
|
||||
}
|
||||
|
||||
// Test that we don't need to wait for an account data sync to access directly the keyid from DB
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
quadS.setDefaultKey(TEST_KEY_ID)
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_StoreSecretWithMultipleKey() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val keyId1 = "Key.1"
|
||||
val key1Info = generatedSecret(aliceSession, keyId1, true)
|
||||
val keyId2 = "Key2"
|
||||
@ -196,7 +179,7 @@ class QuadSTests : InstrumentedTest {
|
||||
|
||||
val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.storeSecret(
|
||||
"my.secret",
|
||||
mySecretText.toByteArray().toBase64NoPadding(),
|
||||
@ -216,33 +199,33 @@ class QuadSTests : InstrumentedTest {
|
||||
assertNotNull(encryptedContent?.get(keyId2))
|
||||
|
||||
// Assert that can decrypt with both keys
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.getSecret("my.secret",
|
||||
keyId1,
|
||||
RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)!!
|
||||
)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.getSecret("my.secret",
|
||||
keyId2,
|
||||
RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!!
|
||||
)
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_GetSecretWithBadPassphrase() {
|
||||
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
|
||||
val keyId1 = "Key.1"
|
||||
val passphrase = "The good pass phrase"
|
||||
val key1Info = generatedSecretFromPassphrase(aliceSession, passphrase, keyId1, true)
|
||||
|
||||
val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.storeSecret(
|
||||
"my.secret",
|
||||
mySecretText.toByteArray().toBase64NoPadding(),
|
||||
@ -250,19 +233,23 @@ class QuadSTests : InstrumentedTest {
|
||||
)
|
||||
}
|
||||
|
||||
mTestHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.getSecret("my.secret",
|
||||
keyId1,
|
||||
RawBytesKeySpec.fromPassphrase(
|
||||
"A bad passphrase",
|
||||
key1Info.content?.passphrase?.salt ?: "",
|
||||
key1Info.content?.passphrase?.iterations ?: 0,
|
||||
null)
|
||||
)
|
||||
testHelper.runBlockingTest {
|
||||
try {
|
||||
aliceSession.sharedSecretStorageService.getSecret("my.secret",
|
||||
keyId1,
|
||||
RawBytesKeySpec.fromPassphrase(
|
||||
"A bad passphrase",
|
||||
key1Info.content?.passphrase?.salt ?: "",
|
||||
key1Info.content?.passphrase?.iterations ?: 0,
|
||||
null)
|
||||
)
|
||||
} catch (throwable: Throwable) {
|
||||
assert(throwable is SharedSecretStorageError.BadMac)
|
||||
}
|
||||
}
|
||||
|
||||
// Now try with correct key
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
aliceSession.sharedSecretStorageService.getSecret("my.secret",
|
||||
keyId1,
|
||||
RawBytesKeySpec.fromPassphrase(
|
||||
@ -273,42 +260,36 @@ class QuadSTests : InstrumentedTest {
|
||||
)
|
||||
}
|
||||
|
||||
mTestHelper.signOutAndClose(aliceSession)
|
||||
testHelper.signOutAndClose(aliceSession)
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
private fun assertAccountData(session: Session, type: String): UserAccountDataEvent {
|
||||
val accountDataLock = CountDownLatch(1)
|
||||
var accountData: UserAccountDataEvent? = null
|
||||
|
||||
val liveAccountData = runBlocking(Dispatchers.Main) {
|
||||
session.accountDataService().getLiveUserAccountDataEvent(type)
|
||||
}
|
||||
val accountDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
|
||||
if (t?.getOrNull()?.type == type) {
|
||||
accountData = t.getOrNull()
|
||||
accountDataLock.countDown()
|
||||
testHelper.waitWithLatch {
|
||||
val liveAccountData = session.accountDataService().getLiveUserAccountDataEvent(type)
|
||||
val accountDataObserver = Observer<Optional<UserAccountDataEvent>?> { t ->
|
||||
if (t?.getOrNull()?.type == type) {
|
||||
accountData = t.getOrNull()
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
liveAccountData.observeForever(accountDataObserver)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.Main) { liveAccountData.observeForever(accountDataObserver) }
|
||||
mTestHelper.await(accountDataLock)
|
||||
|
||||
assertNotNull("Account Data type:$type should be found", accountData)
|
||||
|
||||
return accountData!!
|
||||
}
|
||||
|
||||
private fun generatedSecret(session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
|
||||
val quadS = session.sharedSecretStorageService
|
||||
|
||||
val creationInfo = mTestHelper.runBlockingTest {
|
||||
val creationInfo = testHelper.runBlockingTest {
|
||||
quadS.generateKey(keyId, null, keyId, emptyKeySigner)
|
||||
}
|
||||
|
||||
assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
|
||||
|
||||
if (asDefault) {
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
quadS.setDefaultKey(keyId)
|
||||
}
|
||||
assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
|
||||
@ -320,7 +301,7 @@ class QuadSTests : InstrumentedTest {
|
||||
private fun generatedSecretFromPassphrase(session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
|
||||
val quadS = session.sharedSecretStorageService
|
||||
|
||||
val creationInfo = mTestHelper.runBlockingTest {
|
||||
val creationInfo = testHelper.runBlockingTest {
|
||||
quadS.generateKeyWithPassphrase(
|
||||
keyId,
|
||||
keyId,
|
||||
@ -331,7 +312,7 @@ class QuadSTests : InstrumentedTest {
|
||||
|
||||
assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
|
||||
if (asDefault) {
|
||||
mTestHelper.runBlockingTest {
|
||||
testHelper.runBlockingTest {
|
||||
quadS.setDefaultKey(keyId)
|
||||
}
|
||||
assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
|
||||
|
@ -53,12 +53,12 @@ import java.util.concurrent.CountDownLatch
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class SASTest : InstrumentedTest {
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
@Test
|
||||
fun test_aliceStartThenAliceCancel() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -83,7 +83,7 @@ class SASTest : InstrumentedTest {
|
||||
val aliceKeyTx = aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID!!)
|
||||
assertNotNull("Alice should have a started transaction", aliceKeyTx)
|
||||
|
||||
mTestHelper.await(bobTxCreatedLatch)
|
||||
testHelper.await(bobTxCreatedLatch)
|
||||
bobVerificationService.removeListener(bobListener)
|
||||
|
||||
val bobKeyTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID)
|
||||
@ -116,7 +116,7 @@ class SASTest : InstrumentedTest {
|
||||
bobVerificationService.addListener(bobListener2)
|
||||
|
||||
aliceSasTx.cancel(CancelCode.User)
|
||||
mTestHelper.await(cancelLatch)
|
||||
testHelper.await(cancelLatch)
|
||||
|
||||
assertTrue("Should be cancelled on alice side", aliceSasTx.state is VerificationTxState.Cancelled)
|
||||
assertTrue("Should be cancelled on bob side", bobSasTx.state is VerificationTxState.Cancelled)
|
||||
@ -133,13 +133,13 @@ class SASTest : InstrumentedTest {
|
||||
assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID))
|
||||
assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID))
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_key_agreement_protocols_must_include_curve25519() {
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
||||
@ -186,17 +186,17 @@ class SASTest : InstrumentedTest {
|
||||
|
||||
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, protocols = protocols)
|
||||
|
||||
mTestHelper.await(cancelLatch)
|
||||
testHelper.await(cancelLatch)
|
||||
|
||||
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod, cancelReason)
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_key_agreement_macs_Must_include_hmac_sha256() {
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
||||
@ -223,18 +223,18 @@ class SASTest : InstrumentedTest {
|
||||
|
||||
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, mac = mac)
|
||||
|
||||
mTestHelper.await(cancelLatch)
|
||||
testHelper.await(cancelLatch)
|
||||
|
||||
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
|
||||
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_key_agreement_short_code_include_decimal() {
|
||||
fail("Not passing for the moment")
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
||||
@ -261,12 +261,12 @@ class SASTest : InstrumentedTest {
|
||||
|
||||
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, codes = codes)
|
||||
|
||||
mTestHelper.await(cancelLatch)
|
||||
testHelper.await(cancelLatch)
|
||||
|
||||
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
|
||||
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
private fun fakeBobStart(bobSession: Session,
|
||||
@ -303,7 +303,7 @@ class SASTest : InstrumentedTest {
|
||||
// If a device has two verifications in progress with the same device, then it should cancel both verifications.
|
||||
@Test
|
||||
fun test_aliceStartTwoRequests() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -332,10 +332,10 @@ class SASTest : InstrumentedTest {
|
||||
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
|
||||
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
|
||||
|
||||
mTestHelper.await(aliceCreatedLatch)
|
||||
mTestHelper.await(aliceCancelledLatch)
|
||||
testHelper.await(aliceCreatedLatch)
|
||||
testHelper.await(aliceCancelledLatch)
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -343,7 +343,7 @@ class SASTest : InstrumentedTest {
|
||||
*/
|
||||
@Test
|
||||
fun test_aliceAndBobAgreement() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -383,7 +383,7 @@ class SASTest : InstrumentedTest {
|
||||
val bobUserId = bobSession.myUserId
|
||||
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
|
||||
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
|
||||
mTestHelper.await(aliceAcceptedLatch)
|
||||
testHelper.await(aliceAcceptedLatch)
|
||||
|
||||
assertTrue("Should have receive a commitment", accepted!!.commitment?.trim()?.isEmpty() == false)
|
||||
|
||||
@ -397,12 +397,12 @@ class SASTest : InstrumentedTest {
|
||||
assertTrue("all agreed Short Code should be known by alice", startReq!!.shortAuthenticationStrings.contains(it))
|
||||
}
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_aliceAndBobSASCode() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -444,8 +444,8 @@ class SASTest : InstrumentedTest {
|
||||
val bobUserId = bobSession.myUserId
|
||||
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
|
||||
val verificationSAS = aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
|
||||
mTestHelper.await(aliceSASLatch)
|
||||
mTestHelper.await(bobSASLatch)
|
||||
testHelper.await(aliceSASLatch)
|
||||
testHelper.await(bobSASLatch)
|
||||
|
||||
val aliceTx = aliceVerificationService.getExistingTransaction(bobUserId, verificationSAS!!) as SASDefaultVerificationTransaction
|
||||
val bobTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, verificationSAS) as SASDefaultVerificationTransaction
|
||||
@ -453,12 +453,12 @@ class SASTest : InstrumentedTest {
|
||||
assertEquals("Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
|
||||
bobTx.getShortCodeRepresentation(SasMode.DECIMAL))
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_happyPath() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -520,8 +520,8 @@ class SASTest : InstrumentedTest {
|
||||
val bobUserId = bobSession.myUserId
|
||||
val bobDeviceId = bobSession.cryptoService().getMyDevice().deviceId
|
||||
aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null)
|
||||
mTestHelper.await(aliceSASLatch)
|
||||
mTestHelper.await(bobSASLatch)
|
||||
testHelper.await(aliceSASLatch)
|
||||
testHelper.await(bobSASLatch)
|
||||
|
||||
// Assert that devices are verified
|
||||
val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId)
|
||||
@ -532,12 +532,12 @@ class SASTest : InstrumentedTest {
|
||||
|
||||
assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
|
||||
assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_ConcurrentStart() {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession
|
||||
@ -553,8 +553,8 @@ class SASTest : InstrumentedTest {
|
||||
|
||||
var requestID: String? = null
|
||||
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull()
|
||||
requestID = prAlicePOV?.transactionId
|
||||
Log.v("TEST", "== alicePOV is $prAlicePOV")
|
||||
@ -564,8 +564,8 @@ class SASTest : InstrumentedTest {
|
||||
|
||||
Log.v("TEST", "== requestID is $requestID")
|
||||
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
val prBobPOV = bobVerificationService.getExistingVerificationRequests(aliceSession.myUserId).firstOrNull()
|
||||
Log.v("TEST", "== prBobPOV is $prBobPOV")
|
||||
prBobPOV?.transactionId == requestID
|
||||
@ -579,8 +579,8 @@ class SASTest : InstrumentedTest {
|
||||
)
|
||||
|
||||
// wait for alice to get the ready
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull()
|
||||
Log.v("TEST", "== prAlicePOV is $prAlicePOV")
|
||||
prAlicePOV?.transactionId == requestID && prAlicePOV?.isReady != null
|
||||
@ -606,22 +606,22 @@ class SASTest : InstrumentedTest {
|
||||
var alicePovTx: SasVerificationTransaction?
|
||||
var bobPovTx: SasVerificationTransaction?
|
||||
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
alicePovTx = aliceVerificationService.getExistingTransaction(bobSession.myUserId, requestID!!) as? SasVerificationTransaction
|
||||
Log.v("TEST", "== alicePovTx is $alicePovTx")
|
||||
alicePovTx?.state == VerificationTxState.ShortCodeReady
|
||||
}
|
||||
}
|
||||
// wait for alice to get the ready
|
||||
mTestHelper.waitWithLatch {
|
||||
mTestHelper.retryPeriodicallyWithLatch(it) {
|
||||
testHelper.waitWithLatch {
|
||||
testHelper.retryPeriodicallyWithLatch(it) {
|
||||
bobPovTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, requestID!!) as? SasVerificationTransaction
|
||||
Log.v("TEST", "== bobPovTx is $bobPovTx")
|
||||
bobPovTx?.state == VerificationTxState.ShortCodeReady
|
||||
}
|
||||
}
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ import kotlin.coroutines.resume
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class VerificationTest : InstrumentedTest {
|
||||
private val mTestHelper = CommonTestHelper(context())
|
||||
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
|
||||
private val testHelper = CommonTestHelper(context())
|
||||
private val cryptoTestHelper = CryptoTestHelper(testHelper)
|
||||
|
||||
data class ExpectedResult(
|
||||
val sasIsSupported: Boolean = false,
|
||||
@ -155,12 +155,12 @@ class VerificationTest : InstrumentedTest {
|
||||
bobSupportedMethods: List<VerificationMethod>,
|
||||
expectedResultForAlice: ExpectedResult,
|
||||
expectedResultForBob: ExpectedResult) {
|
||||
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
|
||||
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val bobSession = cryptoTestData.secondSession!!
|
||||
|
||||
mTestHelper.doSync<Unit> { callback ->
|
||||
testHelper.doSync<Unit> { callback ->
|
||||
aliceSession.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -176,7 +176,7 @@ class VerificationTest : InstrumentedTest {
|
||||
}, callback)
|
||||
}
|
||||
|
||||
mTestHelper.doSync<Unit> { callback ->
|
||||
testHelper.doSync<Unit> { callback ->
|
||||
bobSession.cryptoService().crossSigningService()
|
||||
.initializeCrossSigning(
|
||||
object : UserInteractiveAuthInterceptor {
|
||||
@ -234,7 +234,7 @@ class VerificationTest : InstrumentedTest {
|
||||
val bobUserId = bobSession.myUserId
|
||||
// Step 1: Alice starts a verification request
|
||||
aliceVerificationService.requestKeyVerificationInDMs(aliceSupportedMethods, bobUserId, cryptoTestData.roomId)
|
||||
mTestHelper.await(latch)
|
||||
testHelper.await(latch)
|
||||
|
||||
aliceReadyPendingVerificationRequest!!.let { pr ->
|
||||
pr.isSasSupported() shouldBe expectedResultForAlice.sasIsSupported
|
||||
@ -248,6 +248,6 @@ class VerificationTest : InstrumentedTest {
|
||||
pr.otherCanScanQrCode() shouldBe expectedResultForBob.otherCanScanQrCode
|
||||
}
|
||||
|
||||
cryptoTestData.cleanUp(mTestHelper)
|
||||
cryptoTestData.cleanUp(testHelper)
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ object RoomDataHelper {
|
||||
content: Content? = null,
|
||||
prevContent: Content? = null,
|
||||
sender: String = FAKE_TEST_SENDER,
|
||||
stateKey: String = FAKE_TEST_SENDER
|
||||
stateKey: String? = null
|
||||
): Event {
|
||||
return Event(
|
||||
type = type,
|
||||
@ -64,6 +64,6 @@ object RoomDataHelper {
|
||||
|
||||
private fun createFakeRoomMemberEvent(): Event {
|
||||
val roomMember = RoomMemberContent(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent()
|
||||
return createFakeEvent(EventType.STATE_ROOM_MEMBER, roomMember)
|
||||
return createFakeEvent(EventType.STATE_ROOM_MEMBER, roomMember, stateKey = FAKE_TEST_SENDER)
|
||||
}
|
||||
}
|
||||
|
@ -65,14 +65,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
|
||||
message,
|
||||
numberOfMessagesToSend)
|
||||
|
||||
// Alice clear the cache
|
||||
commonTestHelper.runBlockingTest {
|
||||
aliceSession.clearCache()
|
||||
}
|
||||
|
||||
// And restarts the sync
|
||||
aliceSession.startSync(true)
|
||||
|
||||
// Alice clear the cache and restart the sync
|
||||
commonTestHelper.clearCacheAndSync(aliceSession)
|
||||
val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(30))
|
||||
aliceTimeline.start()
|
||||
|
||||
|
@ -24,14 +24,10 @@ import org.junit.runners.JUnit4
|
||||
import org.junit.runners.MethodSorters
|
||||
import org.matrix.android.sdk.InstrumentedTest
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
|
||||
import org.matrix.android.sdk.api.session.search.SearchResult
|
||||
import org.matrix.android.sdk.common.CommonTestHelper
|
||||
import org.matrix.android.sdk.common.CryptoTestData
|
||||
import org.matrix.android.sdk.common.CryptoTestHelper
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
@ -84,24 +80,12 @@ class SearchMessagesTest : InstrumentedTest {
|
||||
val aliceSession = cryptoTestData.firstSession
|
||||
val aliceRoomId = cryptoTestData.roomId
|
||||
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
|
||||
val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(10))
|
||||
aliceTimeline.start()
|
||||
|
||||
val lock = CountDownLatch(1)
|
||||
|
||||
val eventListener = commonTestHelper.createEventListener(lock) { snapshot ->
|
||||
snapshot.count { it.root.content.toModel<MessageContent>()?.body?.startsWith(MESSAGE).orFalse() } == 2
|
||||
}
|
||||
|
||||
aliceTimeline.addListener(eventListener)
|
||||
|
||||
commonTestHelper.sendTextMessage(
|
||||
roomFromAlicePOV,
|
||||
MESSAGE,
|
||||
2)
|
||||
|
||||
commonTestHelper.await(lock)
|
||||
|
||||
val data = commonTestHelper.runBlockingTest {
|
||||
block.invoke(cryptoTestData)
|
||||
}
|
||||
@ -114,7 +98,6 @@ class SearchMessagesTest : InstrumentedTest {
|
||||
}.orFalse()
|
||||
)
|
||||
|
||||
aliceTimeline.removeAllListeners()
|
||||
cryptoTestData.cleanUp(commonTestHelper)
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.session.space
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
@ -50,18 +48,15 @@ class SpaceCreationTest : InstrumentedTest {
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun createSimplePublicSpace() {
|
||||
val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true))
|
||||
val roomName = "My Space"
|
||||
val topic = "A public space for test"
|
||||
var spaceId: String = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceId = session.spaceService().createSpace(roomName, topic, null, true)
|
||||
// wait a bit to let the summary update it self :/
|
||||
it.countDown()
|
||||
}
|
||||
spaceId = session.spaceService().createSpace(roomName, topic, null, true)
|
||||
// wait a bit to let the summary update it self :/
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
@ -134,7 +129,6 @@ class SpaceCreationTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun testSimplePublicSpaceWithChildren() {
|
||||
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
|
||||
val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
|
||||
@ -148,50 +142,40 @@ class SpaceCreationTest : InstrumentedTest {
|
||||
// create a room
|
||||
var firstChild: String? = null
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
firstChild = aliceSession.createRoom(CreateRoomParams().apply {
|
||||
this.name = "FirstRoom"
|
||||
this.topic = "Description of first room"
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
})
|
||||
it.countDown()
|
||||
}
|
||||
firstChild = aliceSession.createRoom(CreateRoomParams().apply {
|
||||
this.name = "FirstRoom"
|
||||
this.topic = "Description of first room"
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
})
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
syncedSpace?.addChildren(firstChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "a", suggested = true)
|
||||
it.countDown()
|
||||
}
|
||||
syncedSpace?.addChildren(firstChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "a", suggested = true)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
var secondChild: String? = null
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
secondChild = aliceSession.createRoom(CreateRoomParams().apply {
|
||||
this.name = "SecondRoom"
|
||||
this.topic = "Description of second room"
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
})
|
||||
it.countDown()
|
||||
}
|
||||
secondChild = aliceSession.createRoom(CreateRoomParams().apply {
|
||||
this.name = "SecondRoom"
|
||||
this.topic = "Description of second room"
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
})
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
syncedSpace?.addChildren(secondChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "b", suggested = true)
|
||||
it.countDown()
|
||||
}
|
||||
syncedSpace?.addChildren(secondChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "b", suggested = true)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
// Try to join from bob, it's a public space no need to invite
|
||||
var joinResult: JoinSpaceResult? = null
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
joinResult = bobSession.spaceService().joinSpace(spaceId)
|
||||
// wait a bit to let the summary update it self :/
|
||||
it.countDown()
|
||||
}
|
||||
joinResult = bobSession.spaceService().joinSpace(spaceId)
|
||||
// wait a bit to let the summary update it self :/
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
assertEquals(JoinSpaceResult.Success, joinResult)
|
||||
|
@ -18,9 +18,6 @@ package org.matrix.android.sdk.session.space
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.Observer
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
@ -56,43 +53,34 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
private val commonTestHelper = CommonTestHelper(context())
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun createCanonicalChildRelation() {
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
val spaceName = "My Space"
|
||||
val topic = "A public space for test"
|
||||
var spaceId: String = ""
|
||||
var spaceId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
|
||||
it.countDown()
|
||||
}
|
||||
spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
|
||||
var roomId: String = ""
|
||||
var roomId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
roomId = session.createRoom(CreateRoomParams().apply { name = "General" })
|
||||
it.countDown()
|
||||
}
|
||||
roomId = session.createRoom(CreateRoomParams().apply { name = "General" })
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
syncedSpace!!.addChildren(roomId, viaServers, null, true)
|
||||
it.countDown()
|
||||
}
|
||||
syncedSpace!!.addChildren(roomId, viaServers, null, true)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
session.spaceService().setSpaceParent(roomId, spaceId, true, viaServers)
|
||||
it.countDown()
|
||||
}
|
||||
session.spaceService().setSpaceParent(roomId, spaceId, true, viaServers)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
Thread.sleep(9000)
|
||||
@ -181,7 +169,6 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
// }
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun testFilteringBySpace() {
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
@ -205,29 +192,23 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
|
||||
it.countDown()
|
||||
}
|
||||
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
// Create orphan rooms
|
||||
|
||||
var orphan1 = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
orphan1 = session.createRoom(CreateRoomParams().apply { name = "O1" })
|
||||
it.countDown()
|
||||
}
|
||||
orphan1 = session.createRoom(CreateRoomParams().apply { name = "O1" })
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
var orphan2 = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
orphan2 = session.createRoom(CreateRoomParams().apply { name = "O2" })
|
||||
it.countDown()
|
||||
}
|
||||
orphan2 = session.createRoom(CreateRoomParams().apply { name = "O2" })
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
val allRooms = session.getRoomSummaries(roomSummaryQueryParams { excludeType = listOf(RoomType.SPACE) })
|
||||
@ -250,11 +231,9 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
|
||||
// Add a non canonical child and check that it does not appear as orphan
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
val a3 = session.createRoom(CreateRoomParams().apply { name = "A3" })
|
||||
spaceA!!.addChildren(a3, viaServers, null, false)
|
||||
it.countDown()
|
||||
}
|
||||
val a3 = session.createRoom(CreateRoomParams().apply { name = "A3" })
|
||||
spaceA!!.addChildren(a3, viaServers, null, false)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
Thread.sleep(2_000)
|
||||
@ -265,7 +244,6 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun testBreakCycle() {
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
@ -283,20 +261,16 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
|
||||
it.countDown()
|
||||
}
|
||||
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
// add back A as subspace of C
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
val spaceC = session.spaceService().getSpace(spaceCInfo.spaceId)
|
||||
spaceC!!.addChildren(spaceAInfo.spaceId, viaServers, null, true)
|
||||
it.countDown()
|
||||
}
|
||||
val spaceC = session.spaceService().getSpace(spaceCInfo.spaceId)
|
||||
spaceC!!.addChildren(spaceAInfo.spaceId, viaServers, null, true)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
Thread.sleep(1000)
|
||||
@ -313,7 +287,6 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
fun testLiveFlatChildren() {
|
||||
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
|
||||
|
||||
@ -336,12 +309,14 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
session.spaceService().setSpaceParent(spaceBInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
|
||||
}
|
||||
|
||||
val flatAChildren = runBlocking(Dispatchers.Main) {
|
||||
session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId)
|
||||
}
|
||||
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
|
||||
Triple("C1", true /*auto-join*/, true/*canonical*/),
|
||||
Triple("C2", true, true)
|
||||
))
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
|
||||
val flatAChildren = session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId)
|
||||
val childObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(children: List<RoomSummary>?) {
|
||||
// Log.d("## TEST", "Space A flat children update : ${children?.map { it.name }}")
|
||||
@ -354,20 +329,13 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
}
|
||||
}
|
||||
|
||||
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
|
||||
Triple("C1", true /*auto-join*/, true/*canonical*/),
|
||||
Triple("C2", true, true)
|
||||
))
|
||||
|
||||
// add C as subspace of B
|
||||
runBlocking {
|
||||
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
|
||||
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
}
|
||||
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
|
||||
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
|
||||
|
||||
// C1 and C2 should be in flatten child of A now
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
|
||||
flatAChildren.observeForever(childObserver)
|
||||
}
|
||||
|
||||
// Test part one of the rooms
|
||||
@ -376,7 +344,7 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
val bRoom = session.getRoom(bRoomId)
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
|
||||
val flatAChildren = session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId)
|
||||
val childObserver = object : Observer<List<RoomSummary>> {
|
||||
override fun onChanged(children: List<RoomSummary>?) {
|
||||
System.out.println("## TEST | Space A flat children update : ${children?.map { it.name }}")
|
||||
@ -389,13 +357,10 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
// part from b room
|
||||
runBlocking {
|
||||
bRoom!!.leave(null)
|
||||
}
|
||||
bRoom!!.leave(null)
|
||||
// The room should have disapear from flat children
|
||||
GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
|
||||
flatAChildren.observeForever(childObserver)
|
||||
}
|
||||
|
||||
commonTestHelper.signOutAndClose(session)
|
||||
}
|
||||
|
||||
@ -404,94 +369,66 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
val roomIds: List<String>
|
||||
)
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
private fun createPublicSpace(session: Session,
|
||||
spaceName: String,
|
||||
childInfo: List<Triple<String, Boolean, Boolean?>>
|
||||
/** Name, auto-join, canonical*/
|
||||
): TestSpaceCreationResult {
|
||||
var spaceId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
|
||||
it.countDown()
|
||||
var roomIds: List<String> = emptyList()
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
|
||||
roomIds = childInfo.map { entry ->
|
||||
session.createRoom(CreateRoomParams().apply { name = entry.first })
|
||||
}
|
||||
}
|
||||
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
|
||||
val roomIds =
|
||||
childInfo.map { entry ->
|
||||
var roomId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
roomId = session.createRoom(CreateRoomParams().apply { name = entry.first })
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
roomId
|
||||
}
|
||||
|
||||
roomIds.forEachIndexed { index, roomId ->
|
||||
runBlocking {
|
||||
roomIds.forEachIndexed { index, roomId ->
|
||||
syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
|
||||
val canonical = childInfo[index].third
|
||||
if (canonical != null) {
|
||||
session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
|
||||
}
|
||||
}
|
||||
latch.countDown()
|
||||
}
|
||||
return TestSpaceCreationResult(spaceId, roomIds)
|
||||
}
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
private fun createPrivateSpace(session: Session,
|
||||
spaceName: String,
|
||||
childInfo: List<Triple<String, Boolean, Boolean?>>
|
||||
/** Name, auto-join, canonical*/
|
||||
): TestSpaceCreationResult {
|
||||
var spaceId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
|
||||
it.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
|
||||
val roomIds =
|
||||
childInfo.map { entry ->
|
||||
var roomId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
val homeServerCapabilities = session
|
||||
.getHomeServerCapabilities()
|
||||
roomId = session.createRoom(CreateRoomParams().apply {
|
||||
name = entry.first
|
||||
this.featurePreset = RestrictedRoomPreset(
|
||||
homeServerCapabilities,
|
||||
listOf(
|
||||
RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
|
||||
)
|
||||
)
|
||||
})
|
||||
it.countDown()
|
||||
}
|
||||
var roomIds: List<String> = emptyList()
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
|
||||
val syncedSpace = session.spaceService().getSpace(spaceId)
|
||||
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
|
||||
roomIds =
|
||||
childInfo.map { entry ->
|
||||
val homeServerCapabilities = session
|
||||
.getHomeServerCapabilities()
|
||||
session.createRoom(CreateRoomParams().apply {
|
||||
name = entry.first
|
||||
this.featurePreset = RestrictedRoomPreset(
|
||||
homeServerCapabilities,
|
||||
listOf(
|
||||
RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
roomId
|
||||
}
|
||||
|
||||
roomIds.forEachIndexed { index, roomId ->
|
||||
runBlocking {
|
||||
roomIds.forEachIndexed { index, roomId ->
|
||||
syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
|
||||
val canonical = childInfo[index].third
|
||||
if (canonical != null) {
|
||||
session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
|
||||
}
|
||||
}
|
||||
latch.countDown()
|
||||
}
|
||||
return TestSpaceCreationResult(spaceId, roomIds)
|
||||
}
|
||||
@ -559,11 +496,9 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
|
||||
var bobRoomId = ""
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
bobRoomId = bobSession.createRoom(CreateRoomParams().apply { name = "A Bob Room" })
|
||||
bobSession.getRoom(bobRoomId)!!.invite(aliceSession.myUserId)
|
||||
it.countDown()
|
||||
}
|
||||
bobRoomId = bobSession.createRoom(CreateRoomParams().apply { name = "A Bob Room" })
|
||||
bobSession.getRoom(bobRoomId)!!.invite(aliceSession.myUserId)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.runBlockingTest {
|
||||
@ -577,10 +512,8 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
bobSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
it.countDown()
|
||||
}
|
||||
bobSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
@ -600,19 +533,17 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
// Let's now try to make alice admin of the room
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
val room = bobSession.getRoom(bobRoomId)!!
|
||||
val currentPLContent = room
|
||||
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.let { it.content.toModel<PowerLevelsContent>() }
|
||||
val room = bobSession.getRoom(bobRoomId)!!
|
||||
val currentPLContent = room
|
||||
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.let { it.content.toModel<PowerLevelsContent>() }
|
||||
|
||||
val newPowerLevelsContent = currentPLContent
|
||||
?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value)
|
||||
?.toContent()
|
||||
val newPowerLevelsContent = currentPLContent
|
||||
?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value)
|
||||
?.toContent()
|
||||
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent!!)
|
||||
it.countDown()
|
||||
}
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent!!)
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
@ -627,10 +558,8 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch {
|
||||
GlobalScope.launch {
|
||||
aliceSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
it.countDown()
|
||||
}
|
||||
aliceSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
it.countDown()
|
||||
}
|
||||
|
||||
commonTestHelper.waitWithLatch { latch ->
|
||||
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerFactory
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
@ -33,6 +34,7 @@ import org.matrix.android.sdk.internal.di.DaggerMatrixComponent
|
||||
import org.matrix.android.sdk.internal.network.ApiInterceptor
|
||||
import org.matrix.android.sdk.internal.network.UserAgentHolder
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
@ -53,12 +55,17 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
@Inject internal lateinit var sessionManager: SessionManager
|
||||
@Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService
|
||||
@Inject internal lateinit var apiInterceptor: ApiInterceptor
|
||||
@Inject internal lateinit var matrixWorkerFactory: MatrixWorkerFactory
|
||||
|
||||
init {
|
||||
Monarchy.init(context)
|
||||
DaggerMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
|
||||
if (context.applicationContext !is Configuration.Provider) {
|
||||
WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build())
|
||||
val configuration = Configuration.Builder()
|
||||
.setExecutor(Executors.newCachedThreadPool())
|
||||
.setWorkerFactory(matrixWorkerFactory)
|
||||
.build()
|
||||
WorkManager.initialize(context, configuration)
|
||||
}
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
|
||||
}
|
||||
@ -77,6 +84,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
return legacySessionImporter
|
||||
}
|
||||
|
||||
fun workerFactory(): WorkerFactory = matrixWorkerFactory
|
||||
|
||||
fun registerApiInterceptorListener(path: ApiPath, listener: ApiInterceptorListener) {
|
||||
apiInterceptor.addListener(path, listener)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.failure.shouldBeRetried
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.ShareRequestCancellation
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
@ -34,9 +35,8 @@ import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
|
||||
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class CancelGossipRequestWorker(context: Context,
|
||||
params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<CancelGossipRequestWorker.Params>(context, params, Params::class.java) {
|
||||
internal class CancelGossipRequestWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<CancelGossipRequestWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.failure.shouldBeRetried
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.GossipingToDeviceObject
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyShareRequest
|
||||
@ -37,9 +38,8 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class SendGossipRequestWorker(context: Context,
|
||||
params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<SendGossipRequestWorker.Params>(context, params, Params::class.java) {
|
||||
internal class SendGossipRequestWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<SendGossipRequestWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.failure.shouldBeRetried
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||
@ -37,9 +38,8 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class SendGossipWorker(context: Context,
|
||||
params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<SendGossipWorker.Params>(context, params, Params::class.java) {
|
||||
internal class SendGossipWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<SendGossipWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -25,6 +25,7 @@ import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
|
||||
import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
|
||||
@ -50,9 +51,8 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class UpdateTrustWorker(context: Context,
|
||||
params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<UpdateTrustWorker.Params>(context, params, Params::class.java) {
|
||||
internal class UpdateTrustWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<UpdateTrustWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -20,6 +20,7 @@ import androidx.work.Data
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.failure.shouldBeRetried
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import org.matrix.android.sdk.internal.session.room.send.CancelSendTracker
|
||||
@ -33,9 +34,8 @@ import javax.inject.Inject
|
||||
* Possible previous worker: None
|
||||
* Possible next worker : None
|
||||
*/
|
||||
internal class SendVerificationMessageWorker(context: Context,
|
||||
params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<SendVerificationMessageWorker.Params>(context, params, Params::class.java) {
|
||||
internal class SendVerificationMessageWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<SendVerificationMessageWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.session.TestInterceptor
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.util.system.SystemModule
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import org.matrix.olm.OlmManager
|
||||
import java.io.File
|
||||
|
||||
@ -86,6 +87,8 @@ internal interface MatrixComponent {
|
||||
|
||||
fun sessionManager(): SessionManager
|
||||
|
||||
fun matrixWorkerFactory(): MatrixWorkerFactory
|
||||
|
||||
fun inject(matrix: Matrix)
|
||||
|
||||
@Component.Factory
|
||||
|
@ -20,6 +20,8 @@ import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.internal.session.MockHttpInterceptor
|
||||
import org.matrix.android.sdk.internal.session.TestInterceptor
|
||||
import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
||||
import org.matrix.android.sdk.internal.util.DefaultBackgroundDetectionObserver
|
||||
|
||||
@Module
|
||||
internal object NoOpTestModule {
|
||||
@ -28,4 +30,11 @@ internal object NoOpTestModule {
|
||||
@JvmStatic
|
||||
@MockHttpInterceptor
|
||||
fun providesTestInterceptor(): TestInterceptor? = null
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@MatrixScope
|
||||
fun providesBackgroundDetectionObserver(): BackgroundDetectionObserver {
|
||||
return DefaultBackgroundDetectionObserver()
|
||||
}
|
||||
}
|
||||
|
@ -17,24 +17,38 @@
|
||||
package org.matrix.android.sdk.internal.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ListenableWorker
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkRequest
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class WorkManagerProvider @Inject constructor(
|
||||
context: Context,
|
||||
@SessionId private val sessionId: String
|
||||
@SessionId private val sessionId: String,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val sessionScope: CoroutineScope
|
||||
) {
|
||||
private val tag = MATRIX_SDK_TAG_PREFIX + sessionId
|
||||
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
|
||||
init {
|
||||
checkIfWorkerFactoryIsSetup()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
|
||||
*/
|
||||
@ -60,6 +74,27 @@ internal class WorkManagerProvider @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIfWorkerFactoryIsSetup() {
|
||||
sessionScope.launch(coroutineDispatchers.main) {
|
||||
val checkWorkerRequest = OneTimeWorkRequestBuilder<MatrixWorkerFactory.CheckFactoryWorker>().build()
|
||||
workManager.enqueue(checkWorkerRequest)
|
||||
val checkWorkerLiveState = workManager.getWorkInfoByIdLiveData(checkWorkerRequest.id)
|
||||
val observer = object : Observer<WorkInfo> {
|
||||
override fun onChanged(workInfo: WorkInfo) {
|
||||
if (workInfo.state.isFinished) {
|
||||
checkWorkerLiveState.removeObserver(this)
|
||||
if (workInfo.state == WorkInfo.State.FAILED) {
|
||||
throw RuntimeException("MatrixWorkerFactory is not being set on your worker configuration.\n" +
|
||||
"Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" +
|
||||
"You can grab the instance through the Matrix class.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
checkWorkerLiveState.observeForever(observer)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MATRIX_SDK_TAG_PREFIX = "MatrixSDK-"
|
||||
|
||||
|
@ -203,8 +203,11 @@ internal class MxCallImpl(
|
||||
|
||||
override fun selectAnswer() {
|
||||
Timber.tag(loggerTag.value).v("select answer $callId")
|
||||
if (isOutgoing) return
|
||||
state = CallState.Answering
|
||||
if (!isOutgoing) return
|
||||
// This is an outgoing call, select the remote client that answered.
|
||||
if (state != CallState.Dialing) {
|
||||
Timber.tag(loggerTag.value).w("Expected state is CallState.Dialing got $state.")
|
||||
}
|
||||
CallSelectAnswerContent(
|
||||
callId = callId,
|
||||
partyId = ourPartyId,
|
||||
|
@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||
@ -63,8 +64,8 @@ private data class NewAttachmentAttributes(
|
||||
* Possible previous worker: None
|
||||
* Possible next worker : Always [MultipleEventSendingDispatcherWorker]
|
||||
*/
|
||||
internal class UploadContentWorker(val context: Context, params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<UploadContentWorker.Params>(context, params, Params::class.java) {
|
||||
internal class UploadContentWorker(val context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<UploadContentWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.group
|
||||
import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
|
||||
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
@ -28,8 +29,8 @@ import javax.inject.Inject
|
||||
* Possible previous worker: None
|
||||
* Possible next worker : None
|
||||
*/
|
||||
internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<GetGroupDataWorker.Params>(context, params, Params::class.java) {
|
||||
internal class GetGroupDataWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<GetGroupDataWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -19,13 +19,14 @@ import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
|
||||
import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AddPusherWorker(context: Context, params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<AddPusherWorker.Params>(context, params, Params::class.java) {
|
||||
internal class AddPusherWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<AddPusherWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -21,6 +21,7 @@ import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
|
||||
@ -38,8 +39,8 @@ import javax.inject.Inject
|
||||
* Possible previous worker: Always [UploadContentWorker]
|
||||
* Possible next worker : None, but it will post new work to send events, encrypted or not
|
||||
*/
|
||||
internal class MultipleEventSendingDispatcherWorker(context: Context, params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<MultipleEventSendingDispatcherWorker.Params>(context, params, Params::class.java) {
|
||||
internal class MultipleEventSendingDispatcherWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<MultipleEventSendingDispatcherWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -19,6 +19,7 @@ import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
@ -32,8 +33,8 @@ import javax.inject.Inject
|
||||
* Possible previous worker: None
|
||||
* Possible next worker : None
|
||||
*/
|
||||
internal class RedactEventWorker(context: Context, params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<RedactEventWorker.Params>(context, params, Params::class.java) {
|
||||
internal class RedactEventWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<RedactEventWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -23,6 +23,7 @@ import io.realm.RealmConfiguration
|
||||
import org.matrix.android.sdk.api.failure.shouldBeRetried
|
||||
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.tasks.SendEventTask
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
@ -38,9 +39,8 @@ import javax.inject.Inject
|
||||
* Possible previous worker: [EncryptEventWorker] or first worker
|
||||
* Possible next worker : None
|
||||
*/
|
||||
internal class SendEventWorker(context: Context,
|
||||
params: WorkerParameters) :
|
||||
SessionSafeCoroutineWorker<SendEventWorker.Params>(context, params, Params::class.java) {
|
||||
internal class SendEventWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<SendEventWorker.Params>(context, params, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -25,9 +25,12 @@ import javax.inject.Inject
|
||||
internal class SyncTokenStore @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
|
||||
|
||||
fun getLastToken(): String? {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
val token = Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
// Makes sure realm is up-to-date as it's used for querying internally on non looper thread.
|
||||
it.refresh()
|
||||
it.where(SyncEntity::class.java).findFirst()?.nextBatch
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
fun saveToken(realm: Realm, token: String?) {
|
||||
|
@ -21,8 +21,8 @@ import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.failure.isTokenError
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.di.WorkManagerProvider
|
||||
import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import org.matrix.android.sdk.internal.session.sync.SyncPresence
|
||||
import org.matrix.android.sdk.internal.session.sync.SyncTask
|
||||
@ -41,9 +41,8 @@ private const val DEFAULT_DELAY_TIMEOUT = 30_000L
|
||||
* Possible previous worker: None
|
||||
* Possible next worker : None
|
||||
*/
|
||||
internal class SyncWorker(context: Context,
|
||||
workerParameters: WorkerParameters
|
||||
) : SessionSafeCoroutineWorker<SyncWorker.Params>(context, workerParameters, Params::class.java) {
|
||||
internal class SyncWorker(context: Context, workerParameters: WorkerParameters, sessionManager: SessionManager) :
|
||||
SessionSafeCoroutineWorker<SyncWorker.Params>(context, workerParameters, sessionManager, Params::class.java) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
@ -56,7 +55,6 @@ internal class SyncWorker(context: Context,
|
||||
|
||||
@Inject lateinit var syncTask: SyncTask
|
||||
@Inject lateinit var taskExecutor: TaskExecutor
|
||||
@Inject lateinit var networkConnectivityChecker: NetworkConnectivityChecker
|
||||
@Inject lateinit var workManagerProvider: WorkManagerProvider
|
||||
|
||||
override fun injectWith(injector: SessionComponent) {
|
||||
|
@ -18,26 +18,32 @@ package org.matrix.android.sdk.internal.util
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import org.matrix.android.sdk.internal.di.MatrixScope
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* To be attached to ProcessLifecycleOwner lifecycle
|
||||
*/
|
||||
@MatrixScope
|
||||
internal class BackgroundDetectionObserver @Inject constructor() : DefaultLifecycleObserver {
|
||||
interface BackgroundDetectionObserver : DefaultLifecycleObserver {
|
||||
val isInBackground: Boolean
|
||||
|
||||
var isInBackground: Boolean = true
|
||||
fun register(listener: Listener)
|
||||
fun unregister(listener: Listener)
|
||||
|
||||
interface Listener {
|
||||
fun onMoveToForeground()
|
||||
fun onMoveToBackground()
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultBackgroundDetectionObserver : BackgroundDetectionObserver {
|
||||
|
||||
override var isInBackground: Boolean = true
|
||||
private set
|
||||
|
||||
private val listeners = LinkedHashSet<Listener>()
|
||||
private val listeners = LinkedHashSet<BackgroundDetectionObserver.Listener>()
|
||||
|
||||
fun register(listener: Listener) {
|
||||
override fun register(listener: BackgroundDetectionObserver.Listener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
fun unregister(listener: Listener) {
|
||||
override fun unregister(listener: BackgroundDetectionObserver.Listener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
@ -52,9 +58,4 @@ internal class BackgroundDetectionObserver @Inject constructor() : DefaultLifecy
|
||||
isInBackground = true
|
||||
listeners.forEach { it.onMoveToBackground() }
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun onMoveToForeground()
|
||||
fun onMoveToBackground()
|
||||
}
|
||||
}
|
||||
|
@ -17,16 +17,33 @@
|
||||
package org.matrix.android.sdk.internal.worker
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ListenableWorker
|
||||
import androidx.work.WorkerFactory
|
||||
import androidx.work.WorkerParameters
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.CancelGossipRequestWorker
|
||||
import org.matrix.android.sdk.internal.crypto.SendGossipRequestWorker
|
||||
import org.matrix.android.sdk.internal.crypto.SendGossipWorker
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
|
||||
import org.matrix.android.sdk.internal.crypto.verification.SendVerificationMessageWorker
|
||||
import org.matrix.android.sdk.internal.di.MatrixScope
|
||||
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
|
||||
import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
|
||||
import org.matrix.android.sdk.internal.session.pushers.AddPusherWorker
|
||||
import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker
|
||||
import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker
|
||||
import org.matrix.android.sdk.internal.session.room.send.SendEventWorker
|
||||
import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
class MatrixWorkerFactory @Inject constructor(
|
||||
private val workerFactories: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<DelegateWorkerFactory>>
|
||||
) : WorkerFactory() {
|
||||
/**
|
||||
* This factory is responsible of creating Workers by giving the session manager.
|
||||
* This is not the cleanest way but getting SessionComponent is dependant of args type.
|
||||
*/
|
||||
@MatrixScope
|
||||
internal class MatrixWorkerFactory @Inject constructor(private val sessionManager: SessionManager) : WorkerFactory() {
|
||||
|
||||
override fun createWorker(
|
||||
appContext: Context,
|
||||
@ -34,11 +51,61 @@ class MatrixWorkerFactory @Inject constructor(
|
||||
workerParameters: WorkerParameters
|
||||
): ListenableWorker? {
|
||||
Timber.d("MatrixWorkerFactory.createWorker for $workerClassName")
|
||||
return when (workerClassName) {
|
||||
CheckFactoryWorker::class.java.name ->
|
||||
CheckFactoryWorker(appContext, workerParameters, true)
|
||||
AddPusherWorker::class.java.name ->
|
||||
AddPusherWorker(appContext, workerParameters, sessionManager)
|
||||
CancelGossipRequestWorker::class.java.name ->
|
||||
CancelGossipRequestWorker(appContext, workerParameters, sessionManager)
|
||||
GetGroupDataWorker::class.java.name ->
|
||||
GetGroupDataWorker(appContext, workerParameters, sessionManager)
|
||||
MultipleEventSendingDispatcherWorker::class.java.name ->
|
||||
MultipleEventSendingDispatcherWorker(appContext, workerParameters, sessionManager)
|
||||
RedactEventWorker::class.java.name ->
|
||||
RedactEventWorker(appContext, workerParameters, sessionManager)
|
||||
SendEventWorker::class.java.name ->
|
||||
SendEventWorker(appContext, workerParameters, sessionManager)
|
||||
SendGossipRequestWorker::class.java.name ->
|
||||
SendGossipRequestWorker(appContext, workerParameters, sessionManager)
|
||||
SendGossipWorker::class.java.name ->
|
||||
SendGossipWorker(appContext, workerParameters, sessionManager)
|
||||
SendVerificationMessageWorker::class.java.name ->
|
||||
SendVerificationMessageWorker(appContext, workerParameters, sessionManager)
|
||||
SyncWorker::class.java.name ->
|
||||
SyncWorker(appContext, workerParameters, sessionManager)
|
||||
UpdateTrustWorker::class.java.name ->
|
||||
UpdateTrustWorker(appContext, workerParameters, sessionManager)
|
||||
UploadContentWorker::class.java.name ->
|
||||
UploadContentWorker(appContext, workerParameters, sessionManager)
|
||||
else -> {
|
||||
Timber.w("No worker defined on MatrixWorkerFactory for $workerClassName will delegate to default.")
|
||||
// Return null to delegate to the default WorkerFactory.
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val foundEntry =
|
||||
workerFactories.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }
|
||||
val factoryProvider = foundEntry?.value
|
||||
?: throw IllegalArgumentException("unknown worker class name: $workerClassName")
|
||||
return factoryProvider.get().create(appContext, workerParameters)
|
||||
/**
|
||||
* This worker is launched by the factory with the isCreatedByMatrixWorkerFactory flag to true.
|
||||
* If the MatrixWorkerFactory is not set up, it will default to the other constructor and it will throw
|
||||
*/
|
||||
class CheckFactoryWorker(context: Context,
|
||||
workerParameters: WorkerParameters,
|
||||
private val isCreatedByMatrixWorkerFactory: Boolean) :
|
||||
CoroutineWorker(context, workerParameters) {
|
||||
|
||||
// Called by WorkManager if there is no MatrixWorkerFactory
|
||||
constructor(context: Context, workerParameters: WorkerParameters) : this(context,
|
||||
workerParameters,
|
||||
isCreatedByMatrixWorkerFactory = false)
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
return if (!isCreatedByMatrixWorkerFactory) {
|
||||
Result.failure()
|
||||
} else {
|
||||
Result.success()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import androidx.work.CoroutineWorker
|
||||
import androidx.work.Data
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
import timber.log.Timber
|
||||
|
||||
@ -33,6 +34,7 @@ import timber.log.Timber
|
||||
internal abstract class SessionSafeCoroutineWorker<PARAM : SessionWorkerParams>(
|
||||
context: Context,
|
||||
workerParameters: WorkerParameters,
|
||||
private val sessionManager: SessionManager,
|
||||
private val paramClass: Class<PARAM>
|
||||
) : CoroutineWorker(context, workerParameters) {
|
||||
|
||||
@ -48,7 +50,7 @@ internal abstract class SessionSafeCoroutineWorker<PARAM : SessionWorkerParams>(
|
||||
.also { Timber.e("Unable to parse work parameters") }
|
||||
|
||||
return try {
|
||||
val sessionComponent = getSessionComponent(params.sessionId)
|
||||
val sessionComponent = sessionManager.getSessionComponent(params.sessionId)
|
||||
?: return buildErrorResult(params, "No session")
|
||||
|
||||
// Make sure to inject before handling error as you may need some dependencies to process them.
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.worker
|
||||
|
||||
import androidx.work.ListenableWorker
|
||||
import org.matrix.android.sdk.api.Matrix
|
||||
import org.matrix.android.sdk.internal.session.SessionComponent
|
||||
|
||||
internal fun ListenableWorker.getSessionComponent(sessionId: String): SessionComponent? {
|
||||
return Matrix.getInstance(applicationContext).sessionManager.getSessionComponent(sessionId)
|
||||
}
|
@ -160,7 +160,7 @@ Formatter\.formatShortFileSize===1
|
||||
# android\.text\.TextUtils
|
||||
|
||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
|
||||
enum class===108
|
||||
enum class===110
|
||||
|
||||
### Do not import temporary legacy classes
|
||||
import org.matrix.android.sdk.internal.legacy.riot===3
|
||||
|
26
tools/compressVideo.sh
Executable file
26
tools/compressVideo.sh
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# Copyright (c) 2021 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.
|
||||
#
|
||||
|
||||
set -e
|
||||
echo "Converting file $1"
|
||||
file=$(echo $1 | sed 's/\.[^.]*$//')
|
||||
ffmpeg -i $1 -filter_complex "[0:v] fps=12,scale=480:-1,split [a][b];[a] palettegen [p];[b][p] paletteuse" $file-tmp.gif
|
||||
echo "Converting to Gif"
|
||||
gifsicle -O3 --lossy=80 -o $file.gif $file-tmp.gif
|
||||
rm $file-tmp.gif
|
||||
echo "Done, $file.gif has been generated"
|
@ -140,16 +140,8 @@ android {
|
||||
buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\""
|
||||
resValue "string", "build_number", "\"${buildNumber}\""
|
||||
|
||||
// The two booleans must not have the same value. We need two values for the manifest
|
||||
// LoginFlowV2 is disabled to be merged on develop (changelog: Improve login/register flow (#1410, #2585, #3172))
|
||||
resValue "bool", "useLoginV1", "true"
|
||||
resValue "bool", "useLoginV2", "false"
|
||||
|
||||
// NotificationSettingsV2 is disabled. To be released in conjunction with iOS/Web
|
||||
def useNotificationSettingsV2 = true
|
||||
buildConfigField "Boolean", "USE_NOTIFICATION_SETTINGS_V2", "${useNotificationSettingsV2}"
|
||||
resValue "bool", "useNotificationSettingsV1", "${!useNotificationSettingsV2}"
|
||||
resValue "bool", "useNotificationSettingsV2", "${useNotificationSettingsV2}"
|
||||
buildConfigField "im.vector.app.features.VectorFeatures.LoginVersion", "LOGIN_VERSION", "im.vector.app.features.VectorFeatures.LoginVersion.V1"
|
||||
buildConfigField "im.vector.app.features.VectorFeatures.NotificationSettingsVersion", "NOTIFICATION_SETTINGS_VERSION", "im.vector.app.features.VectorFeatures.NotificationSettingsVersion.V2"
|
||||
|
||||
buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping"
|
||||
|
||||
|
@ -21,22 +21,27 @@ import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.espresso.tools.clickOnPreference
|
||||
import im.vector.app.features.VectorFeatures
|
||||
|
||||
class SettingsNotificationsRobot {
|
||||
|
||||
fun crawl() {
|
||||
if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) {
|
||||
clickOn(R.string.settings_notification_default)
|
||||
pressBack()
|
||||
clickOn(R.string.settings_notification_mentions_and_keywords)
|
||||
// TODO Test adding a keyword?
|
||||
pressBack()
|
||||
clickOn(R.string.settings_notification_other)
|
||||
pressBack()
|
||||
} else {
|
||||
clickOn(R.string.settings_notification_advanced)
|
||||
pressBack()
|
||||
when (BuildConfig.NOTIFICATION_SETTINGS_VERSION!!) {
|
||||
VectorFeatures.NotificationSettingsVersion.V1 -> {
|
||||
clickOn(R.string.settings_notification_advanced)
|
||||
pressBack()
|
||||
}
|
||||
VectorFeatures.NotificationSettingsVersion.V2 -> {
|
||||
clickOn(R.string.settings_notification_default)
|
||||
pressBack()
|
||||
clickOn(R.string.settings_notification_mentions_and_keywords)
|
||||
// TODO Test adding a keyword?
|
||||
pressBack()
|
||||
clickOn(R.string.settings_notification_other)
|
||||
pressBack()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
clickOn(R.string.settings_noisy_notifications_preferences)
|
||||
TODO Cannot go back
|
||||
|
@ -113,45 +113,33 @@
|
||||
|
||||
<activity android:name=".features.home.HomeActivity" />
|
||||
|
||||
<!-- exported="true" is required to handle android.intent.action.VIEW for URL redirection-->
|
||||
<activity
|
||||
android:name=".features.login.SSORedirectRouterActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Vector.Black.Transparent">
|
||||
|
||||
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="connect"
|
||||
android:scheme="element" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".features.login.LoginActivity"
|
||||
android:enabled="@bool/useLoginV1"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="connect"
|
||||
android:scheme="element" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- exported="true" is required to handle android.intent.action.VIEW for URL redirection-->
|
||||
<activity
|
||||
android:name=".features.login2.LoginActivity2"
|
||||
android:enabled="@bool/useLoginV2"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="connect"
|
||||
android:scheme="element" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite :/ -->
|
||||
<activity
|
||||
|
@ -220,6 +220,7 @@ class VectorApplication :
|
||||
|
||||
override fun getWorkManagerConfiguration(): WorkConfiguration {
|
||||
return WorkConfiguration.Builder()
|
||||
.setWorkerFactory(Matrix.getInstance(this.appContext).workerFactory())
|
||||
.setExecutor(Executors.newCachedThreadPool())
|
||||
.build()
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ import im.vector.app.core.error.DefaultErrorFormatter
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.time.Clock
|
||||
import im.vector.app.core.time.DefaultClock
|
||||
import im.vector.app.features.DefaultVectorFeatures
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.invite.AutoAcceptInvites
|
||||
import im.vector.app.features.invite.CompileTimeAutoAcceptInvites
|
||||
import im.vector.app.features.navigation.DefaultNavigator
|
||||
@ -133,4 +135,9 @@ object VectorStaticModule {
|
||||
fun providesCoroutineDispatchers(): CoroutineDispatchers {
|
||||
return CoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.Default)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun providesFeatures(): VectorFeatures {
|
||||
return DefaultVectorFeatures()
|
||||
}
|
||||
}
|
||||
|
@ -41,8 +41,6 @@ import im.vector.app.features.pin.UnlockedActivity
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.signout.hard.SignedOutActivity
|
||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||
import im.vector.app.features.signout.soft.SoftLogoutActivity2
|
||||
import im.vector.app.features.themes.ActivityOtherThemes
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -223,9 +221,11 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
||||
navigator.openLogin(this, null)
|
||||
null
|
||||
}
|
||||
args.isSoftLogout ->
|
||||
args.isSoftLogout -> {
|
||||
// The homeserver has invalidated the token, with a soft logout
|
||||
getSoftLogoutActivityIntent()
|
||||
navigator.softLogout(this)
|
||||
null
|
||||
}
|
||||
args.isUserLoggedOut ->
|
||||
// the homeserver has invalidated the token (password changed, device deleted, other security reasons)
|
||||
SignedOutActivity.newIntent(this)
|
||||
@ -236,7 +236,8 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
||||
HomeActivity.newIntent(this)
|
||||
} else {
|
||||
// The token is still invalid
|
||||
getSoftLogoutActivityIntent()
|
||||
navigator.softLogout(this)
|
||||
null
|
||||
}
|
||||
else -> {
|
||||
// First start, or no active session
|
||||
@ -247,12 +248,4 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
||||
intent?.let { startActivity(it) }
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun getSoftLogoutActivityIntent(): Intent {
|
||||
return if (resources.getBoolean(R.bool.useLoginV2)) {
|
||||
SoftLogoutActivity2.newIntent(this)
|
||||
} else {
|
||||
SoftLogoutActivity.newIntent(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features
|
||||
|
||||
import im.vector.app.BuildConfig
|
||||
|
||||
interface VectorFeatures {
|
||||
|
||||
fun loginVersion(): LoginVersion
|
||||
fun notificationSettingsVersion(): NotificationSettingsVersion
|
||||
|
||||
enum class LoginVersion {
|
||||
V1,
|
||||
V2
|
||||
}
|
||||
|
||||
enum class NotificationSettingsVersion {
|
||||
V1,
|
||||
V2
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultVectorFeatures : VectorFeatures {
|
||||
override fun loginVersion(): VectorFeatures.LoginVersion = BuildConfig.LOGIN_VERSION
|
||||
override fun notificationSettingsVersion(): VectorFeatures.NotificationSettingsVersion = BuildConfig.NOTIFICATION_SETTINGS_VERSION
|
||||
}
|
@ -17,7 +17,6 @@ package im.vector.app.features.home.room.list.actions
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.bottomSheetDividerItem
|
||||
import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem
|
||||
@ -25,6 +24,7 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem
|
||||
import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.roomprofile.notifications.notificationOptions
|
||||
import im.vector.app.features.roomprofile.notifications.notificationStateMapped
|
||||
@ -38,7 +38,8 @@ import javax.inject.Inject
|
||||
class RoomListQuickActionsEpoxyController @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider
|
||||
private val stringProvider: StringProvider,
|
||||
private val features: VectorFeatures
|
||||
) : TypedEpoxyController<RoomListQuickActionViewState>() {
|
||||
|
||||
var listener: Listener? = null
|
||||
@ -47,7 +48,7 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
|
||||
val notificationViewState = state.notificationSettingsViewState
|
||||
val roomSummary = notificationViewState.roomSummary() ?: return
|
||||
val host = this
|
||||
val isV2 = BuildConfig.USE_NOTIFICATION_SETTINGS_V2
|
||||
val isV2 = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2
|
||||
// V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications
|
||||
val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2
|
||||
|
||||
@ -73,14 +74,14 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
|
||||
}
|
||||
|
||||
if (isV2) {
|
||||
notificationViewState.notificationOptions.forEach { notificationState ->
|
||||
notificationViewState.notificationOptions.forEach { notificationState ->
|
||||
val title = titleForNotificationState(notificationState)
|
||||
radioButtonItem {
|
||||
id(notificationState.name)
|
||||
titleRes(title)
|
||||
selected(notificationViewState.notificationStateMapped() == notificationState)
|
||||
listener {
|
||||
host.listener?.didSelectRoomNotificationState(notificationState)
|
||||
host.listener?.didSelectRoomNotificationState(notificationState)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,8 +103,9 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
|
||||
RoomNotificationState.ALL_MESSAGES_NOISY -> R.string.room_settings_all_messages
|
||||
RoomNotificationState.MENTIONS_ONLY -> R.string.room_settings_mention_and_keyword_only
|
||||
RoomNotificationState.MUTE -> R.string.room_settings_none
|
||||
else -> null
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) {
|
||||
val host = this@RoomListQuickActionsEpoxyController
|
||||
val selected = when (this) {
|
||||
|
@ -18,6 +18,7 @@ package im.vector.app.features.login
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.ViewCompat
|
||||
@ -363,5 +364,11 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
|
||||
putExtra(EXTRA_CONFIG, loginConfig)
|
||||
}
|
||||
}
|
||||
|
||||
fun redirectIntent(context: Context, data: Uri?): Intent {
|
||||
return Intent(context, LoginActivity::class.java).apply {
|
||||
setData(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.login
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SSORedirectRouterActivity : AppCompatActivity() {
|
||||
|
||||
@Inject lateinit var navigator: Navigator
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
navigator.loginSSORedirect(this, intent.data)
|
||||
finish()
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package im.vector.app.features.login2
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.ViewCompat
|
||||
@ -396,5 +397,11 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
|
||||
putExtra(EXTRA_CONFIG, loginConfig)
|
||||
}
|
||||
}
|
||||
|
||||
fun redirectIntent(context: Context, data: Uri?): Intent {
|
||||
return Intent(context, LoginActivity2::class.java).apply {
|
||||
setData(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package im.vector.app.features.navigation
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
@ -36,6 +37,7 @@ import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.fatalError
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||
import im.vector.app.features.call.conference.VectorJitsiActivity
|
||||
import im.vector.app.features.call.transfer.CallTransferActivity
|
||||
@ -77,6 +79,8 @@ import im.vector.app.features.roomprofile.RoomProfileActivity
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import im.vector.app.features.share.SharedData
|
||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||
import im.vector.app.features.signout.soft.SoftLogoutActivity2
|
||||
import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet
|
||||
import im.vector.app.features.spaces.SpaceExploreActivity
|
||||
import im.vector.app.features.spaces.SpacePreviewActivity
|
||||
@ -102,19 +106,35 @@ class DefaultNavigator @Inject constructor(
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val widgetArgsBuilder: WidgetArgsBuilder,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider
|
||||
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
|
||||
private val features: VectorFeatures
|
||||
) : Navigator {
|
||||
|
||||
override fun openLogin(context: Context, loginConfig: LoginConfig?, flags: Int) {
|
||||
val intent = if (context.resources.getBoolean(R.bool.useLoginV2)) {
|
||||
LoginActivity2.newIntent(context, loginConfig)
|
||||
} else {
|
||||
LoginActivity.newIntent(context, loginConfig)
|
||||
val intent = when (features.loginVersion()) {
|
||||
VectorFeatures.LoginVersion.V1 -> LoginActivity.newIntent(context, loginConfig)
|
||||
VectorFeatures.LoginVersion.V2 -> LoginActivity2.newIntent(context, loginConfig)
|
||||
}
|
||||
intent.addFlags(flags)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun loginSSORedirect(context: Context, data: Uri?) {
|
||||
val intent = when (features.loginVersion()) {
|
||||
VectorFeatures.LoginVersion.V1 -> LoginActivity.redirectIntent(context, data)
|
||||
VectorFeatures.LoginVersion.V2 -> LoginActivity2.redirectIntent(context, data)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun softLogout(context: Context) {
|
||||
val intent = when (features.loginVersion()) {
|
||||
VectorFeatures.LoginVersion.V1 -> SoftLogoutActivity.newIntent(context)
|
||||
VectorFeatures.LoginVersion.V2 -> SoftLogoutActivity2.newIntent(context)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun openRoom(context: Context, roomId: String, eventId: String?, buildTask: Boolean) {
|
||||
if (sessionHolder.getSafeActiveSession()?.getRoom(roomId) == null) {
|
||||
fatalError("Trying to open an unknown room $roomId", vectorPreferences.failFast())
|
||||
|
@ -19,6 +19,7 @@ package im.vector.app.features.navigation
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.core.util.Pair
|
||||
@ -41,6 +42,10 @@ interface Navigator {
|
||||
|
||||
fun openLogin(context: Context, loginConfig: LoginConfig? = null, flags: Int = 0)
|
||||
|
||||
fun loginSSORedirect(context: Context, data: Uri?)
|
||||
|
||||
fun softLogout(context: Context)
|
||||
|
||||
fun openRoom(context: Context, roomId: String, eventId: String? = null, buildTask: Boolean = false)
|
||||
|
||||
sealed class PostSwitchSpaceAction {
|
||||
|
@ -31,7 +31,6 @@ import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.animations.AppBarStateChangeListener
|
||||
import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
|
||||
@ -45,6 +44,7 @@ import im.vector.app.core.utils.copyToClipboard
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingAction
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||
@ -70,6 +70,7 @@ class RoomProfileFragment @Inject constructor(
|
||||
private val roomProfileController: RoomProfileController,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
|
||||
private val features: VectorFeatures
|
||||
) :
|
||||
VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
||||
RoomProfileController.Callback {
|
||||
@ -258,12 +259,15 @@ class RoomProfileFragment @Inject constructor(
|
||||
}
|
||||
|
||||
override fun onNotificationsClicked() {
|
||||
if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) {
|
||||
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings)
|
||||
} else {
|
||||
RoomListQuickActionsBottomSheet
|
||||
.newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
|
||||
.show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
|
||||
when (features.notificationSettingsVersion()) {
|
||||
VectorFeatures.NotificationSettingsVersion.V1 -> {
|
||||
RoomListQuickActionsBottomSheet
|
||||
.newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
|
||||
.show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
|
||||
}
|
||||
VectorFeatures.NotificationSettingsVersion.V2 -> {
|
||||
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,9 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||
const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY"
|
||||
|
||||
const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY"
|
||||
const val SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY"
|
||||
const val SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY"
|
||||
const val SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY"
|
||||
const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
|
||||
const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
|
||||
const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY"
|
||||
|
@ -40,6 +40,7 @@ import im.vector.app.core.pushers.PushersManager
|
||||
import im.vector.app.core.services.GuardServiceStarter
|
||||
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
||||
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.settings.BackgroundSyncMode
|
||||
import im.vector.app.features.settings.BackgroundSyncModeChooserDialog
|
||||
@ -63,7 +64,8 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
||||
private val pushManager: PushersManager,
|
||||
private val activeSessionHolder: ActiveSessionHolder,
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val guardServiceStarter: GuardServiceStarter
|
||||
private val guardServiceStarter: GuardServiceStarter,
|
||||
private val features: VectorFeatures
|
||||
) : VectorSettingsBaseFragment(),
|
||||
BackgroundSyncModeChooserDialog.InteractionListener {
|
||||
|
||||
@ -145,6 +147,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
||||
refreshBackgroundSyncPrefs()
|
||||
|
||||
handleSystemPreference()
|
||||
handleVersionedSettings()
|
||||
}
|
||||
|
||||
private fun bindEmailNotifications() {
|
||||
@ -309,6 +312,15 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleVersionedSettings() {
|
||||
val isNotificationSettingsV2Enabled = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2
|
||||
|
||||
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY)?.isVisible = !isNotificationSettingsV2Enabled
|
||||
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
|
||||
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
|
||||
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
activeSessionHolder.getSafeActiveSession()?.refreshPushers()
|
||||
|
@ -26,38 +26,34 @@
|
||||
android:persistent="false"
|
||||
android:summary="@string/settings_notification_advanced_summary"
|
||||
android:title="@string/settings_notification_advanced"
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment"
|
||||
app:isPreferenceVisible="@bool/useNotificationSettingsV1" />
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
|
||||
android:key="SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY"
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_notification_default"
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsDefaultNotificationPreferenceFragment"
|
||||
app:isPreferenceVisible="@bool/useNotificationSettingsV2"/>
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsDefaultNotificationPreferenceFragment" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
|
||||
android:key="SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY"
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_notification_mentions_and_keywords"
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsKeywordAndMentionsNotificationPreferenceFragment"
|
||||
app:isPreferenceVisible="@bool/useNotificationSettingsV2"/>
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsKeywordAndMentionsNotificationPreferenceFragment" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
|
||||
android:key="SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY"
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_notification_other"
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsOtherNotificationPreferenceFragment"
|
||||
app:isPreferenceVisible="@bool/useNotificationSettingsV2"/>
|
||||
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsOtherNotificationPreferenceFragment" />
|
||||
|
||||
</im.vector.app.core.preference.VectorPreferenceCategory>
|
||||
|
||||
<im.vector.app.core.preference.VectorPreferenceCategory
|
||||
android:key="SETTINGS_EMAIL_NOTIFICATION_CATEGORY_PREFERENCE_KEY"
|
||||
android:title="@string/settings_notification_emails_category"/>
|
||||
android:title="@string/settings_notification_emails_category" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreferenceCategory
|
||||
android:persistent="false"
|
||||
@ -103,14 +99,14 @@
|
||||
|
||||
<im.vector.app.core.preference.VectorEditTextPreference
|
||||
android:inputType="numberDecimal"
|
||||
android:persistent="false"
|
||||
android:key="SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY"
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_set_sync_delay" />
|
||||
|
||||
<im.vector.app.core.preference.VectorEditTextPreference
|
||||
android:inputType="numberDecimal"
|
||||
android:persistent="false"
|
||||
android:key="SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY"
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_set_sync_timeout" />
|
||||
|
||||
<im.vector.app.core.preference.VectorSwitchPreference
|
||||
|
Loading…
Reference in New Issue
Block a user