forked from GitHub-Mirror/riotX-android
Merge branch 'feature/Perf' into develop
This commit is contained in:
@ -86,7 +86,7 @@ static def gitRevisionDate() {
|
||||
dependencies {
|
||||
|
||||
def arrow_version = "0.8.0"
|
||||
def support_version = '1.1.0-alpha03'
|
||||
def support_version = '1.1.0-beta01'
|
||||
def moshi_version = '1.8.0'
|
||||
def lifecycle_version = '2.0.0'
|
||||
def coroutines_version = "1.0.1"
|
||||
@ -98,8 +98,8 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$support_version"
|
||||
implementation "androidx.recyclerview:recyclerview:$support_version"
|
||||
implementation "androidx.appcompat:appcompat:1.1.0-beta01"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0-alpha06"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
|
||||
@ -107,7 +107,7 @@ dependencies {
|
||||
// Network
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.14.1'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
|
||||
implementation 'com.novoda:merlin:1.1.6'
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
|
||||
@ -120,7 +120,7 @@ dependencies {
|
||||
kapt 'dk.ilios:realmfieldnameshelper:1.1.1'
|
||||
|
||||
// Work
|
||||
implementation "androidx.work:work-runtime-ktx:2.1.0-beta01"
|
||||
implementation "androidx.work:work-runtime-ktx:2.1.0-rc01"
|
||||
|
||||
// FP
|
||||
implementation "io.arrow-kt:arrow-core:$arrow_version"
|
||||
@ -155,11 +155,11 @@ dependencies {
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
|
||||
androidTestImplementation "org.koin:koin-test:$koin_version"
|
||||
androidTestImplementation 'androidx.test:core:1.1.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||
androidTestImplementation 'androidx.test:rules:1.1.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
|
||||
androidTestImplementation "io.mockk:mockk-android:1.8.13.kotlin13"
|
||||
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
|
||||
|
@ -47,8 +47,8 @@ interface Room :
|
||||
* A live [RoomSummary] associated with the room
|
||||
* You can observe this summary to get dynamic data from this room.
|
||||
*/
|
||||
val liveRoomSummary: LiveData<RoomSummary>
|
||||
fun liveRoomSummary(fetchLastEvent: Boolean = false): LiveData<RoomSummary>
|
||||
|
||||
val roomSummary: RoomSummary?
|
||||
fun roomSummary(fetchLastEvent: Boolean = false): RoomSummary?
|
||||
|
||||
}
|
@ -43,6 +43,6 @@ interface RoomService {
|
||||
* Get a live list of room summaries. This list is refreshed as soon as the data changes.
|
||||
* @return the [LiveData] of [RoomSummary]
|
||||
*/
|
||||
fun liveRoomSummaries(): LiveData<List<RoomSummary>>
|
||||
fun liveRoomSummaries(fetchLastEvents: Boolean = true): LiveData<List<RoomSummary>>
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ import android.text.TextUtils
|
||||
import arrow.core.Try
|
||||
import com.squareup.moshi.Types
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import dagger.Lazy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
@ -98,7 +99,7 @@ internal class CryptoManager @Inject constructor(
|
||||
private val olmManager: OlmManager,
|
||||
// The credentials,
|
||||
private val credentials: Credentials,
|
||||
private val myDeviceInfoHolder: MyDeviceInfoHolder,
|
||||
private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
|
||||
// the crypto store
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
// Olm device
|
||||
@ -190,7 +191,7 @@ internal class CryptoManager @Inject constructor(
|
||||
}
|
||||
|
||||
override fun getMyDevice(): MXDeviceInfo {
|
||||
return myDeviceInfoHolder.myDevice
|
||||
return myDeviceInfoHolder.get().myDevice
|
||||
}
|
||||
|
||||
override fun getDevicesList(callback: MatrixCallback<DevicesListResponse>) {
|
||||
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.crypto.verification
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import dagger.Lazy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||
@ -55,7 +56,7 @@ import kotlin.collections.HashMap
|
||||
@SessionScope
|
||||
internal class DefaultSasVerificationService @Inject constructor(private val credentials: Credentials,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val myDeviceInfoHolder: MyDeviceInfoHolder,
|
||||
private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val sendToDeviceTask: SendToDeviceTask,
|
||||
@ -197,7 +198,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
|
||||
cryptoStore,
|
||||
sendToDeviceTask,
|
||||
taskExecutor,
|
||||
myDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
startReq.transactionID!!,
|
||||
otherUserId)
|
||||
addTransaction(tx)
|
||||
@ -366,7 +367,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
|
||||
cryptoStore,
|
||||
sendToDeviceTask,
|
||||
taskExecutor,
|
||||
myDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
txID,
|
||||
userId,
|
||||
deviceID)
|
||||
|
@ -16,29 +16,24 @@
|
||||
|
||||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomSummaryMapper @Inject constructor(private val timelineEventFactory: TimelineEventFactory) {
|
||||
|
||||
internal class RoomSummaryMapper @Inject constructor(
|
||||
private val timelineEventFactory: TimelineEventFactory,
|
||||
private val monarchy: Monarchy) {
|
||||
|
||||
fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
||||
fun map(roomSummaryEntity: RoomSummaryEntity, getLatestEvent: Boolean = false): RoomSummary {
|
||||
val tags = roomSummaryEntity.tags.map {
|
||||
RoomTag(it.tagName, it.tagOrder)
|
||||
}
|
||||
val latestEvent = roomSummaryEntity.latestEvent?.let {
|
||||
var ev: TimelineEvent? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
ev = timelineEventFactory.create(it, realm)
|
||||
val latestEvent = if (getLatestEvent) {
|
||||
roomSummaryEntity.latestEvent?.let {
|
||||
timelineEventFactory.create(it, it.realm)
|
||||
}
|
||||
ev
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return RoomSummary(
|
||||
roomId = roomSummaryEntity.roomId,
|
||||
|
@ -48,58 +48,7 @@ internal class DefaultPushRuleService @Inject constructor(
|
||||
|
||||
override fun fetchPushRules(scope: String) {
|
||||
pushRulesTask
|
||||
.configureWith(Unit)
|
||||
.dispatchTo(object : MatrixCallback<GetPushRulesResponse> {
|
||||
override fun onSuccess(data: GetPushRulesResponse) {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
//clear existings?
|
||||
//TODO
|
||||
realm.where(PushRulesEntity::class.java)
|
||||
.equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId)
|
||||
.findAll().deleteAllFromRealm()
|
||||
|
||||
val content = PushRulesEntity(sessionParams.credentials.userId, scope, "content")
|
||||
data.global.content?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
content.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(content)
|
||||
|
||||
val override = PushRulesEntity(sessionParams.credentials.userId, scope, "override")
|
||||
data.global.override?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
override.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(override)
|
||||
|
||||
val rooms = PushRulesEntity(sessionParams.credentials.userId, scope, "room")
|
||||
data.global.room?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
rooms.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(rooms)
|
||||
|
||||
val senders = PushRulesEntity(sessionParams.credentials.userId, scope, "sender")
|
||||
data.global.sender?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
senders.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(senders)
|
||||
|
||||
val underrides = PushRulesEntity(sessionParams.credentials.userId, scope, "underride")
|
||||
data.global.underride?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
underrides.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(underrides)
|
||||
}
|
||||
}
|
||||
})
|
||||
.configureWith(GetPushRulesTask.Params(scope))
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
|
@ -54,22 +54,6 @@ internal class DefaultPusherService @Inject constructor(
|
||||
override fun refreshPushers() {
|
||||
getPusherTask
|
||||
.configureWith(Unit)
|
||||
.dispatchTo(object : MatrixCallback<GetPushersResponse> {
|
||||
override fun onSuccess(data: GetPushersResponse) {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
//clear existings?
|
||||
realm.where(PusherEntity::class.java)
|
||||
.equalTo(PusherEntityFields.USER_ID, sessionParam.credentials.userId)
|
||||
.findAll().deleteAllFromRealm()
|
||||
data.pushers?.forEach { jsonPusher ->
|
||||
jsonPusher.toEntity(sessionParam.credentials.userId).also {
|
||||
it.state = PusherState.REGISTERED
|
||||
realm.insertOrUpdate(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
|
@ -16,19 +16,81 @@
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import arrow.core.Try
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
|
||||
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
internal interface GetPushRulesTask : Task<Unit, GetPushRulesResponse>
|
||||
internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> {
|
||||
|
||||
internal class DefaultGetPushRulesTask @Inject constructor(private val pushRulesApi: PushRulesApi) : GetPushRulesTask {
|
||||
data class Params(val scope: String)
|
||||
|
||||
override suspend fun execute(params: Unit): Try<GetPushRulesResponse> {
|
||||
return executeRequest {
|
||||
}
|
||||
|
||||
|
||||
internal class DefaultGetPushRulesTask @Inject constructor(private val pushRulesApi: PushRulesApi,
|
||||
private val monarchy: Monarchy,
|
||||
private val sessionParams: SessionParams) : GetPushRulesTask {
|
||||
|
||||
override suspend fun execute(params: GetPushRulesTask.Params): Try<Unit> {
|
||||
return executeRequest<GetPushRulesResponse> {
|
||||
apiCall = pushRulesApi.getAllRules()
|
||||
}.flatMap { response ->
|
||||
val scope = params.scope
|
||||
return monarchy.tryTransactionSync { realm ->
|
||||
//clear existings?
|
||||
//TODO
|
||||
realm.where(PushRulesEntity::class.java)
|
||||
.equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId)
|
||||
.findAll().deleteAllFromRealm()
|
||||
|
||||
val content = PushRulesEntity(sessionParams.credentials.userId, scope, "content")
|
||||
response.global.content?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
content.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(content)
|
||||
|
||||
val override = PushRulesEntity(sessionParams.credentials.userId, scope, "override")
|
||||
response.global.override?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
override.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(override)
|
||||
|
||||
val rooms = PushRulesEntity(sessionParams.credentials.userId, scope, "room")
|
||||
response.global.room?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
rooms.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(rooms)
|
||||
|
||||
val senders = PushRulesEntity(sessionParams.credentials.userId, scope, "sender")
|
||||
response.global.sender?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
senders.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(senders)
|
||||
|
||||
val underrides = PushRulesEntity(sessionParams.credentials.userId, scope, "underride")
|
||||
response.global.underride?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
underrides.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(underrides)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,17 +16,39 @@
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import arrow.core.Try
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.pushers.PusherState
|
||||
import im.vector.matrix.android.internal.database.mapper.toEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetPushersTask : Task<Unit, GetPushersResponse>
|
||||
internal interface GetPushersTask : Task<Unit, Unit>
|
||||
|
||||
internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: PushersAPI) : GetPushersTask {
|
||||
internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: PushersAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val sessionParams: SessionParams) : GetPushersTask {
|
||||
|
||||
override suspend fun execute(params: Unit): Try<GetPushersResponse> {
|
||||
return executeRequest {
|
||||
override suspend fun execute(params: Unit): Try<Unit> {
|
||||
return executeRequest<GetPushersResponse> {
|
||||
apiCall = pushersAPI.getPushers()
|
||||
}.flatMap { response ->
|
||||
monarchy.tryTransactionSync { realm ->
|
||||
//clear existings?
|
||||
realm.where(PusherEntity::class.java)
|
||||
.equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId)
|
||||
.findAll().deleteAllFromRealm()
|
||||
response.pushers?.forEach { jsonPusher ->
|
||||
jsonPusher.toEntity(sessionParams.credentials.userId).also {
|
||||
it.state = PusherState.REGISTERED
|
||||
realm.insertOrUpdate(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.util.fetchCopied
|
||||
import im.vector.matrix.android.internal.util.fetchCopyMap
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
@ -47,19 +48,19 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
private val relationService: RelationService,
|
||||
private val roomMembersService: MembershipService
|
||||
) : Room,
|
||||
TimelineService by timelineService,
|
||||
SendService by sendService,
|
||||
StateService by stateService,
|
||||
ReadService by readService,
|
||||
RelationService by relationService,
|
||||
MembershipService by roomMembersService {
|
||||
TimelineService by timelineService,
|
||||
SendService by sendService,
|
||||
StateService by stateService,
|
||||
ReadService by readService,
|
||||
RelationService by relationService,
|
||||
MembershipService by roomMembersService {
|
||||
|
||||
override val liveRoomSummary: LiveData<RoomSummary> by lazy {
|
||||
override fun liveRoomSummary(fetchLastEvent: Boolean): LiveData<RoomSummary> {
|
||||
val liveRealmData = RealmLiveData<RoomSummaryEntity>(monarchy.realmConfiguration) { realm ->
|
||||
RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME)
|
||||
}
|
||||
Transformations.map(liveRealmData) { results ->
|
||||
val roomSummaries = results.map { roomSummaryMapper.map(it) }
|
||||
return Transformations.map(liveRealmData) { results ->
|
||||
val roomSummaries = results.map { roomSummaryMapper.map(it, fetchLastEvent) }
|
||||
|
||||
if (roomSummaries.isEmpty()) {
|
||||
// Create a dummy RoomSummary to avoid Crash during Sign Out or clear cache
|
||||
@ -70,11 +71,12 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
}
|
||||
}
|
||||
|
||||
override val roomSummary: RoomSummary?
|
||||
get() {
|
||||
var sum: RoomSummaryEntity? = monarchy.fetchCopied { RoomSummaryEntity.where(it, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME).findFirst() }
|
||||
return sum?.let { roomSummaryMapper.map(it) }
|
||||
}
|
||||
override fun roomSummary(fetchLastEvent: Boolean): RoomSummary? {
|
||||
return monarchy.fetchAllMappedSync(
|
||||
{ realm -> RoomSummaryEntity.where(realm).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
|
||||
{ roomSummaryMapper.map(it, fetchLastEvent) }
|
||||
).firstOrNull()
|
||||
}
|
||||
|
||||
override fun isEncrypted(): Boolean {
|
||||
return cryptoService.isRoomEncrypted(roomId)
|
||||
|
@ -52,10 +52,10 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
||||
return roomFactory.create(roomId)
|
||||
}
|
||||
|
||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||
override fun liveRoomSummaries(fetchLastEvents: Boolean): LiveData<List<RoomSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm -> RoomSummaryEntity.where(realm).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
|
||||
{ roomSummaryMapper.map(it) }
|
||||
{ roomSummaryMapper.map(it, fetchLastEvents) }
|
||||
)
|
||||
}
|
||||
}
|
@ -30,7 +30,12 @@ import im.vector.matrix.android.api.util.addTo
|
||||
import im.vector.matrix.android.internal.crypto.NewSessionListener
|
||||
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.*
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.findIncludingEvent
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
@ -38,7 +43,13 @@ import im.vector.matrix.android.internal.database.query.whereInRoom
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.Debouncer
|
||||
import io.realm.*
|
||||
import io.realm.OrderedCollectionChangeSet
|
||||
import io.realm.OrderedRealmCollectionChangeListener
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.RealmResults
|
||||
import io.realm.Sort
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
@ -50,7 +61,6 @@ import kotlin.collections.HashMap
|
||||
private const val INITIAL_LOAD_SIZE = 20
|
||||
private const val MIN_FETCHING_COUNT = 30
|
||||
private const val DISPLAY_INDEX_UNKNOWN = Int.MIN_VALUE
|
||||
private const val THREAD_NAME = "TIMELINE_DB_THREAD"
|
||||
|
||||
internal class DefaultTimeline(
|
||||
private val roomId: String,
|
||||
@ -64,18 +74,22 @@ internal class DefaultTimeline(
|
||||
private val allowedTypes: List<String>?
|
||||
) : Timeline {
|
||||
|
||||
private companion object {
|
||||
val BACKGROUND_HANDLER = Handler(
|
||||
HandlerThread("TIMELINE_DB_THREAD").apply { start() }.looper
|
||||
)
|
||||
}
|
||||
|
||||
override var listener: Timeline.Listener? = null
|
||||
set(value) {
|
||||
field = value
|
||||
backgroundHandler.get()?.post {
|
||||
BACKGROUND_HANDLER.post {
|
||||
postSnapshot()
|
||||
}
|
||||
}
|
||||
|
||||
private val isStarted = AtomicBoolean(false)
|
||||
private val isReady = AtomicBoolean(false)
|
||||
private val backgroundHandlerThread = AtomicReference<HandlerThread>()
|
||||
private val backgroundHandler = AtomicReference<Handler>()
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
private val backgroundRealm = AtomicReference<Realm>()
|
||||
private val cancelableBag = CancelableBag()
|
||||
@ -168,14 +182,14 @@ internal class DefaultTimeline(
|
||||
override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
|
||||
if (roomId == this@DefaultTimeline.roomId) {
|
||||
Timber.v("New session id detected for this room")
|
||||
backgroundHandler.get()?.post {
|
||||
BACKGROUND_HANDLER.post {
|
||||
val realm = backgroundRealm.get()
|
||||
var hasChange = false
|
||||
builtEvents.forEachIndexed { index, timelineEvent ->
|
||||
if (timelineEvent.isEncrypted()) {
|
||||
val eventContent = timelineEvent.root.content.toModel<EncryptedEventContent>()
|
||||
if (eventContent?.sessionId == sessionId
|
||||
&& (timelineEvent.root.mClearEvent == null || timelineEvent.root.mCryptoError != null)) {
|
||||
&& (timelineEvent.root.mClearEvent == null || timelineEvent.root.mCryptoError != null)) {
|
||||
//we need to rebuild this event
|
||||
EventEntity.where(realm, eventId = timelineEvent.root.eventId!!).findFirst()?.let {
|
||||
builtEvents[index] = timelineEventFactory.create(it, realm)
|
||||
@ -194,7 +208,7 @@ internal class DefaultTimeline(
|
||||
// Public methods ******************************************************************************
|
||||
|
||||
override fun paginate(direction: Timeline.Direction, count: Int) {
|
||||
backgroundHandler.get()?.post {
|
||||
BACKGROUND_HANDLER.post {
|
||||
if (!canPaginate(direction)) {
|
||||
return@post
|
||||
}
|
||||
@ -211,13 +225,8 @@ internal class DefaultTimeline(
|
||||
override fun start() {
|
||||
if (isStarted.compareAndSet(false, true)) {
|
||||
Timber.v("Start timeline for roomId: $roomId and eventId: $initialEventId")
|
||||
val handlerThread = HandlerThread(THREAD_NAME + hashCode())
|
||||
handlerThread.start()
|
||||
val handler = Handler(handlerThread.looper)
|
||||
this.backgroundHandlerThread.set(handlerThread)
|
||||
this.backgroundHandler.set(handler)
|
||||
cryptoService.addNewSessionListener(newSessionListener)
|
||||
handler.post {
|
||||
BACKGROUND_HANDLER.post {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
backgroundRealm.set(realm)
|
||||
clearUnlinkedEvents(realm)
|
||||
@ -246,14 +255,12 @@ internal class DefaultTimeline(
|
||||
if (isStarted.compareAndSet(true, false)) {
|
||||
cryptoService.removeSessionListener(newSessionListener)
|
||||
Timber.v("Dispose timeline for roomId: $roomId and eventId: $initialEventId")
|
||||
backgroundHandler.get()?.post {
|
||||
BACKGROUND_HANDLER.post {
|
||||
cancelableBag.cancel()
|
||||
liveEvents.removeAllChangeListeners()
|
||||
backgroundRealm.getAndSet(null).also {
|
||||
it.close()
|
||||
}
|
||||
backgroundHandler.set(null)
|
||||
backgroundHandlerThread.getAndSet(null)?.quit()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -387,9 +394,9 @@ internal class DefaultTimeline(
|
||||
private fun executePaginationTask(direction: Timeline.Direction, limit: Int) {
|
||||
val token = getTokenLive(direction) ?: return
|
||||
val params = PaginationTask.Params(roomId = roomId,
|
||||
from = token,
|
||||
direction = direction.toPaginationDirection(),
|
||||
limit = limit)
|
||||
from = token,
|
||||
direction = direction.toPaginationDirection(),
|
||||
limit = limit)
|
||||
|
||||
Timber.v("Should fetch $limit items $direction")
|
||||
paginationTask.configureWith(params)
|
||||
@ -400,7 +407,7 @@ internal class DefaultTimeline(
|
||||
Timber.v("Success fetching $limit items $direction from pagination request")
|
||||
} else {
|
||||
// Database won't be updated, so we force pagination request
|
||||
backgroundHandler.get()?.post {
|
||||
BACKGROUND_HANDLER.post {
|
||||
executePaginationTask(direction, limit)
|
||||
}
|
||||
}
|
||||
@ -441,6 +448,7 @@ internal class DefaultTimeline(
|
||||
if (count < 1) {
|
||||
return 0
|
||||
}
|
||||
val start = System.currentTimeMillis()
|
||||
val offsetResults = getOffsetResults(startDisplayIndex, direction, count)
|
||||
if (offsetResults.isEmpty()) {
|
||||
return 0
|
||||
@ -459,7 +467,8 @@ internal class DefaultTimeline(
|
||||
builtEventsIdMap.entries.filter { it.value >= position }.forEach { it.setValue(it.value + 1) }
|
||||
builtEventsIdMap[eventEntity.eventId] = position
|
||||
}
|
||||
Timber.v("Built ${offsetResults.size} items from db")
|
||||
val time = System.currentTimeMillis() - start
|
||||
Timber.v("Built ${offsetResults.size} items from db in $time ms")
|
||||
return offsetResults.size
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ internal class SimpleTimelineEventFactory @Inject constructor(private val roomMe
|
||||
val result = cryptoService.decryptEvent(event, UUID.randomUUID().toString())
|
||||
event.setClearData(result)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Encrypted event: decryption failed")
|
||||
Timber.e("Encrypted event: decryption failed")
|
||||
if (failure is MXDecryptionException) {
|
||||
event.setCryptoError(failure.cryptoError)
|
||||
}
|
||||
|
Reference in New Issue
Block a user