From f1d902b9ad27a785112ba22f8f770796b472758d Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 1 Sep 2020 19:36:50 +0200 Subject: [PATCH] Enable strict mode and remove some stuff from the main thread --- .../internal/database/RealmInstanceWrapper.kt | 35 +++++++++ .../internal/database/RealmSessionProvider.kt | 72 +++++++++++++++++++ .../mapper/ReadReceiptsSummaryMapper.kt | 10 ++- .../sdk/internal/session/SessionModule.kt | 5 ++ .../sdk/internal/session/room/RoomGetter.kt | 11 ++- .../room/state/StateEventDataSource.kt | 14 ++-- .../session/room/timeline/DefaultTimeline.kt | 10 +-- .../room/timeline/DefaultTimelineService.kt | 26 +++---- .../internal/session/user/UserDataSource.kt | 15 ++-- .../user/accountdata/AccountDataDataSource.kt | 15 ++-- .../session/widgets/helper/WidgetFactory.kt | 10 ++- .../java/im/vector/app/VectorApplication.kt | 8 +++ .../app/core/glide/VectorGlideModelLoader.kt | 2 +- .../home/room/detail/RoomDetailViewModel.kt | 16 +++-- .../timeline/item/MessageImageVideoItem.kt | 2 +- .../features/media/ImageContentRenderer.kt | 10 ++- .../features/rageshake/VectorFileLogger.kt | 19 +++-- .../members/RoomMemberListViewModel.kt | 16 ++--- .../vector/app/features/themes/ThemeUtils.kt | 16 ++++- 19 files changed, 225 insertions(+), 87 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt new file mode 100644 index 0000000000..851605437f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstanceWrapper.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database + +import io.realm.Realm +import java.io.Closeable + +class RealmInstanceWrapper(private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable { + + override fun close() { + if (closeRealmOnClose) { + realm.close() + } + } + + fun withRealm(block: (Realm) -> R): R { + return use { + block(it.realm) + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt new file mode 100644 index 0000000000..a232d83b6d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionProvider.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database + +import android.os.Looper +import androidx.annotation.MainThread +import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.session.SessionLifecycleObserver +import org.matrix.android.sdk.internal.session.SessionScope +import javax.inject.Inject +import kotlin.concurrent.getOrSet + +/** + * This class keeps an instance of realm open in the main thread so you can grab it whenever you want to get a realm + * instance. This does check each time if you are on the main thread or not and returns the appropriate realm instance. + */ +@SessionScope +class RealmSessionProvider @Inject constructor(@SessionDatabase private val monarchy: Monarchy) + : SessionLifecycleObserver { + + private val realmThreadLocal = ThreadLocal() + + /** + * Allow you to execute a block with an opened realm. It automatically closes it if necessary (ie. when not in main thread) + */ + fun withRealm(block: (Realm) -> R): R { + return getRealmWrapper().withRealm(block) + } + + @MainThread + override fun onStart() { + realmThreadLocal.getOrSet { + Realm.getInstance(monarchy.realmConfiguration) + } + } + + @MainThread + override fun onStop() { + realmThreadLocal.get()?.close() + realmThreadLocal.remove() + } + + private fun getRealmWrapper(): RealmInstanceWrapper { + val isOnMainThread = isOnMainThread() + val realm = if (isOnMainThread) { + realmThreadLocal.getOrSet { + Realm.getInstance(monarchy.realmConfiguration) + } + } else { + Realm.getInstance(monarchy.realmConfiguration) + } + return RealmInstanceWrapper(realm, closeRealmOnClose = !isOnMainThread) + } + + private fun isOnMainThread() = Looper.myLooper() == Looper.getMainLooper() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt index 188ca4937c..6b9c0e7a45 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/ReadReceiptsSummaryMapper.kt @@ -18,26 +18,24 @@ package org.matrix.android.sdk.internal.database.mapper import org.matrix.android.sdk.api.session.room.model.ReadReceipt +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity import org.matrix.android.sdk.internal.database.model.UserEntity import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.di.SessionDatabase -import io.realm.Realm -import io.realm.RealmConfiguration import javax.inject.Inject -internal class ReadReceiptsSummaryMapper @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration) { +internal class ReadReceiptsSummaryMapper @Inject constructor(private val realmSessionProvider: RealmSessionProvider) { fun map(readReceiptsSummaryEntity: ReadReceiptsSummaryEntity?): List { if (readReceiptsSummaryEntity == null) { return emptyList() } - return Realm.getInstance(realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> val readReceipts = readReceiptsSummaryEntity.readReceipts readReceipts .mapNotNull { val user = UserEntity.where(realm, it.userId).findFirst() - ?: return@mapNotNull null + ?: return@mapNotNull null ReadReceipt(user.asDomain(), it.originServerTs.toLong()) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index d404cecc51..e2042bfeac 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorage import org.matrix.android.sdk.internal.crypto.verification.VerificationMessageProcessor import org.matrix.android.sdk.internal.database.DatabaseCleaner import org.matrix.android.sdk.internal.database.EventInsertLiveObserver +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.SessionRealmConfigurationFactory import org.matrix.android.sdk.internal.di.Authenticated import org.matrix.android.sdk.internal.di.DeviceId @@ -343,6 +344,10 @@ internal abstract class SessionModule { @IntoSet abstract fun bindDatabaseCleaner(observer: DatabaseCleaner): SessionLifecycleObserver + @Binds + @IntoSet + abstract fun bindRealmSessionProvider(observer: RealmSessionProvider): SessionLifecycleObserver + @Binds abstract fun bindInitialSyncProgressService(service: DefaultInitialSyncProgressService): InitialSyncProgressService diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt index 38dcad2311..985cf80e97 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomGetter.kt @@ -17,17 +17,16 @@ package org.matrix.android.sdk.internal.session.room -import com.zhuinden.monarchy.Monarchy +import io.realm.Realm import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper -import io.realm.Realm import javax.inject.Inject internal interface RoomGetter { @@ -38,18 +37,18 @@ internal interface RoomGetter { @SessionScope internal class DefaultRoomGetter @Inject constructor( - @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val roomFactory: RoomFactory ) : RoomGetter { override fun getRoom(roomId: String): Room? { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> createRoom(realm, roomId) } } override fun getDirectRoomWith(otherUserId: String): Room? { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> RoomSummaryEntity.where(realm) .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) .equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt index e8dc2ddf40..65d30868d8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt @@ -20,24 +20,26 @@ package org.matrix.android.sdk.internal.session.room.state import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.RealmQuery +import io.realm.kotlin.where import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.query.process -import io.realm.Realm -import io.realm.RealmQuery -import io.realm.kotlin.where import javax.inject.Inject -internal class StateEventDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy) { +internal class StateEventDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider) { fun getStateEvent(roomId: String, eventType: String, stateKey: QueryStringValue): Event? { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> buildStateEventQuery(realm, roomId, setOf(eventType), stateKey).findFirst()?.root?.asDomain() } } @@ -53,7 +55,7 @@ internal class StateEventDataSource @Inject constructor(@SessionDatabase private } fun getStateEvents(roomId: String, eventTypes: Set, stateKey: QueryStringValue): List { - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return realmSessionProvider.withRealm { realm -> buildStateEventQuery(realm, roomId, eventTypes, stateKey) .findAll() .mapNotNull { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 421cd1b063..52651af881 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -39,6 +39,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.util.CancelableBag +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntityFields @@ -76,7 +77,8 @@ internal class DefaultTimeline( private val settings: TimelineSettings, private val hiddenReadReceipts: TimelineHiddenReadReceipts, private val eventBus: EventBus, - private val eventDecryptor: TimelineEventDecryptor + private val eventDecryptor: TimelineEventDecryptor, + private val realmSessionProvider: RealmSessionProvider ) : Timeline, TimelineHiddenReadReceipts.Delegate { data class OnNewTimelineEvents(val roomId: String, val eventIds: List) @@ -136,13 +138,13 @@ internal class DefaultTimeline( } override fun pendingEventCount(): Int { - return Realm.getInstance(realmConfiguration).use { + return realmSessionProvider.withRealm { RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.count() ?: 0 } } override fun failedToDeliverEventCount(): Int { - return Realm.getInstance(realmConfiguration).use { + return realmSessionProvider.withRealm { TimelineEventEntity.findAllInRoomWithSendStates(it, roomId, SendState.HAS_FAILED_STATES).count() } } @@ -239,7 +241,7 @@ internal class DefaultTimeline( return eventId } // Otherwise, we should check if the event is in the db, but is hidden because of filters - return Realm.getInstance(realmConfiguration).use { localRealm -> + return realmSessionProvider.withRealm { localRealm -> val nonFilteredEvents = buildEventQuery(localRealm) .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING) .findAll() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt index db675f69f5..c60a944409 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt @@ -22,6 +22,9 @@ import androidx.lifecycle.Transformations import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import com.zhuinden.monarchy.Monarchy +import io.realm.Sort +import io.realm.kotlin.where +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.isImageMessage import org.matrix.android.sdk.api.session.events.model.isVideoMessage import org.matrix.android.sdk.api.session.room.timeline.Timeline @@ -30,7 +33,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.internal.crypto.store.db.doWithRealm +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.ReadReceiptsSummaryMapper import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.model.TimelineEventEntity @@ -38,13 +41,10 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.util.fetchCopyMap -import io.realm.Sort -import io.realm.kotlin.where -import org.greenrobot.eventbus.EventBus internal class DefaultTimelineService @AssistedInject constructor(@Assisted private val roomId: String, @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val eventBus: EventBus, private val taskExecutor: TaskExecutor, private val contextOfEventTask: GetContextOfEventTask, @@ -73,17 +73,17 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings), eventBus = eventBus, eventDecryptor = eventDecryptor, - fetchTokenAndPaginateTask = fetchTokenAndPaginateTask + fetchTokenAndPaginateTask = fetchTokenAndPaginateTask, + realmSessionProvider = realmSessionProvider ) } override fun getTimeLineEvent(eventId: String): TimelineEvent? { - return monarchy - .fetchCopyMap({ - TimelineEventEntity.where(it, roomId = roomId, eventId = eventId).findFirst() - }, { entity, _ -> - timelineEventMapper.map(entity) - }) + return realmSessionProvider.withRealm { realm -> + TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst()?.let { + timelineEventMapper.map(it) + } + } } override fun getTimeLineEventLive(eventId: String): LiveData> { @@ -98,7 +98,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv override fun getAttachmentMessages(): List { // TODO pretty bad query.. maybe we should denormalize clear type in base? - return doWithRealm(monarchy.realmConfiguration) { realm -> + return realmSessionProvider.withRealm { realm -> realm.where() .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt index dd3c6856c0..f6cb86c0ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt @@ -23,9 +23,11 @@ import androidx.paging.DataSource import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList import com.zhuinden.monarchy.Monarchy +import io.realm.Case import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.IgnoredUserEntity import org.matrix.android.sdk.internal.database.model.IgnoredUserEntityFields @@ -33,11 +35,10 @@ import org.matrix.android.sdk.internal.database.model.UserEntity import org.matrix.android.sdk.internal.database.model.UserEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.internal.util.fetchCopied -import io.realm.Case import javax.inject.Inject -internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy) { +internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider) { private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory by lazy { monarchy.createDataSourceFactory { realm -> @@ -58,10 +59,10 @@ internal class UserDataSource @Inject constructor(@SessionDatabase private val m } fun getUser(userId: String): User? { - val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() } - ?: return null - - return userEntity.asDomain() + return realmSessionProvider.withRealm { + val userEntity = UserEntity.where(it, userId).findFirst() + userEntity?.asDomain() + } } fun getUserLive(userId: String): LiveData> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt index d54bfdd63d..a9261eddab 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataDataSource.kt @@ -20,18 +20,20 @@ package org.matrix.android.sdk.internal.session.user.accountdata import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.RealmQuery +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.mapper.AccountDataMapper import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields import org.matrix.android.sdk.internal.di.SessionDatabase -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent -import io.realm.Realm -import io.realm.RealmQuery import javax.inject.Inject internal class AccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, private val accountDataMapper: AccountDataMapper) { fun getAccountDataEvent(type: String): UserAccountDataEvent? { @@ -45,10 +47,9 @@ internal class AccountDataDataSource @Inject constructor(@SessionDatabase privat } fun getAccountDataEvents(types: Set): List { - return monarchy.fetchAllMappedSync( - { accountDataEventsQuery(it, types) }, - accountDataMapper::map - ) + return realmSessionProvider.withRealm { + accountDataEventsQuery(it, types).findAll().map(accountDataMapper::map) + } } fun getLiveAccountDataEvents(types: Set): LiveData> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt index 2cbc9b23dc..992dbf16df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt @@ -23,17 +23,15 @@ import org.matrix.android.sdk.api.session.room.sender.SenderInfo import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.WidgetContent import org.matrix.android.sdk.api.session.widgets.model.WidgetType -import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.user.UserDataSource -import io.realm.Realm -import io.realm.RealmConfiguration import java.net.URLEncoder import javax.inject.Inject -internal class WidgetFactory @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration, - private val userDataSource: UserDataSource, +internal class WidgetFactory @Inject constructor(private val userDataSource: UserDataSource, + private val realmSessionProvider: RealmSessionProvider, @UserId private val userId: String) { fun create(widgetEvent: Event): Widget? { @@ -44,7 +42,7 @@ internal class WidgetFactory @Inject constructor(@SessionDatabase private val re val senderInfo = if (widgetEvent.senderId == null || widgetEvent.roomId == null) { null } else { - Realm.getInstance(realmConfiguration).use { + realmSessionProvider.withRealm { val roomMemberHelper = RoomMemberHelper(it, widgetEvent.roomId) val roomMemberSummaryEntity = roomMemberHelper.getLastRoomMember(widgetEvent.senderId) SenderInfo( diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index f64ebf9245..bca0a028e9 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.res.Configuration import android.os.Handler import android.os.HandlerThread +import android.os.StrictMode import androidx.core.provider.FontRequest import androidx.core.provider.FontsContractCompat import androidx.lifecycle.Lifecycle @@ -92,6 +93,13 @@ class VectorApplication : private var fontThreadHandler: Handler? = null override fun onCreate() { + if (BuildConfig.DEBUG) { + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyFlashScreen() + .penaltyLog() + .build()) + } super.onCreate() appContext = this vectorComponent = DaggerVectorComponent.factory().create(this) diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 2a17c2ca1b..0eba78dbf8 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -100,7 +100,7 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { Timber.v("Load data: $data") - if (data.isLocalFile() && data.url != null) { + if (data.isLocalFile && data.url != null) { val initialFile = File(data.url) callback.onDataReady(initialFile.inputStream()) return diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index eab0007080..a77d50d767 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -896,13 +896,15 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) { - if (action.event.root.sendState.isSent()) { // ignore pending/local events - visibleEventsObservable.accept(action) - } - // We need to update this with the related m.replace also (to move read receipt) - action.event.annotations?.editSummary?.sourceEvents?.forEach { - room.getTimeLineEvent(it)?.let { event -> - visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event)) + viewModelScope.launch(Dispatchers.Default) { + if (action.event.root.sendState.isSent()) { // ignore pending/local events + visibleEventsObservable.accept(action) + } + // We need to update this with the related m.replace also (to move read receipt) + action.event.annotations?.editSummary?.sourceEvents?.forEach { + room.getTimeLineEvent(it)?.let { event -> + visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event)) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index 9ada087207..ffc51f671f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -50,7 +50,7 @@ abstract class MessageImageVideoItem : AbsMessageItem(null) + private val mColorByAttr = HashMap() // init the theme @@ -68,8 +71,16 @@ object ThemeUtils { * @return the selected application theme */ fun getApplicationTheme(context: Context): String { - return PreferenceManager.getDefaultSharedPreferences(context) - .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE) ?: THEME_LIGHT_VALUE + val currentTheme = this.currentTheme.get() + return if (currentTheme == null) { + val themeFromPref = PreferenceManager + .getDefaultSharedPreferences(context) + .getString(APPLICATION_THEME_KEY, THEME_LIGHT_VALUE) ?: THEME_LIGHT_VALUE + this.currentTheme.set(themeFromPref) + themeFromPref + } else { + currentTheme + } } /** @@ -78,6 +89,7 @@ object ThemeUtils { * @param aTheme the new theme */ fun setApplicationTheme(context: Context, aTheme: String) { + currentTheme.set(aTheme) when (aTheme) { THEME_DARK_VALUE -> context.setTheme(R.style.AppTheme_Dark) THEME_BLACK_VALUE -> context.setTheme(R.style.AppTheme_Black)