Merge pull request #4046 from vector-im/feature/bma/incr_sync_investigation
Incr sync investigation
This commit is contained in:
commit
b52f2b0422
1
changelog.d/4046.feature
Normal file
1
changelog.d/4046.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Push and syncs: add debug info on room list and on room detail screen and improves the log format.
|
1
changelog.d/4046.misc
Normal file
1
changelog.d/4046.misc
Normal file
@ -0,0 +1 @@
|
|||||||
|
InitialSyncProgressService has been renamed to SyncStatusService and its function getInitialSyncProgressStatus() has been renamed to getSyncStatusLive()
|
@ -7,8 +7,8 @@ ext.versions = [
|
|||||||
'targetCompat' : JavaVersion.VERSION_11,
|
'targetCompat' : JavaVersion.VERSION_11,
|
||||||
]
|
]
|
||||||
|
|
||||||
// Ref: https://kotlinlang.org/releases.html
|
|
||||||
def gradle = "7.0.2"
|
def gradle = "7.0.2"
|
||||||
|
// Ref: https://kotlinlang.org/releases.html
|
||||||
def kotlin = "1.5.30"
|
def kotlin = "1.5.30"
|
||||||
def kotlinCoroutines = "1.5.1"
|
def kotlinCoroutines = "1.5.1"
|
||||||
def dagger = "2.38.1"
|
def dagger = "2.38.1"
|
||||||
@ -55,6 +55,8 @@ ext.libs = [
|
|||||||
'lifecycleExtensions' : "androidx.lifecycle:lifecycle-extensions:$lifecycle",
|
'lifecycleExtensions' : "androidx.lifecycle:lifecycle-extensions:$lifecycle",
|
||||||
'lifecycleJava8' : "androidx.lifecycle:lifecycle-common-java8:$lifecycle",
|
'lifecycleJava8' : "androidx.lifecycle:lifecycle-common-java8:$lifecycle",
|
||||||
'lifecycleLivedata' : "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1",
|
'lifecycleLivedata' : "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1",
|
||||||
|
'datastore' : "androidx.datastore:datastore:1.0.0",
|
||||||
|
'datastorepreferences' : "androidx.datastore:datastore-preferences:1.0.0",
|
||||||
'pagingRuntimeKtx' : "androidx.paging:paging-runtime-ktx:2.1.2",
|
'pagingRuntimeKtx' : "androidx.paging:paging-runtime-ktx:2.1.2",
|
||||||
'coreTesting' : "androidx.arch.core:core-testing:2.1.0",
|
'coreTesting' : "androidx.arch.core:core-testing:2.1.0",
|
||||||
'testCore' : "androidx.test:core:$androidxTest",
|
'testCore' : "androidx.test:core:$androidxTest",
|
||||||
|
@ -24,6 +24,7 @@ package org.matrix.android.sdk.api.logger
|
|||||||
*/
|
*/
|
||||||
open class LoggerTag(_value: String, parentTag: LoggerTag? = null) {
|
open class LoggerTag(_value: String, parentTag: LoggerTag? = null) {
|
||||||
|
|
||||||
|
object SYNC : LoggerTag("SYNC")
|
||||||
object VOIP : LoggerTag("VOIP")
|
object VOIP : LoggerTag("VOIP")
|
||||||
|
|
||||||
val value: String = if (parentTag == null) {
|
val value: String = if (parentTag == null) {
|
||||||
|
@ -36,7 +36,7 @@ import org.matrix.android.sdk.api.session.file.FileService
|
|||||||
import org.matrix.android.sdk.api.session.group.GroupService
|
import org.matrix.android.sdk.api.session.group.GroupService
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||||
import org.matrix.android.sdk.api.session.identity.IdentityService
|
import org.matrix.android.sdk.api.session.identity.IdentityService
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||||
import org.matrix.android.sdk.api.session.media.MediaService
|
import org.matrix.android.sdk.api.session.media.MediaService
|
||||||
import org.matrix.android.sdk.api.session.openid.OpenIdService
|
import org.matrix.android.sdk.api.session.openid.OpenIdService
|
||||||
@ -75,7 +75,7 @@ interface Session :
|
|||||||
ProfileService,
|
ProfileService,
|
||||||
PushRuleService,
|
PushRuleService,
|
||||||
PushersService,
|
PushersService,
|
||||||
InitialSyncProgressService,
|
SyncStatusService,
|
||||||
HomeServerCapabilitiesService,
|
HomeServerCapabilitiesService,
|
||||||
SecureStorageService,
|
SecureStorageService,
|
||||||
AccountService {
|
AccountService {
|
||||||
|
@ -17,15 +17,33 @@ package org.matrix.android.sdk.api.session.initsync
|
|||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
|
||||||
interface InitialSyncProgressService {
|
interface SyncStatusService {
|
||||||
|
|
||||||
fun getInitialSyncProgressStatus(): LiveData<Status>
|
fun getSyncStatusLive(): LiveData<Status>
|
||||||
|
|
||||||
sealed class Status {
|
sealed class Status {
|
||||||
object Idle : Status()
|
/**
|
||||||
|
* For initial sync
|
||||||
|
*/
|
||||||
|
abstract class InitialSyncStatus: Status()
|
||||||
|
|
||||||
|
object Idle : InitialSyncStatus()
|
||||||
data class Progressing(
|
data class Progressing(
|
||||||
val initSyncStep: InitSyncStep,
|
val initSyncStep: InitSyncStep,
|
||||||
val percentProgress: Int = 0
|
val percentProgress: Int = 0
|
||||||
) : Status()
|
) : InitialSyncStatus()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For incremental sync
|
||||||
|
*/
|
||||||
|
abstract class IncrementalSyncStatus: Status()
|
||||||
|
|
||||||
|
object IncrementalSyncIdle : IncrementalSyncStatus()
|
||||||
|
data class IncrementalSyncParsing(
|
||||||
|
val rooms: Int,
|
||||||
|
val toDevice: Int
|
||||||
|
) : IncrementalSyncStatus()
|
||||||
|
object IncrementalSyncError : IncrementalSyncStatus()
|
||||||
|
object IncrementalSyncDone : IncrementalSyncStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -40,7 +40,7 @@ import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
|
|||||||
import org.matrix.android.sdk.api.session.file.FileService
|
import org.matrix.android.sdk.api.session.file.FileService
|
||||||
import org.matrix.android.sdk.api.session.group.GroupService
|
import org.matrix.android.sdk.api.session.group.GroupService
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||||
import org.matrix.android.sdk.api.session.media.MediaService
|
import org.matrix.android.sdk.api.session.media.MediaService
|
||||||
import org.matrix.android.sdk.api.session.openid.OpenIdService
|
import org.matrix.android.sdk.api.session.openid.OpenIdService
|
||||||
@ -115,7 +115,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
private val contentUploadProgressTracker: ContentUploadStateTracker,
|
private val contentUploadProgressTracker: ContentUploadStateTracker,
|
||||||
private val typingUsersTracker: TypingUsersTracker,
|
private val typingUsersTracker: TypingUsersTracker,
|
||||||
private val contentDownloadStateTracker: ContentDownloadStateTracker,
|
private val contentDownloadStateTracker: ContentDownloadStateTracker,
|
||||||
private val initialSyncProgressService: Lazy<InitialSyncProgressService>,
|
private val syncStatusService: Lazy<SyncStatusService>,
|
||||||
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
|
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
|
||||||
private val accountDataService: Lazy<SessionAccountDataService>,
|
private val accountDataService: Lazy<SessionAccountDataService>,
|
||||||
private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
|
private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
|
||||||
@ -141,7 +141,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
PushersService by pushersService.get(),
|
PushersService by pushersService.get(),
|
||||||
EventService by eventService.get(),
|
EventService by eventService.get(),
|
||||||
TermsService by termsService.get(),
|
TermsService by termsService.get(),
|
||||||
InitialSyncProgressService by initialSyncProgressService.get(),
|
SyncStatusService by syncStatusService.get(),
|
||||||
SecureStorageService by secureStorageService.get(),
|
SecureStorageService by secureStorageService.get(),
|
||||||
HomeServerCapabilitiesService by homeServerCapabilitiesService.get(),
|
HomeServerCapabilitiesService by homeServerCapabilitiesService.get(),
|
||||||
ProfileService by profileService.get(),
|
ProfileService by profileService.get(),
|
||||||
|
@ -37,7 +37,7 @@ import org.matrix.android.sdk.api.session.SessionLifecycleObserver
|
|||||||
import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
|
import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
|
||||||
import org.matrix.android.sdk.api.session.events.EventService
|
import org.matrix.android.sdk.api.session.events.EventService
|
||||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.openid.OpenIdService
|
import org.matrix.android.sdk.api.session.openid.OpenIdService
|
||||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||||
import org.matrix.android.sdk.api.session.securestorage.SecureStorageService
|
import org.matrix.android.sdk.api.session.securestorage.SecureStorageService
|
||||||
@ -81,7 +81,7 @@ import org.matrix.android.sdk.internal.session.download.DownloadProgressIntercep
|
|||||||
import org.matrix.android.sdk.internal.session.events.DefaultEventService
|
import org.matrix.android.sdk.internal.session.events.DefaultEventService
|
||||||
import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
|
import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
|
||||||
import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
|
import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
|
||||||
import org.matrix.android.sdk.internal.session.initsync.DefaultInitialSyncProgressService
|
import org.matrix.android.sdk.internal.session.initsync.DefaultSyncStatusService
|
||||||
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
|
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
|
||||||
import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService
|
import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService
|
||||||
import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService
|
import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService
|
||||||
@ -355,7 +355,7 @@ internal abstract class SessionModule {
|
|||||||
abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver
|
abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindInitialSyncProgressService(service: DefaultInitialSyncProgressService): InitialSyncProgressService
|
abstract fun bindSyncStatusService(service: DefaultSyncStatusService): SyncStatusService
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindSecureStorageService(service: DefaultSecureStorageService): SecureStorageService
|
abstract fun bindSecureStorageService(service: DefaultSecureStorageService): SecureStorageService
|
||||||
|
@ -18,23 +18,28 @@ package org.matrix.android.sdk.internal.session.initsync
|
|||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
|
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class DefaultInitialSyncProgressService @Inject constructor()
|
internal class DefaultSyncStatusService @Inject constructor()
|
||||||
: InitialSyncProgressService,
|
: SyncStatusService,
|
||||||
ProgressReporter {
|
ProgressReporter {
|
||||||
|
|
||||||
private val status = MutableLiveData<InitialSyncProgressService.Status>()
|
private val status = MutableLiveData<SyncStatusService.Status>()
|
||||||
|
|
||||||
private var rootTask: TaskInfo? = null
|
private var rootTask: TaskInfo? = null
|
||||||
|
|
||||||
override fun getInitialSyncProgressStatus(): LiveData<InitialSyncProgressService.Status> {
|
override fun getSyncStatusLive(): LiveData<SyncStatusService.Status> {
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only to be used for incremental sync
|
||||||
|
fun setStatus(newStatus: SyncStatusService.Status.IncrementalSyncStatus) {
|
||||||
|
status.postValue(newStatus)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a rootTask
|
* Create a rootTask
|
||||||
*/
|
*/
|
||||||
@ -67,7 +72,7 @@ internal class DefaultInitialSyncProgressService @Inject constructor()
|
|||||||
// Update the progress of the leaf and all its parents
|
// Update the progress of the leaf and all its parents
|
||||||
leaf.setProgress(progress)
|
leaf.setProgress(progress)
|
||||||
// Then update the live data using leaf wording and root progress
|
// Then update the live data using leaf wording and root progress
|
||||||
status.postValue(InitialSyncProgressService.Status.Progressing(leaf.initSyncStep, root.currentProgress.toInt()))
|
status.postValue(SyncStatusService.Status.Progressing(leaf.initSyncStep, root.currentProgress.toInt()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,13 +87,13 @@ internal class DefaultInitialSyncProgressService @Inject constructor()
|
|||||||
// And close it
|
// And close it
|
||||||
endedTask.parent.child = null
|
endedTask.parent.child = null
|
||||||
} else {
|
} else {
|
||||||
status.postValue(InitialSyncProgressService.Status.Idle)
|
status.postValue(SyncStatusService.Status.Idle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun endAll() {
|
fun endAll() {
|
||||||
rootTask = null
|
rootTask = null
|
||||||
status.postValue(InitialSyncProgressService.Status.Idle)
|
status.postValue(SyncStatusService.Status.Idle)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,9 @@
|
|||||||
package org.matrix.android.sdk.internal.session.sync
|
package org.matrix.android.sdk.internal.session.sync
|
||||||
|
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
|
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
|
||||||
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
|
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||||
@ -26,7 +28,7 @@ import org.matrix.android.sdk.internal.network.executeRequest
|
|||||||
import org.matrix.android.sdk.internal.network.toFailure
|
import org.matrix.android.sdk.internal.network.toFailure
|
||||||
import org.matrix.android.sdk.internal.session.filter.FilterRepository
|
import org.matrix.android.sdk.internal.session.filter.FilterRepository
|
||||||
import org.matrix.android.sdk.internal.session.homeserver.GetHomeServerCapabilitiesTask
|
import org.matrix.android.sdk.internal.session.homeserver.GetHomeServerCapabilitiesTask
|
||||||
import org.matrix.android.sdk.internal.session.initsync.DefaultInitialSyncProgressService
|
import org.matrix.android.sdk.internal.session.initsync.DefaultSyncStatusService
|
||||||
import org.matrix.android.sdk.internal.session.initsync.reportSubtask
|
import org.matrix.android.sdk.internal.session.initsync.reportSubtask
|
||||||
import org.matrix.android.sdk.internal.session.sync.model.LazyRoomSyncEphemeral
|
import org.matrix.android.sdk.internal.session.sync.model.LazyRoomSyncEphemeral
|
||||||
import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser
|
import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser
|
||||||
@ -40,6 +42,8 @@ import java.io.File
|
|||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("SyncTask", LoggerTag.SYNC)
|
||||||
|
|
||||||
internal interface SyncTask : Task<SyncTask.Params, Unit> {
|
internal interface SyncTask : Task<SyncTask.Params, Unit> {
|
||||||
|
|
||||||
data class Params(
|
data class Params(
|
||||||
@ -53,7 +57,7 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
@UserId private val userId: String,
|
@UserId private val userId: String,
|
||||||
private val filterRepository: FilterRepository,
|
private val filterRepository: FilterRepository,
|
||||||
private val syncResponseHandler: SyncResponseHandler,
|
private val syncResponseHandler: SyncResponseHandler,
|
||||||
private val initialSyncProgressService: DefaultInitialSyncProgressService,
|
private val defaultSyncStatusService: DefaultSyncStatusService,
|
||||||
private val syncTokenStore: SyncTokenStore,
|
private val syncTokenStore: SyncTokenStore,
|
||||||
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask,
|
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask,
|
||||||
private val userStore: UserStore,
|
private val userStore: UserStore,
|
||||||
@ -75,7 +79,7 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun doSync(params: SyncTask.Params) {
|
private suspend fun doSync(params: SyncTask.Params) {
|
||||||
Timber.v("Sync task started on Thread: ${Thread.currentThread().name}")
|
Timber.tag(loggerTag.value).d("Sync task started on Thread: ${Thread.currentThread().name}")
|
||||||
|
|
||||||
val requestParams = HashMap<String, String>()
|
val requestParams = HashMap<String, String>()
|
||||||
var timeout = 0L
|
var timeout = 0L
|
||||||
@ -92,7 +96,7 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
if (isInitialSync) {
|
if (isInitialSync) {
|
||||||
// We might want to get the user information in parallel too
|
// We might want to get the user information in parallel too
|
||||||
userStore.createOrUpdate(userId)
|
userStore.createOrUpdate(userId)
|
||||||
initialSyncProgressService.startRoot(InitSyncStep.ImportingAccount, 100)
|
defaultSyncStatusService.startRoot(InitSyncStep.ImportingAccount, 100)
|
||||||
}
|
}
|
||||||
// Maybe refresh the homeserver capabilities data we know
|
// Maybe refresh the homeserver capabilities data we know
|
||||||
getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false))
|
getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false))
|
||||||
@ -100,20 +104,20 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT)
|
val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT)
|
||||||
|
|
||||||
if (isInitialSync) {
|
if (isInitialSync) {
|
||||||
Timber.d("INIT_SYNC with filter: ${requestParams["filter"]}")
|
Timber.tag(loggerTag.value).d("INIT_SYNC with filter: ${requestParams["filter"]}")
|
||||||
val initSyncStrategy = initialSyncStrategy
|
val initSyncStrategy = initialSyncStrategy
|
||||||
logDuration("INIT_SYNC strategy: $initSyncStrategy") {
|
logDuration("INIT_SYNC strategy: $initSyncStrategy", loggerTag) {
|
||||||
if (initSyncStrategy is InitialSyncStrategy.Optimized) {
|
if (initSyncStrategy is InitialSyncStrategy.Optimized) {
|
||||||
roomSyncEphemeralTemporaryStore.reset()
|
roomSyncEphemeralTemporaryStore.reset()
|
||||||
workingDir.mkdirs()
|
workingDir.mkdirs()
|
||||||
val file = downloadInitSyncResponse(requestParams)
|
val file = downloadInitSyncResponse(requestParams)
|
||||||
reportSubtask(initialSyncProgressService, InitSyncStep.ImportingAccount, 1, 0.7F) {
|
reportSubtask(defaultSyncStatusService, InitSyncStep.ImportingAccount, 1, 0.7F) {
|
||||||
handleSyncFile(file, initSyncStrategy)
|
handleSyncFile(file, initSyncStrategy)
|
||||||
}
|
}
|
||||||
// Delete all files
|
// Delete all files
|
||||||
workingDir.deleteRecursively()
|
workingDir.deleteRecursively()
|
||||||
} else {
|
} else {
|
||||||
val syncResponse = logDuration("INIT_SYNC Request") {
|
val syncResponse = logDuration("INIT_SYNC Request", loggerTag) {
|
||||||
executeRequest(globalErrorReceiver) {
|
executeRequest(globalErrorReceiver) {
|
||||||
syncAPI.sync(
|
syncAPI.sync(
|
||||||
params = requestParams,
|
params = requestParams,
|
||||||
@ -122,43 +126,60 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logDuration("INIT_SYNC Database insertion") {
|
logDuration("INIT_SYNC Database insertion", loggerTag) {
|
||||||
syncResponseHandler.handleResponse(syncResponse, token, initialSyncProgressService)
|
syncResponseHandler.handleResponse(syncResponse, token, defaultSyncStatusService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initialSyncProgressService.endAll()
|
defaultSyncStatusService.endAll()
|
||||||
} else {
|
} else {
|
||||||
val syncResponse = executeRequest(globalErrorReceiver) {
|
Timber.tag(loggerTag.value).d("Start incremental sync request")
|
||||||
|
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncIdle)
|
||||||
|
val syncResponse = try {
|
||||||
|
executeRequest(globalErrorReceiver) {
|
||||||
syncAPI.sync(
|
syncAPI.sync(
|
||||||
params = requestParams,
|
params = requestParams,
|
||||||
readTimeOut = readTimeOut
|
readTimeOut = readTimeOut
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
syncResponseHandler.handleResponse(syncResponse, token, null)
|
} catch (throwable: Throwable) {
|
||||||
|
Timber.tag(loggerTag.value).e(throwable, "Incremental sync request error")
|
||||||
|
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncError)
|
||||||
|
throw throwable
|
||||||
}
|
}
|
||||||
Timber.v("Sync task finished on Thread: ${Thread.currentThread().name}")
|
val nbRooms = syncResponse.rooms?.invite.orEmpty().size + syncResponse.rooms?.join.orEmpty().size + syncResponse.rooms?.leave.orEmpty().size
|
||||||
|
val nbToDevice = syncResponse.toDevice?.events.orEmpty().size
|
||||||
|
Timber.tag(loggerTag.value).d("Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s)")
|
||||||
|
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncParsing(
|
||||||
|
rooms = nbRooms,
|
||||||
|
toDevice = nbToDevice
|
||||||
|
))
|
||||||
|
syncResponseHandler.handleResponse(syncResponse, token, null)
|
||||||
|
Timber.tag(loggerTag.value).d("Incremental sync done")
|
||||||
|
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncDone)
|
||||||
|
}
|
||||||
|
Timber.tag(loggerTag.value).d("Sync task finished on Thread: ${Thread.currentThread().name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun downloadInitSyncResponse(requestParams: Map<String, String>): File {
|
private suspend fun downloadInitSyncResponse(requestParams: Map<String, String>): File {
|
||||||
val workingFile = File(workingDir, "initSync.json")
|
val workingFile = File(workingDir, "initSync.json")
|
||||||
val status = initialSyncStatusRepository.getStep()
|
val status = initialSyncStatusRepository.getStep()
|
||||||
if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) {
|
if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) {
|
||||||
Timber.d("INIT_SYNC file is already here")
|
Timber.tag(loggerTag.value).d("INIT_SYNC file is already here")
|
||||||
reportSubtask(initialSyncProgressService, InitSyncStep.Downloading, 1, 0.3f) {
|
reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.3f) {
|
||||||
// Empty task
|
// Empty task
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_DOWNLOADING)
|
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_DOWNLOADING)
|
||||||
val syncResponse = logDuration("INIT_SYNC Perform server request") {
|
val syncResponse = logDuration("INIT_SYNC Perform server request", loggerTag) {
|
||||||
reportSubtask(initialSyncProgressService, InitSyncStep.ServerComputing, 1, 0.2f) {
|
reportSubtask(defaultSyncStatusService, InitSyncStep.ServerComputing, 1, 0.2f) {
|
||||||
getSyncResponse(requestParams, MAX_NUMBER_OF_RETRY_AFTER_TIMEOUT)
|
getSyncResponse(requestParams, MAX_NUMBER_OF_RETRY_AFTER_TIMEOUT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syncResponse.isSuccessful) {
|
if (syncResponse.isSuccessful) {
|
||||||
logDuration("INIT_SYNC Download and save to file") {
|
logDuration("INIT_SYNC Download and save to file", loggerTag) {
|
||||||
reportSubtask(initialSyncProgressService, InitSyncStep.Downloading, 1, 0.1f) {
|
reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.1f) {
|
||||||
syncResponse.body()?.byteStream()?.use { inputStream ->
|
syncResponse.body()?.byteStream()?.use { inputStream ->
|
||||||
workingFile.outputStream().use { outputStream ->
|
workingFile.outputStream().use { outputStream ->
|
||||||
inputStream.copyTo(outputStream)
|
inputStream.copyTo(outputStream)
|
||||||
@ -168,7 +189,7 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw syncResponse.toFailure(globalErrorReceiver)
|
throw syncResponse.toFailure(globalErrorReceiver)
|
||||||
.also { Timber.w("INIT_SYNC request failure: $this") }
|
.also { Timber.tag(loggerTag.value).w("INIT_SYNC request failure: $this") }
|
||||||
}
|
}
|
||||||
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_DOWNLOADED)
|
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_DOWNLOADED)
|
||||||
}
|
}
|
||||||
@ -185,9 +206,9 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
).awaitResponse()
|
).awaitResponse()
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (throwable is SocketTimeoutException && retry > 0) {
|
if (throwable is SocketTimeoutException && retry > 0) {
|
||||||
Timber.w("INIT_SYNC timeout retry left: $retry")
|
Timber.tag(loggerTag.value).w("INIT_SYNC timeout retry left: $retry")
|
||||||
} else {
|
} else {
|
||||||
Timber.e(throwable, "INIT_SYNC timeout, no retry left, or other error")
|
Timber.tag(loggerTag.value).e(throwable, "INIT_SYNC timeout, no retry left, or other error")
|
||||||
throw throwable
|
throw throwable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,18 +216,18 @@ internal class DefaultSyncTask @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleSyncFile(workingFile: File, initSyncStrategy: InitialSyncStrategy.Optimized) {
|
private suspend fun handleSyncFile(workingFile: File, initSyncStrategy: InitialSyncStrategy.Optimized) {
|
||||||
logDuration("INIT_SYNC handleSyncFile()") {
|
logDuration("INIT_SYNC handleSyncFile()", loggerTag) {
|
||||||
val syncResponse = logDuration("INIT_SYNC Read file and parse") {
|
val syncResponse = logDuration("INIT_SYNC Read file and parse", loggerTag) {
|
||||||
syncResponseParser.parse(initSyncStrategy, workingFile)
|
syncResponseParser.parse(initSyncStrategy, workingFile)
|
||||||
}
|
}
|
||||||
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_PARSED)
|
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_PARSED)
|
||||||
// Log some stats
|
// Log some stats
|
||||||
val nbOfJoinedRooms = syncResponse.rooms?.join?.size ?: 0
|
val nbOfJoinedRooms = syncResponse.rooms?.join?.size ?: 0
|
||||||
val nbOfJoinedRoomsInFile = syncResponse.rooms?.join?.values?.count { it.ephemeral is LazyRoomSyncEphemeral.Stored }
|
val nbOfJoinedRoomsInFile = syncResponse.rooms?.join?.values?.count { it.ephemeral is LazyRoomSyncEphemeral.Stored }
|
||||||
Timber.d("INIT_SYNC $nbOfJoinedRooms rooms, $nbOfJoinedRoomsInFile ephemeral stored into files")
|
Timber.tag(loggerTag.value).d("INIT_SYNC $nbOfJoinedRooms rooms, $nbOfJoinedRoomsInFile ephemeral stored into files")
|
||||||
|
|
||||||
logDuration("INIT_SYNC Database insertion") {
|
logDuration("INIT_SYNC Database insertion", loggerTag) {
|
||||||
syncResponseHandler.handleResponse(syncResponse, null, initialSyncProgressService)
|
syncResponseHandler.handleResponse(syncResponse, null, defaultSyncStatusService)
|
||||||
}
|
}
|
||||||
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_SUCCESS)
|
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_SUCCESS)
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import kotlinx.coroutines.cancelChildren
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.call.MxCall
|
import org.matrix.android.sdk.api.session.call.MxCall
|
||||||
import org.matrix.android.sdk.internal.session.call.ActiveCallHandler
|
import org.matrix.android.sdk.internal.session.call.ActiveCallHandler
|
||||||
import org.matrix.android.sdk.internal.session.sync.SyncPresence
|
import org.matrix.android.sdk.internal.session.sync.SyncPresence
|
||||||
@ -49,6 +50,8 @@ import kotlin.concurrent.schedule
|
|||||||
private const val RETRY_WAIT_TIME_MS = 10_000L
|
private const val RETRY_WAIT_TIME_MS = 10_000L
|
||||||
private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L
|
private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("SyncThread", LoggerTag.SYNC)
|
||||||
|
|
||||||
internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
||||||
private val networkConnectivityChecker: NetworkConnectivityChecker,
|
private val networkConnectivityChecker: NetworkConnectivityChecker,
|
||||||
private val backgroundDetectionObserver: BackgroundDetectionObserver,
|
private val backgroundDetectionObserver: BackgroundDetectionObserver,
|
||||||
@ -83,7 +86,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
|
|
||||||
fun restart() = synchronized(lock) {
|
fun restart() = synchronized(lock) {
|
||||||
if (!isStarted) {
|
if (!isStarted) {
|
||||||
Timber.v("Resume sync...")
|
Timber.tag(loggerTag.value).d("Resume sync...")
|
||||||
isStarted = true
|
isStarted = true
|
||||||
// Check again server availability and the token validity
|
// Check again server availability and the token validity
|
||||||
canReachServer = true
|
canReachServer = true
|
||||||
@ -94,7 +97,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
|
|
||||||
fun pause() = synchronized(lock) {
|
fun pause() = synchronized(lock) {
|
||||||
if (isStarted) {
|
if (isStarted) {
|
||||||
Timber.v("Pause sync...")
|
Timber.tag(loggerTag.value).d("Pause sync...")
|
||||||
isStarted = false
|
isStarted = false
|
||||||
retryNoNetworkTask?.cancel()
|
retryNoNetworkTask?.cancel()
|
||||||
syncScope.coroutineContext.cancelChildren()
|
syncScope.coroutineContext.cancelChildren()
|
||||||
@ -102,7 +105,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun kill() = synchronized(lock) {
|
fun kill() = synchronized(lock) {
|
||||||
Timber.v("Kill sync...")
|
Timber.tag(loggerTag.value).d("Kill sync...")
|
||||||
updateStateTo(SyncState.Killing)
|
updateStateTo(SyncState.Killing)
|
||||||
retryNoNetworkTask?.cancel()
|
retryNoNetworkTask?.cancel()
|
||||||
syncScope.coroutineContext.cancelChildren()
|
syncScope.coroutineContext.cancelChildren()
|
||||||
@ -124,21 +127,21 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
Timber.v("Start syncing...")
|
Timber.tag(loggerTag.value).d("Start syncing...")
|
||||||
|
|
||||||
isStarted = true
|
isStarted = true
|
||||||
networkConnectivityChecker.register(this)
|
networkConnectivityChecker.register(this)
|
||||||
backgroundDetectionObserver.register(this)
|
backgroundDetectionObserver.register(this)
|
||||||
registerActiveCallsObserver()
|
registerActiveCallsObserver()
|
||||||
while (state != SyncState.Killing) {
|
while (state != SyncState.Killing) {
|
||||||
Timber.v("Entering loop, state: $state")
|
Timber.tag(loggerTag.value).d("Entering loop, state: $state")
|
||||||
if (!isStarted) {
|
if (!isStarted) {
|
||||||
Timber.v("Sync is Paused. Waiting...")
|
Timber.tag(loggerTag.value).d("Sync is Paused. Waiting...")
|
||||||
updateStateTo(SyncState.Paused)
|
updateStateTo(SyncState.Paused)
|
||||||
synchronized(lock) { lock.wait() }
|
synchronized(lock) { lock.wait() }
|
||||||
Timber.v("...unlocked")
|
Timber.tag(loggerTag.value).d("...unlocked")
|
||||||
} else if (!canReachServer) {
|
} else if (!canReachServer) {
|
||||||
Timber.v("No network. Waiting...")
|
Timber.tag(loggerTag.value).d("No network. Waiting...")
|
||||||
updateStateTo(SyncState.NoNetwork)
|
updateStateTo(SyncState.NoNetwork)
|
||||||
// We force retrying in RETRY_WAIT_TIME_MS maximum. Otherwise it will be unlocked by onConnectivityChanged() or restart()
|
// We force retrying in RETRY_WAIT_TIME_MS maximum. Otherwise it will be unlocked by onConnectivityChanged() or restart()
|
||||||
retryNoNetworkTask = Timer(SyncState.NoNetwork.toString(), false).schedule(RETRY_WAIT_TIME_MS) {
|
retryNoNetworkTask = Timer(SyncState.NoNetwork.toString(), false).schedule(RETRY_WAIT_TIME_MS) {
|
||||||
@ -148,19 +151,19 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronized(lock) { lock.wait() }
|
synchronized(lock) { lock.wait() }
|
||||||
Timber.v("...retry")
|
Timber.tag(loggerTag.value).d("...retry")
|
||||||
} else if (!isTokenValid) {
|
} else if (!isTokenValid) {
|
||||||
Timber.v("Token is invalid. Waiting...")
|
Timber.tag(loggerTag.value).d("Token is invalid. Waiting...")
|
||||||
updateStateTo(SyncState.InvalidToken)
|
updateStateTo(SyncState.InvalidToken)
|
||||||
synchronized(lock) { lock.wait() }
|
synchronized(lock) { lock.wait() }
|
||||||
Timber.v("...unlocked")
|
Timber.tag(loggerTag.value).d("...unlocked")
|
||||||
} else {
|
} else {
|
||||||
if (state !is SyncState.Running) {
|
if (state !is SyncState.Running) {
|
||||||
updateStateTo(SyncState.Running(afterPause = true))
|
updateStateTo(SyncState.Running(afterPause = true))
|
||||||
}
|
}
|
||||||
// No timeout after a pause
|
// No timeout after a pause
|
||||||
val timeout = state.let { if (it is SyncState.Running && it.afterPause) 0 else DEFAULT_LONG_POOL_TIMEOUT }
|
val timeout = state.let { if (it is SyncState.Running && it.afterPause) 0 else DEFAULT_LONG_POOL_TIMEOUT }
|
||||||
Timber.v("Execute sync request with timeout $timeout")
|
Timber.tag(loggerTag.value).d("Execute sync request with timeout $timeout")
|
||||||
val params = SyncTask.Params(timeout, SyncPresence.Online)
|
val params = SyncTask.Params(timeout, SyncPresence.Online)
|
||||||
val sync = syncScope.launch {
|
val sync = syncScope.launch {
|
||||||
doSync(params)
|
doSync(params)
|
||||||
@ -168,10 +171,10 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
runBlocking {
|
runBlocking {
|
||||||
sync.join()
|
sync.join()
|
||||||
}
|
}
|
||||||
Timber.v("...Continue")
|
Timber.tag(loggerTag.value).d("...Continue")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timber.v("Sync killed")
|
Timber.tag(loggerTag.value).d("Sync killed")
|
||||||
updateStateTo(SyncState.Killed)
|
updateStateTo(SyncState.Killed)
|
||||||
backgroundDetectionObserver.unregister(this)
|
backgroundDetectionObserver.unregister(this)
|
||||||
networkConnectivityChecker.unregister(this)
|
networkConnectivityChecker.unregister(this)
|
||||||
@ -199,19 +202,19 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
}
|
}
|
||||||
if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) {
|
if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) {
|
||||||
// Timeout are not critical
|
// Timeout are not critical
|
||||||
Timber.v("Timeout")
|
Timber.tag(loggerTag.value).d("Timeout")
|
||||||
} else if (failure is CancellationException) {
|
} else if (failure is CancellationException) {
|
||||||
Timber.v("Cancelled")
|
Timber.tag(loggerTag.value).d("Cancelled")
|
||||||
} else if (failure.isTokenError()) {
|
} else if (failure.isTokenError()) {
|
||||||
// No token or invalid token, stop the thread
|
// No token or invalid token, stop the thread
|
||||||
Timber.w(failure, "Token error")
|
Timber.tag(loggerTag.value).w(failure, "Token error")
|
||||||
isStarted = false
|
isStarted = false
|
||||||
isTokenValid = false
|
isTokenValid = false
|
||||||
} else {
|
} else {
|
||||||
Timber.e(failure)
|
Timber.tag(loggerTag.value).e(failure)
|
||||||
if (failure !is Failure.NetworkConnection || failure.cause is JsonEncodingException) {
|
if (failure !is Failure.NetworkConnection || failure.cause is JsonEncodingException) {
|
||||||
// Wait 10s before retrying
|
// Wait 10s before retrying
|
||||||
Timber.v("Wait 10s")
|
Timber.tag(loggerTag.value).d("Wait 10s")
|
||||||
delay(RETRY_WAIT_TIME_MS)
|
delay(RETRY_WAIT_TIME_MS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +228,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateStateTo(newState: SyncState) {
|
private fun updateStateTo(newState: SyncState) {
|
||||||
Timber.v("Update state from $state to $newState")
|
Timber.tag(loggerTag.value).d("Update state from $state to $newState")
|
||||||
if (newState == state) {
|
if (newState == state) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package org.matrix.android.sdk.internal.util
|
package org.matrix.android.sdk.internal.util
|
||||||
|
|
||||||
import org.matrix.android.sdk.BuildConfig
|
import org.matrix.android.sdk.BuildConfig
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String {
|
internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String {
|
||||||
@ -32,14 +33,15 @@ internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal suspend fun <T> logDuration(message: String,
|
internal suspend fun <T> logDuration(message: String,
|
||||||
|
loggerTag: LoggerTag,
|
||||||
block: suspend () -> T): T {
|
block: suspend () -> T): T {
|
||||||
Timber.d("$message -- BEGIN")
|
Timber.tag(loggerTag.value).d("$message -- BEGIN")
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
val result = logRamUsage(message) {
|
val result = logRamUsage(message) {
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
val duration = System.currentTimeMillis() - start
|
val duration = System.currentTimeMillis() - start
|
||||||
Timber.d("$message -- END duration: $duration ms")
|
Timber.tag(loggerTag.value).d("$message -- END duration: $duration ms")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -345,6 +345,9 @@ dependencies {
|
|||||||
implementation libs.androidx.lifecycleExtensions
|
implementation libs.androidx.lifecycleExtensions
|
||||||
implementation libs.androidx.lifecycleLivedata
|
implementation libs.androidx.lifecycleLivedata
|
||||||
|
|
||||||
|
implementation libs.androidx.datastore
|
||||||
|
implementation libs.androidx.datastorepreferences
|
||||||
|
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
implementation libs.jakewharton.timber
|
implementation libs.jakewharton.timber
|
||||||
@ -406,7 +409,7 @@ dependencies {
|
|||||||
// To convert voice message on old platforms
|
// To convert voice message on old platforms
|
||||||
implementation 'com.arthenica:ffmpeg-kit-audio:4.4.LTS'
|
implementation 'com.arthenica:ffmpeg-kit-audio:4.4.LTS'
|
||||||
|
|
||||||
//Alerter
|
// Alerter
|
||||||
implementation 'com.tapadoo.android:alerter:7.0.1'
|
implementation 'com.tapadoo.android:alerter:7.0.1'
|
||||||
|
|
||||||
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
||||||
|
@ -39,17 +39,22 @@ import im.vector.app.features.notifications.NotifiableMessageEvent
|
|||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import im.vector.app.features.notifications.SimpleNotifiableEvent
|
import im.vector.app.features.notifications.SimpleNotifiableEvent
|
||||||
|
import im.vector.app.features.settings.VectorDataStore
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.push.fcm.FcmHelper
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.pushrules.Action
|
import org.matrix.android.sdk.api.pushrules.Action
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class extending FirebaseMessagingService.
|
* Class extending FirebaseMessagingService.
|
||||||
*/
|
*/
|
||||||
@ -60,6 +65,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
private lateinit var pusherManager: PushersManager
|
private lateinit var pusherManager: PushersManager
|
||||||
private lateinit var activeSessionHolder: ActiveSessionHolder
|
private lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
private lateinit var vectorPreferences: VectorPreferences
|
private lateinit var vectorPreferences: VectorPreferences
|
||||||
|
private lateinit var vectorDataStore: VectorDataStore
|
||||||
private lateinit var wifiDetector: WifiDetector
|
private lateinit var wifiDetector: WifiDetector
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||||
@ -77,6 +83,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
pusherManager = pusherManager()
|
pusherManager = pusherManager()
|
||||||
activeSessionHolder = activeSessionHolder()
|
activeSessionHolder = activeSessionHolder()
|
||||||
vectorPreferences = vectorPreferences()
|
vectorPreferences = vectorPreferences()
|
||||||
|
vectorDataStore = vectorDataStore()
|
||||||
wifiDetector = wifiDetector()
|
wifiDetector = wifiDetector()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,9 +95,13 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
*/
|
*/
|
||||||
override fun onMessageReceived(message: RemoteMessage) {
|
override fun onMessageReceived(message: RemoteMessage) {
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
||||||
Timber.d("## onMessageReceived() %s", message.data.toString())
|
Timber.tag(loggerTag.value).d("## onMessageReceived() %s", message.data.toString())
|
||||||
|
}
|
||||||
|
Timber.tag(loggerTag.value).d("## onMessageReceived() from FCM with priority %s", message.priority)
|
||||||
|
|
||||||
|
runBlocking {
|
||||||
|
vectorDataStore.incrementPushCounter()
|
||||||
}
|
}
|
||||||
Timber.d("## onMessageReceived() from FCM with priority %s", message.priority)
|
|
||||||
|
|
||||||
// Diagnostic Push
|
// Diagnostic Push
|
||||||
if (message.data["event_id"] == PushersManager.TEST_EVENT_ID) {
|
if (message.data["event_id"] == PushersManager.TEST_EVENT_ID) {
|
||||||
@ -100,14 +111,14 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!vectorPreferences.areNotificationEnabledForDevice()) {
|
if (!vectorPreferences.areNotificationEnabledForDevice()) {
|
||||||
Timber.i("Notification are disabled for this device")
|
Timber.tag(loggerTag.value).i("Notification are disabled for this device")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mUIHandler.post {
|
mUIHandler.post {
|
||||||
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||||
// we are in foreground, let the sync do the things?
|
// we are in foreground, let the sync do the things?
|
||||||
Timber.d("PUSH received in a foreground state, ignore")
|
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
|
||||||
} else {
|
} else {
|
||||||
onMessageReceivedInternal(message.data)
|
onMessageReceivedInternal(message.data)
|
||||||
}
|
}
|
||||||
@ -121,7 +132,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
* you retrieve the token.
|
* you retrieve the token.
|
||||||
*/
|
*/
|
||||||
override fun onNewToken(refreshedToken: String) {
|
override fun onNewToken(refreshedToken: String) {
|
||||||
Timber.i("onNewToken: FCM Token has been updated")
|
Timber.tag(loggerTag.value).i("onNewToken: FCM Token has been updated")
|
||||||
FcmHelper.storeFcmToken(this, refreshedToken)
|
FcmHelper.storeFcmToken(this, refreshedToken)
|
||||||
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
||||||
pusherManager.registerPusherWithFcmKey(refreshedToken)
|
pusherManager.registerPusherWithFcmKey(refreshedToken)
|
||||||
@ -138,7 +149,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
* It is recommended that the app do a full sync with the app server after receiving this call.
|
* It is recommended that the app do a full sync with the app server after receiving this call.
|
||||||
*/
|
*/
|
||||||
override fun onDeletedMessages() {
|
override fun onDeletedMessages() {
|
||||||
Timber.v("## onDeletedMessages()")
|
Timber.tag(loggerTag.value).v("## onDeletedMessages()")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,9 +161,9 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
private fun onMessageReceivedInternal(data: Map<String, String>) {
|
private fun onMessageReceivedInternal(data: Map<String, String>) {
|
||||||
try {
|
try {
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
||||||
Timber.d("## onMessageReceivedInternal() : $data")
|
Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $data")
|
||||||
} else {
|
} else {
|
||||||
Timber.d("## onMessageReceivedInternal() : $data")
|
Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()")
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the badge counter
|
// update the badge counter
|
||||||
@ -162,24 +173,24 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
val session = activeSessionHolder.getSafeActiveSession()
|
val session = activeSessionHolder.getSafeActiveSession()
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
Timber.w("## Can't sync from push, no current session")
|
Timber.tag(loggerTag.value).w("## Can't sync from push, no current session")
|
||||||
} else {
|
} else {
|
||||||
val eventId = data["event_id"]
|
val eventId = data["event_id"]
|
||||||
val roomId = data["room_id"]
|
val roomId = data["room_id"]
|
||||||
|
|
||||||
if (isEventAlreadyKnown(eventId, roomId)) {
|
if (isEventAlreadyKnown(eventId, roomId)) {
|
||||||
Timber.d("Ignoring push, event already known")
|
Timber.tag(loggerTag.value).d("Ignoring push, event already known")
|
||||||
} else {
|
} else {
|
||||||
// Try to get the Event content faster
|
// Try to get the Event content faster
|
||||||
Timber.d("Requesting event in fast lane")
|
Timber.tag(loggerTag.value).d("Requesting event in fast lane")
|
||||||
getEventFastLane(session, roomId, eventId)
|
getEventFastLane(session, roomId, eventId)
|
||||||
|
|
||||||
Timber.d("Requesting background sync")
|
Timber.tag(loggerTag.value).d("Requesting background sync")
|
||||||
session.requireBackgroundSync()
|
session.requireBackgroundSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## onMessageReceivedInternal() failed")
|
Timber.tag(loggerTag.value).e(e, "## onMessageReceivedInternal() failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,18 +204,18 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (wifiDetector.isConnectedToWifi().not()) {
|
if (wifiDetector.isConnectedToWifi().not()) {
|
||||||
Timber.d("No WiFi network, do not get Event")
|
Timber.tag(loggerTag.value).d("No WiFi network, do not get Event")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
Timber.d("Fast lane: start request")
|
Timber.tag(loggerTag.value).d("Fast lane: start request")
|
||||||
val event = tryOrNull { session.getEvent(roomId, eventId) } ?: return@launch
|
val event = tryOrNull { session.getEvent(roomId, eventId) } ?: return@launch
|
||||||
|
|
||||||
val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event)
|
val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event)
|
||||||
|
|
||||||
resolvedEvent
|
resolvedEvent
|
||||||
?.also { Timber.d("Fast lane: notify drawer") }
|
?.also { Timber.tag(loggerTag.value).d("Fast lane: notify drawer") }
|
||||||
?.let {
|
?.let {
|
||||||
it.isPushGatewayEvent = true
|
it.isPushGatewayEvent = true
|
||||||
notificationDrawerManager.onNotifiableEventReceived(it)
|
notificationDrawerManager.onNotifiableEventReceived(it)
|
||||||
@ -222,7 +233,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
val room = session.getRoom(roomId) ?: return false
|
val room = session.getRoom(roomId) ?: return false
|
||||||
return room.getTimeLineEvent(eventId) != null
|
return room.getTimeLineEvent(eventId) != null
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined")
|
Timber.tag(loggerTag.value).e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -230,7 +241,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
|
|
||||||
private fun handleNotificationWithoutSyncingMode(data: Map<String, String>, session: Session?) {
|
private fun handleNotificationWithoutSyncingMode(data: Map<String, String>, session: Session?) {
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
Timber.e("## handleNotificationWithoutSyncingMode cannot find session")
|
Timber.tag(loggerTag.value).e("## handleNotificationWithoutSyncingMode cannot find session")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,9 +274,9 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
val notifiableEvent = notifiableEventResolver.resolveEvent(event, session)
|
val notifiableEvent = notifiableEventResolver.resolveEvent(event, session)
|
||||||
|
|
||||||
if (notifiableEvent == null) {
|
if (notifiableEvent == null) {
|
||||||
Timber.e("Unsupported notifiable event $eventId")
|
Timber.tag(loggerTag.value).e("Unsupported notifiable event $eventId")
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
||||||
Timber.e("--> $event")
|
Timber.tag(loggerTag.value).e("--> $event")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (notifiableEvent is NotifiableMessageEvent) {
|
if (notifiableEvent is NotifiableMessageEvent) {
|
||||||
|
@ -58,6 +58,7 @@ import im.vector.app.features.rageshake.VectorFileLogger
|
|||||||
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
import im.vector.app.features.reactions.data.EmojiDataSource
|
import im.vector.app.features.reactions.data.EmojiDataSource
|
||||||
import im.vector.app.features.session.SessionListener
|
import im.vector.app.features.session.SessionListener
|
||||||
|
import im.vector.app.features.settings.VectorDataStore
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import org.matrix.android.sdk.api.Matrix
|
import org.matrix.android.sdk.api.Matrix
|
||||||
@ -145,6 +146,8 @@ interface VectorComponent {
|
|||||||
|
|
||||||
fun vectorPreferences(): VectorPreferences
|
fun vectorPreferences(): VectorPreferences
|
||||||
|
|
||||||
|
fun vectorDataStore(): VectorDataStore
|
||||||
|
|
||||||
fun wifiDetector(): WifiDetector
|
fun wifiDetector(): WifiDetector
|
||||||
|
|
||||||
fun vectorFileLogger(): VectorFileLogger
|
fun vectorFileLogger(): VectorFileLogger
|
||||||
|
@ -70,7 +70,7 @@ import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
|||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.push.fcm.FcmHelper
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import org.matrix.android.sdk.internal.session.sync.InitialSyncStrategy
|
import org.matrix.android.sdk.internal.session.sync.InitialSyncStrategy
|
||||||
@ -308,11 +308,11 @@ class HomeActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun renderState(state: HomeActivityViewState) {
|
private fun renderState(state: HomeActivityViewState) {
|
||||||
when (val status = state.initialSyncProgressServiceStatus) {
|
when (val status = state.syncStatusServiceStatus) {
|
||||||
is InitialSyncProgressService.Status.Idle -> {
|
is SyncStatusService.Status.Idle -> {
|
||||||
views.waitingView.root.isVisible = false
|
views.waitingView.root.isVisible = false
|
||||||
}
|
}
|
||||||
is InitialSyncProgressService.Status.Progressing -> {
|
is SyncStatusService.Status.Progressing -> {
|
||||||
val initSyncStepStr = initSyncStepFormatter.format(status.initSyncStep)
|
val initSyncStepStr = initSyncStepFormatter.format(status.initSyncStep)
|
||||||
Timber.v("$initSyncStepStr ${status.percentProgress}")
|
Timber.v("$initSyncStepStr ${status.percentProgress}")
|
||||||
views.waitingView.root.setOnClickListener {
|
views.waitingView.root.setOnClickListener {
|
||||||
@ -330,6 +330,7 @@ class HomeActivity :
|
|||||||
}
|
}
|
||||||
views.waitingView.root.isVisible = true
|
views.waitingView.root.isVisible = true
|
||||||
}
|
}
|
||||||
|
else -> Unit
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,8 +475,8 @@ class HomeActivity :
|
|||||||
override fun getMenuRes() = R.menu.home
|
override fun getMenuRes() = R.menu.home
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||||
menu.findItem(R.id.menu_home_init_sync_legacy)?.isVisible = vectorPreferences.developerMode()
|
menu.findItem(R.id.menu_home_init_sync_legacy).isVisible = vectorPreferences.developerMode()
|
||||||
menu.findItem(R.id.menu_home_init_sync_optimized)?.isVisible = vectorPreferences.developerMode()
|
menu.findItem(R.id.menu_home_init_sync_optimized).isVisible = vectorPreferences.developerMode()
|
||||||
return super.onPrepareOptionsMenu(menu)
|
return super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
|||||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleIds
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
@ -122,25 +122,26 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
private fun observeInitialSync() {
|
private fun observeInitialSync() {
|
||||||
val session = activeSessionHolder.getSafeActiveSession() ?: return
|
val session = activeSessionHolder.getSafeActiveSession() ?: return
|
||||||
|
|
||||||
session.getInitialSyncProgressStatus()
|
session.getSyncStatusLive()
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.subscribe { status ->
|
.subscribe { status ->
|
||||||
when (status) {
|
when (status) {
|
||||||
is InitialSyncProgressService.Status.Progressing -> {
|
is SyncStatusService.Status.Progressing -> {
|
||||||
// Schedule a check of the bootstrap when the init sync will be finished
|
// Schedule a check of the bootstrap when the init sync will be finished
|
||||||
checkBootstrap = true
|
checkBootstrap = true
|
||||||
}
|
}
|
||||||
is InitialSyncProgressService.Status.Idle -> {
|
is SyncStatusService.Status.Idle -> {
|
||||||
if (checkBootstrap) {
|
if (checkBootstrap) {
|
||||||
checkBootstrap = false
|
checkBootstrap = false
|
||||||
maybeBootstrapCrossSigningAfterInitialSync()
|
maybeBootstrapCrossSigningAfterInitialSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
initialSyncProgressServiceStatus = status
|
syncStatusServiceStatus = status
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
package im.vector.app.features.home
|
package im.vector.app.features.home
|
||||||
|
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
|
|
||||||
data class HomeActivityViewState(
|
data class HomeActivityViewState(
|
||||||
val initialSyncProgressServiceStatus: InitialSyncProgressService.Status = InitialSyncProgressService.Status.Idle
|
val syncStatusServiceStatus: SyncStatusService.Status = SyncStatusService.Status.Idle
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
@ -440,7 +440,11 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
|
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
|
||||||
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
|
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
|
||||||
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
|
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
|
||||||
views.syncStateView.render(it.syncState)
|
views.syncStateView.render(
|
||||||
|
it.syncState,
|
||||||
|
it.incrementalSyncStatus,
|
||||||
|
it.pushCounter,
|
||||||
|
vectorPreferences.developerShowDebugInfo())
|
||||||
|
|
||||||
hasUnreadRooms = it.hasUnreadMessages
|
hasUnreadRooms = it.hasUnreadMessages
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,16 @@ import im.vector.app.features.call.webrtc.WebRtcCallManager
|
|||||||
import im.vector.app.features.createdirect.DirectRoomHelper
|
import im.vector.app.features.createdirect.DirectRoomHelper
|
||||||
import im.vector.app.features.invite.AutoAcceptInvites
|
import im.vector.app.features.invite.AutoAcceptInvites
|
||||||
import im.vector.app.features.invite.showInvites
|
import im.vector.app.features.invite.showInvites
|
||||||
|
import im.vector.app.features.settings.VectorDataStore
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
@ -56,10 +59,11 @@ import java.util.concurrent.TimeUnit
|
|||||||
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val uiStateRepository: UiStateRepository,
|
private val uiStateRepository: UiStateRepository,
|
||||||
|
private val vectorDataStore: VectorDataStore,
|
||||||
private val callManager: WebRtcCallManager,
|
private val callManager: WebRtcCallManager,
|
||||||
private val directRoomHelper: DirectRoomHelper,
|
private val directRoomHelper: DirectRoomHelper,
|
||||||
private val appStateHandler: AppStateHandler,
|
private val appStateHandler: AppStateHandler,
|
||||||
private val autoAcceptInvites: AutoAcceptInvites)
|
private val autoAcceptInvites: AutoAcceptInvites)
|
||||||
: VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
|
: VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
|
||||||
CallProtocolsChecker.Listener {
|
CallProtocolsChecker.Listener {
|
||||||
|
|
||||||
@ -89,6 +93,7 @@ private val autoAcceptInvites: AutoAcceptInvites)
|
|||||||
observeRoomGroupingMethod()
|
observeRoomGroupingMethod()
|
||||||
observeRoomSummaries()
|
observeRoomSummaries()
|
||||||
updateShowDialPadTab()
|
updateShowDialPadTab()
|
||||||
|
observeDataStore()
|
||||||
callManager.addProtocolsCheckerListener(this)
|
callManager.addProtocolsCheckerListener(this)
|
||||||
session.rx().liveUser(session.myUserId).execute {
|
session.rx().liveUser(session.myUserId).execute {
|
||||||
copy(
|
copy(
|
||||||
@ -97,6 +102,18 @@ private val autoAcceptInvites: AutoAcceptInvites)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeDataStore() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
vectorDataStore.pushCounterFlow.collect { nbOfPush ->
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
pushCounter = nbOfPush
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun handle(action: HomeDetailAction) {
|
override fun handle(action: HomeDetailAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is HomeDetailAction.SwitchTab -> handleSwitchTab(action)
|
is HomeDetailAction.SwitchTab -> handleSwitchTab(action)
|
||||||
@ -173,6 +190,17 @@ private val autoAcceptInvites: AutoAcceptInvites)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
|
|
||||||
|
session.getSyncStatusLive()
|
||||||
|
.asObservable()
|
||||||
|
.subscribe {
|
||||||
|
if (it is SyncStatusService.Status.IncrementalSyncStatus) {
|
||||||
|
setState {
|
||||||
|
copy(incrementalSyncStatus = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeRoomGroupingMethod() {
|
private fun observeRoomGroupingMethod() {
|
||||||
|
@ -22,6 +22,7 @@ import com.airbnb.mvrx.MvRxState
|
|||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.RoomGroupingMethod
|
import im.vector.app.RoomGroupingMethod
|
||||||
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
@ -39,6 +40,8 @@ data class HomeDetailViewState(
|
|||||||
val notificationHighlightRooms: Boolean = false,
|
val notificationHighlightRooms: Boolean = false,
|
||||||
val hasUnreadMessages: Boolean = false,
|
val hasUnreadMessages: Boolean = false,
|
||||||
val syncState: SyncState = SyncState.Idle,
|
val syncState: SyncState = SyncState.Idle,
|
||||||
|
val incrementalSyncStatus: SyncStatusService.Status.IncrementalSyncStatus = SyncStatusService.Status.IncrementalSyncIdle,
|
||||||
|
val pushCounter: Int = 0,
|
||||||
val showDialPadTab: Boolean = false
|
val showDialPadTab: Boolean = false
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
||||||
|
@ -387,8 +387,17 @@ class RoomDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
roomDetailViewModel.selectSubscribe(RoomDetailViewState::syncState) { syncState ->
|
roomDetailViewModel.selectSubscribe(
|
||||||
views.syncStateView.render(syncState)
|
RoomDetailViewState::syncState,
|
||||||
|
RoomDetailViewState::incrementalSyncStatus,
|
||||||
|
RoomDetailViewState::pushCounter
|
||||||
|
) { syncState, incrementalSyncStatus, pushCounter ->
|
||||||
|
views.syncStateView.render(
|
||||||
|
syncState,
|
||||||
|
incrementalSyncStatus,
|
||||||
|
pushCounter,
|
||||||
|
vectorPreferences.developerShowDebugInfo()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
roomDetailViewModel.observeViewEvents {
|
roomDetailViewModel.observeViewEvents {
|
||||||
|
@ -38,9 +38,9 @@ import im.vector.app.core.extensions.exhaustive
|
|||||||
import im.vector.app.core.mvrx.runCatchingToAsync
|
import im.vector.app.core.mvrx.runCatchingToAsync
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
|
|
||||||
import im.vector.app.features.attachments.toContentAttachmentData
|
import im.vector.app.features.attachments.toContentAttachmentData
|
||||||
import im.vector.app.features.call.conference.ConferenceEvent
|
import im.vector.app.features.call.conference.ConferenceEvent
|
||||||
|
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
|
||||||
import im.vector.app.features.call.conference.JitsiService
|
import im.vector.app.features.call.conference.JitsiService
|
||||||
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
import im.vector.app.features.call.lookup.CallProtocolsChecker
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
@ -57,12 +57,14 @@ import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
|
|||||||
import im.vector.app.features.home.room.typing.TypingHelper
|
import im.vector.app.features.home.room.typing.TypingHelper
|
||||||
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
|
import im.vector.app.features.settings.VectorDataStore
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.voice.VoicePlayerHelper
|
import im.vector.app.features.voice.VoicePlayerHelper
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.commonmark.parser.Parser
|
import org.commonmark.parser.Parser
|
||||||
@ -80,6 +82,7 @@ import org.matrix.android.sdk.api.session.events.model.isTextMessage
|
|||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.file.FileService
|
import org.matrix.android.sdk.api.session.file.FileService
|
||||||
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
@ -102,6 +105,7 @@ import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
|||||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||||
import org.matrix.android.sdk.api.util.toOptional
|
import org.matrix.android.sdk.api.util.toOptional
|
||||||
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
||||||
|
import org.matrix.android.sdk.rx.asObservable
|
||||||
import org.matrix.android.sdk.rx.rx
|
import org.matrix.android.sdk.rx.rx
|
||||||
import org.matrix.android.sdk.rx.unwrap
|
import org.matrix.android.sdk.rx.unwrap
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -111,6 +115,7 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
class RoomDetailViewModel @AssistedInject constructor(
|
class RoomDetailViewModel @AssistedInject constructor(
|
||||||
@Assisted private val initialState: RoomDetailViewState,
|
@Assisted private val initialState: RoomDetailViewState,
|
||||||
private val vectorPreferences: VectorPreferences,
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
private val vectorDataStore: VectorDataStore,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val rainbowGenerator: RainbowGenerator,
|
private val rainbowGenerator: RainbowGenerator,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
@ -174,6 +179,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
observeSummaryState()
|
observeSummaryState()
|
||||||
getUnreadState()
|
getUnreadState()
|
||||||
observeSyncState()
|
observeSyncState()
|
||||||
|
observeDataStore()
|
||||||
observeEventDisplayedActions()
|
observeEventDisplayedActions()
|
||||||
loadDraftIfAny()
|
loadDraftIfAny()
|
||||||
observeUnreadState()
|
observeUnreadState()
|
||||||
@ -198,6 +204,18 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeDataStore() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
vectorDataStore.pushCounterFlow.collect { nbOfPush ->
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
pushCounter = nbOfPush
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun prepareForEncryption() {
|
private fun prepareForEncryption() {
|
||||||
// check if there is not already a call made, or if there has been an error
|
// check if there is not already a call made, or if there has been an error
|
||||||
if (prepareToEncrypt.shouldLoad) {
|
if (prepareToEncrypt.shouldLoad) {
|
||||||
@ -1493,6 +1511,17 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
|
|
||||||
|
session.getSyncStatusLive()
|
||||||
|
.asObservable()
|
||||||
|
.subscribe { it ->
|
||||||
|
if (it is SyncStatusService.Status.IncrementalSyncStatus) {
|
||||||
|
setState {
|
||||||
|
copy(incrementalSyncStatus = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeRoomSummary() {
|
private fun observeRoomSummary() {
|
||||||
|
@ -21,6 +21,7 @@ import com.airbnb.mvrx.MvRxState
|
|||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
@ -77,6 +78,8 @@ data class RoomDetailViewState(
|
|||||||
val tombstoneEvent: Event? = null,
|
val tombstoneEvent: Event? = null,
|
||||||
val joinUpgradedRoomAsync: Async<String> = Uninitialized,
|
val joinUpgradedRoomAsync: Async<String> = Uninitialized,
|
||||||
val syncState: SyncState = SyncState.Idle,
|
val syncState: SyncState = SyncState.Idle,
|
||||||
|
val incrementalSyncStatus: SyncStatusService.Status.IncrementalSyncStatus = SyncStatusService.Status.IncrementalSyncIdle,
|
||||||
|
val pushCounter: Int = 0,
|
||||||
val highlightedEventId: String? = null,
|
val highlightedEventId: String? = null,
|
||||||
val unreadState: UnreadState = UnreadState.Unknown,
|
val unreadState: UnreadState = UnreadState.Unknown,
|
||||||
val canShowJumpToReadMarker: Boolean = true,
|
val canShowJumpToReadMarker: Boolean = true,
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.settings
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.intPreferencesKey
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "vector_settings")
|
||||||
|
|
||||||
|
class VectorDataStore @Inject constructor(
|
||||||
|
private val context: Context
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val pushCounter = intPreferencesKey("push_counter")
|
||||||
|
|
||||||
|
val pushCounterFlow: Flow<Int> = context.dataStore.data.map { preferences ->
|
||||||
|
preferences[pushCounter] ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun incrementPushCounter() {
|
||||||
|
context.dataStore.edit { settings ->
|
||||||
|
val currentCounterValue = settings[pushCounter] ?: 0
|
||||||
|
settings[pushCounter] = currentCounterValue + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -159,6 +159,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
|||||||
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
||||||
private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
||||||
private const val SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY"
|
private const val SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY"
|
||||||
|
private const val SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY = "SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY"
|
||||||
|
|
||||||
// SETTINGS_LABS_HIDE_TECHNICAL_E2E_ERRORS
|
// SETTINGS_LABS_HIDE_TECHNICAL_E2E_ERRORS
|
||||||
private const val SETTINGS_LABS_SHOW_COMPLETE_HISTORY_IN_ENCRYPTED_ROOM = "SETTINGS_LABS_SHOW_COMPLETE_HISTORY_IN_ENCRYPTED_ROOM"
|
private const val SETTINGS_LABS_SHOW_COMPLETE_HISTORY_IN_ENCRYPTED_ROOM = "SETTINGS_LABS_SHOW_COMPLETE_HISTORY_IN_ENCRYPTED_ROOM"
|
||||||
@ -312,6 +313,10 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
|||||||
return defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY, false)
|
return defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun developerShowDebugInfo(): Boolean {
|
||||||
|
return developerMode() && defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY, false)
|
||||||
|
}
|
||||||
|
|
||||||
fun shouldShowHiddenEvents(): Boolean {
|
fun shouldShowHiddenEvents(): Boolean {
|
||||||
return developerMode() && defaultPrefs.getBoolean(SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, false)
|
return developerMode() && defaultPrefs.getBoolean(SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, false)
|
||||||
}
|
}
|
||||||
|
@ -16,27 +16,41 @@
|
|||||||
|
|
||||||
package im.vector.app.features.sync.widget
|
package im.vector.app.features.sync.widget
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.widget.FrameLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.utils.isAirplaneModeOn
|
import im.vector.app.core.utils.isAirplaneModeOn
|
||||||
import im.vector.app.databinding.ViewSyncStateBinding
|
import im.vector.app.databinding.ViewSyncStateBinding
|
||||||
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||||
|
|
||||||
class SyncStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
class SyncStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||||
: FrameLayout(context, attrs, defStyle) {
|
: LinearLayout(context, attrs, defStyle) {
|
||||||
|
|
||||||
private val views: ViewSyncStateBinding
|
private val views: ViewSyncStateBinding
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.view_sync_state, this)
|
inflate(context, R.layout.view_sync_state, this)
|
||||||
views = ViewSyncStateBinding.bind(this)
|
views = ViewSyncStateBinding.bind(this)
|
||||||
|
orientation = VERTICAL
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(newState: SyncState) {
|
@SuppressLint("SetTextI18n")
|
||||||
|
fun render(newState: SyncState,
|
||||||
|
incrementalSyncStatus: SyncStatusService.Status.IncrementalSyncStatus,
|
||||||
|
pushCounter: Int,
|
||||||
|
showDebugInfo: Boolean
|
||||||
|
) {
|
||||||
|
views.syncStateDebugInfo.isVisible = showDebugInfo
|
||||||
|
if (showDebugInfo) {
|
||||||
|
views.syncStateDebugInfoText.text =
|
||||||
|
"Sync thread : ${newState.toHumanReadable()}\nSync request: ${incrementalSyncStatus.toHumanReadable()}"
|
||||||
|
views.syncStateDebugInfoPushCounter.text =
|
||||||
|
"Push: $pushCounter"
|
||||||
|
}
|
||||||
views.syncStateProgressBar.isVisible = newState is SyncState.Running && newState.afterPause
|
views.syncStateProgressBar.isVisible = newState is SyncState.Running && newState.afterPause
|
||||||
|
|
||||||
if (newState == SyncState.NoNetwork) {
|
if (newState == SyncState.NoNetwork) {
|
||||||
@ -48,4 +62,26 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute
|
|||||||
views.syncStateNoNetworkAirplane.isVisible = false
|
views.syncStateNoNetworkAirplane.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun SyncState.toHumanReadable(): String {
|
||||||
|
return when (this) {
|
||||||
|
SyncState.Idle -> "Idle"
|
||||||
|
SyncState.InvalidToken -> "InvalidToken"
|
||||||
|
SyncState.Killed -> "Killed"
|
||||||
|
SyncState.Killing -> "Killing"
|
||||||
|
SyncState.NoNetwork -> "NoNetwork"
|
||||||
|
SyncState.Paused -> "Paused"
|
||||||
|
is SyncState.Running -> "$this"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SyncStatusService.Status.IncrementalSyncStatus.toHumanReadable(): String {
|
||||||
|
return when (this) {
|
||||||
|
SyncStatusService.Status.IncrementalSyncIdle -> "Idle"
|
||||||
|
is SyncStatusService.Status.IncrementalSyncParsing -> "Parsing ${this.rooms} room(s) ${this.toDevice} toDevice(s)"
|
||||||
|
SyncStatusService.Status.IncrementalSyncError -> "Error"
|
||||||
|
SyncStatusService.Status.IncrementalSyncDone -> "Done"
|
||||||
|
else -> "?"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,34 @@
|
|||||||
tools:orientation="vertical"
|
tools:orientation="vertical"
|
||||||
tools:parentTag="android.widget.LinearLayout">
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/syncStateDebugInfo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/syncStateDebugInfoText"
|
||||||
|
style="@style/Widget.Vector.TextView.Caption"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
tools:text="debug info" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/syncStateDebugInfoPushCounter"
|
||||||
|
style="@style/Widget.Vector.TextView.Caption"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="123" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<!-- Trick to remove surrounding padding (clip from wrapping frame) -->
|
<!-- Trick to remove surrounding padding (clip from wrapping frame) -->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/syncStateProgressBar"
|
android:id="@+id/syncStateProgressBar"
|
||||||
|
@ -2659,6 +2659,9 @@
|
|||||||
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
||||||
<string name="template_settings_developer_mode_fail_fast_summary">${app_name} may crash more often when an unexpected error occurs</string>
|
<string name="template_settings_developer_mode_fail_fast_summary">${app_name} may crash more often when an unexpected error occurs</string>
|
||||||
|
|
||||||
|
<string name="settings_developer_mode_show_info_on_screen_title">Show debug info on screen</string>
|
||||||
|
<string name="settings_developer_mode_show_info_on_screen_summary">Show some useful info to help debugging the application</string>
|
||||||
|
|
||||||
<string name="command_description_shrug">Prepends ¯\\_(ツ)_/¯ to a plain-text message</string>
|
<string name="command_description_shrug">Prepends ¯\\_(ツ)_/¯ to a plain-text message</string>
|
||||||
|
|
||||||
<string name="create_room_encryption_title">"Enable encryption"</string>
|
<string name="create_room_encryption_title">"Enable encryption"</string>
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
<im.vector.app.core.preference.VectorSwitchPreference
|
<im.vector.app.core.preference.VectorSwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
|
|
||||||
android:icon="@drawable/ic_verification_glasses"
|
android:icon="@drawable/ic_verification_glasses"
|
||||||
|
android:key="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
|
||||||
android:summary="@string/settings_developer_mode_summary"
|
android:summary="@string/settings_developer_mode_summary"
|
||||||
android:title="@string/settings_developer_mode" />
|
android:title="@string/settings_developer_mode" />
|
||||||
|
|
||||||
@ -17,6 +17,13 @@
|
|||||||
android:key="SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
android:key="SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
||||||
android:title="@string/settings_labs_show_hidden_events_in_timeline" />
|
android:title="@string/settings_labs_show_hidden_events_in_timeline" />
|
||||||
|
|
||||||
|
<im.vector.app.core.preference.VectorSwitchPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
|
||||||
|
android:key="SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY"
|
||||||
|
android:summary="@string/settings_developer_mode_show_info_on_screen_summary"
|
||||||
|
android:title="@string/settings_developer_mode_show_info_on_screen_title" />
|
||||||
|
|
||||||
<im.vector.app.core.preference.VectorSwitchPreference
|
<im.vector.app.core.preference.VectorSwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
|
android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user