Merge remote-tracking branch 'origin/develop' into task/eric/when-arrow-alignment

# Conflicts:
#	matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt
#	matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
#	vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
#	vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
#	vector/src/main/java/im/vector/app/features/home/InitSyncStepFormatter.kt
#	vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
#	vector/src/main/java/im/vector/app/features/home/room/detail/timeline/style/TimelineMessageLayoutFactory.kt
#	vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt
This commit is contained in:
ericdecanini 2022-06-08 12:59:54 +02:00
commit 6df88fba59
72 changed files with 572 additions and 503 deletions

View File

@ -49,24 +49,34 @@ body:
### Once tested and validated internally ### Once tested and validated internally
- [ ] Create a new beta release on the GooglePlay console and upload the 4 signed Apks. - [ ] Create a new open testing release on the GooglePlay console and upload the 4 signed Apks.
- [ ] Check that the version codes are correct - [ ] Check that the version codes are correct
- [ ] Copy the fastlane change to the GooglePlay console in the section en-GB. - [ ] Copy the fastlane change to the GooglePlay console in the section en-GB.
- [ ] Push to beta release to 100% of the users - [ ] Push the open testing release to 100% of the users
- [ ] Notify the F-Droid team so that they can schedule the publication on F-Droid - [ ] Notify the F-Droid team [here](https://matrix.to/#/!LAAuJLQXYHjMNWKrCK:matrix.org?via=matrix.org&via=bubu1.eu&via=lant.uk) so that they can schedule the publication on F-Droid
- [ ] The application is available to the PlayStore testers (live). Google can take between 1 hour and up to 7 days to approve the release.
- [ ] The application is available to the F-Droid users.
### Once Live on PlayStore ### Once open testing is live on PlayStore
- [ ] Ping the Android public room and update its topic - [ ] Ping the Android public room and update its topic
- [ ] Add an entry in the internal diary
### After at least 2 days ### Once Live on F-Droid
- [ ] Update the Android public room topic
### After at least 2 days (generally next Monday)
- [ ] Check the [rageshakes](https://github.com/matrix-org/element-android-rageshakes/issues) - [ ] Check the [rageshakes](https://github.com/matrix-org/element-android-rageshakes/issues)
- [ ] Check the crash reports on the GooglePlay console - [ ] Check the crash reports on the GooglePlay console
- [ ] Check the Android Element room for any reported issues on the new version - [ ] Check the Android Element room for any reported issues on the new version
- [ ] If all is OK, push to production and notify Markus (Bubu) to release the F-Droid version - [ ] If all is OK, promote the open testing release to production. Generally using a 100% roll out, but can be a smaller value depending on the release content.
- [ ] Ping the Android public room and update its topic with the new available version - [ ] The application is available to the PlayStore users (live). Google can take (again!) between 1 hour and up to 7 days to approve the release.
### Once production is live on PlayStore
- [ ] Ping the Android public room and update its topic
- [ ] Add an entry in the internal diary
### Android SDK2 ### Android SDK2

View File

@ -43,7 +43,7 @@ plugins {
id "io.gitlab.arturbosch.detekt" version "1.20.0" id "io.gitlab.arturbosch.detekt" version "1.20.0"
// Dependency Analysis // Dependency Analysis
id 'com.autonomousapps.dependency-analysis' version "1.4.0" id 'com.autonomousapps.dependency-analysis' version "1.5.0"
} }
// https://github.com/jeremylong/DependencyCheck // https://github.com/jeremylong/DependencyCheck

5
changelog.d/6029.sdk Normal file
View File

@ -0,0 +1,5 @@
Some methods from `Session` have been moved to a new `SyncService`, that you can retrieve from a `Session`.
- `SyncStatusService` method has been moved to the new `SyncService`
- `InitSyncStep` have been moved and renamed to `InitialSyncStep`
- `SyncStatusService.Status` has been renamed to `SyncRequestState`
- The existing `SyncService` has been renamed to `SyncAndroidService` because of name clash with the new SDK Service

1
changelog.d/6209.bugfix Normal file
View File

@ -0,0 +1 @@
Fix wrong status of live location sharing in timeline

1
changelog.d/6244.feature Normal file
View File

@ -0,0 +1 @@
Re-organize location settings flags

View File

@ -50,7 +50,7 @@ ext.libs = [
androidx : [ androidx : [
'activity' : "androidx.activity:activity:1.4.0", 'activity' : "androidx.activity:activity:1.4.0",
'appCompat' : "androidx.appcompat:appcompat:1.4.2", 'appCompat' : "androidx.appcompat:appcompat:1.4.2",
'core' : "androidx.core:core-ktx:1.7.0", 'core' : "androidx.core:core-ktx:1.8.0",
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1", 'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3", 'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3",
'fragmentKtx' : "androidx.fragment:fragment-ktx:1.4.1", 'fragmentKtx' : "androidx.fragment:fragment-ktx:1.4.1",

View File

@ -88,7 +88,7 @@ class FlowSession(private val session: Session) {
} }
fun liveSyncState(): Flow<SyncState> { fun liveSyncState(): Flow<SyncState> {
return session.getSyncStateLive().asFlow() return session.syncService().getSyncStateLive().asFlow()
} }
fun livePushers(): Flow<List<Pusher>> { fun livePushers(): Flow<List<Pusher>> {

View File

@ -176,7 +176,7 @@ dependencies {
implementation libs.androidx.work implementation libs.androidx.work
// olm lib is now hosted in MavenCentral // olm lib is now hosted in MavenCentral
implementation 'org.matrix.android:olm-sdk:3.2.11' implementation 'org.matrix.android:olm-sdk:3.2.12'
// DI // DI
implementation libs.dagger.dagger implementation libs.dagger.dagger

View File

@ -137,11 +137,11 @@ class CommonTestHelper private constructor(context: Context) {
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) { fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
coroutineScope.launch { coroutineScope.launch {
session.startSync(true) session.syncService().startSync(true)
val syncLiveData = session.getSyncStateLive() val syncLiveData = session.syncService().getSyncStateLive()
val syncObserver = object : Observer<SyncState> { val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) { override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) { if (session.syncService().hasAlreadySynced()) {
lock.countDown() lock.countDown()
syncLiveData.removeObserver(this) syncLiveData.removeObserver(this)
} }
@ -160,10 +160,10 @@ class CommonTestHelper private constructor(context: Context) {
fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) { fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) {
waitWithLatch(timeout) { latch -> waitWithLatch(timeout) { latch ->
session.clearCache() session.clearCache()
val syncLiveData = session.getSyncStateLive() val syncLiveData = session.syncService().getSyncStateLive()
val syncObserver = object : Observer<SyncState> { val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) { override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) { if (session.syncService().hasAlreadySynced()) {
Timber.v("Clear cache and synced") Timber.v("Clear cache and synced")
syncLiveData.removeObserver(this) syncLiveData.removeObserver(this)
latch.countDown() latch.countDown()
@ -171,7 +171,7 @@ class CommonTestHelper private constructor(context: Context) {
} }
} }
syncLiveData.observeForever(syncObserver) syncLiveData.observeForever(syncObserver)
session.startSync(true) session.syncService().startSync(true)
} }
} }

View File

@ -424,7 +424,7 @@ class KeyShareTests : InstrumentedTest {
// /!\ Stop initial alice session syncing so that it can't reply // /!\ Stop initial alice session syncing so that it can't reply
aliceSession.cryptoService().enableKeyGossiping(false) aliceSession.cryptoService().enableKeyGossiping(false)
aliceSession.stopSync() aliceSession.syncService().stopSync()
// Let's now try to request // Let's now try to request
aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root) aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root)
@ -447,7 +447,7 @@ class KeyShareTests : InstrumentedTest {
// let's wake up alice // let's wake up alice
aliceSession.cryptoService().enableKeyGossiping(true) aliceSession.cryptoService().enableKeyGossiping(true)
aliceSession.startSync(true) aliceSession.syncService().startSync(true)
// We should now get a reply from first session // We should now get a reply from first session
commonTestHelper.waitWithLatch { latch -> commonTestHelper.waitWithLatch { latch ->

View File

@ -83,7 +83,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@ -97,7 +97,7 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener) timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000) commonTestHelper.await(lock, 600_000)
} }
aliceSession.stopSync() aliceSession.syncService().stopSync()
} }
@Test @Test
@ -144,7 +144,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@ -156,9 +156,9 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener) timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000) commonTestHelper.await(lock, 600_000)
} }
aliceSession.stopSync() aliceSession.syncService().stopSync()
bobSession.startSync(true) bobSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@ -170,7 +170,7 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener) timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000) commonTestHelper.await(lock, 600_000)
} }
bobSession.stopSync() bobSession.syncService().stopSync()
} }
@Test @Test
@ -217,7 +217,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@ -233,7 +233,7 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener) timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000) commonTestHelper.await(lock, 600_000)
} }
aliceSession.stopSync() aliceSession.syncService().stopSync()
} }
@Test @Test
@ -314,7 +314,7 @@ class ThreadMessagingTest : InstrumentedTest {
val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@ -338,6 +338,6 @@ class ThreadMessagingTest : InstrumentedTest {
timeline.addListener(eventsListener) timeline.addListener(eventsListener)
commonTestHelper.await(lock, 600_000) commonTestHelper.await(lock, 600_000)
} }
aliceSession.stopSync() aliceSession.syncService().stopSync()
} }
} }

View File

@ -57,7 +57,7 @@ class PollAggregationTest : InstrumentedTest {
// Bob creates a poll // Bob creates a poll
roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions) roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions)
aliceSession.startSync(true) aliceSession.syncService().startSync(true)
val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30)) val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30))
aliceTimeline.start() aliceTimeline.start()
@ -133,7 +133,7 @@ class PollAggregationTest : InstrumentedTest {
aliceTimeline.removeAllListeners() aliceTimeline.removeAllListeners()
aliceSession.stopSync() aliceSession.syncService().stopSync()
aliceTimeline.dispose() aliceTimeline.dispose()
} }

View File

@ -88,7 +88,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
} }
// Bob stop to sync // Bob stop to sync
bobSession.stopSync() bobSession.syncService().stopSync()
val firstMessage = "First messages from Alice" val firstMessage = "First messages from Alice"
// Alice sends 30 messages // Alice sends 30 messages
@ -101,7 +101,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
.eventId .eventId
// Bob start to sync // Bob start to sync
bobSession.startSync(true) bobSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
@ -125,7 +125,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
} }
// Bob stop to sync // Bob stop to sync
bobSession.stopSync() bobSession.syncService().stopSync()
val secondMessage = "Second messages from Alice" val secondMessage = "Second messages from Alice"
// Alice sends again 30 messages // Alice sends again 30 messages
@ -136,7 +136,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
) )
// Bob start to sync // Bob start to sync
bobSession.startSync(true) bobSession.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)

View File

@ -71,7 +71,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30)) val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30))
timelineForCurrentMember.start() timelineForCurrentMember.start()
session.startSync(true) session.syncService().startSync(true)
run { run {
val lock = CountDownLatch(1) val lock = CountDownLatch(1)
@ -92,7 +92,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
timelineForCurrentMember.addListener(eventsListener) timelineForCurrentMember.addListener(eventsListener)
commonTestHelper.await(lock, 600_000) commonTestHelper.await(lock, 600_000)
} }
session.stopSync() session.syncService().stopSync()
} }
} }
} }

View File

@ -17,8 +17,6 @@
package org.matrix.android.sdk.api.session package org.matrix.android.sdk.api.session
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import kotlinx.coroutines.flow.SharedFlow
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.auth.data.SessionParams
@ -37,7 +35,6 @@ 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.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
@ -55,8 +52,7 @@ import org.matrix.android.sdk.api.session.signout.SignOutService
import org.matrix.android.sdk.api.session.space.SpaceService import org.matrix.android.sdk.api.session.space.SpaceService
import org.matrix.android.sdk.api.session.statistics.StatisticsListener import org.matrix.android.sdk.api.session.statistics.StatisticsListener
import org.matrix.android.sdk.api.session.sync.FilterService import org.matrix.android.sdk.api.session.sync.FilterService
import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.session.sync.SyncService
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
@ -98,59 +94,11 @@ interface Session {
@MainThread @MainThread
fun open() fun open()
/**
* Requires a one time background sync.
*/
fun requireBackgroundSync()
/**
* Launches infinite self rescheduling background syncs via the WorkManager.
*
* While dozing, syncs will only occur during maintenance windows.
* For reliability it's recommended to also start a long running foreground service
* along with disabling battery optimizations.
*/
fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
fun stopAnyBackgroundSync()
/**
* This method start the sync thread.
*/
fun startSync(fromForeground: Boolean)
/**
* This method stop the sync thread.
*/
fun stopSync()
/** /**
* Clear cache of the session. * Clear cache of the session.
*/ */
suspend fun clearCache() suspend fun clearCache()
/**
* This method allows to listen the sync state.
* @return a [LiveData] of [SyncState].
*/
fun getSyncStateLive(): LiveData<SyncState>
/**
* This method returns the current sync state.
* @return the current [SyncState].
*/
fun getSyncState(): SyncState
/**
* This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
*/
fun syncFlow(): SharedFlow<SyncResponse>
/**
* This methods return true if an initial sync has been processed.
*/
fun hasAlreadySynced(): Boolean
/** /**
* This method allow to close a session. It does stop some services. * This method allow to close a session. It does stop some services.
*/ */
@ -247,9 +195,9 @@ interface Session {
fun termsService(): TermsService fun termsService(): TermsService
/** /**
* Returns the SyncStatusService associated with the session. * Returns the SyncService associated with the session.
*/ */
fun syncStatusService(): SyncStatusService fun syncService(): SyncService
/** /**
* Returns the SecureStorageService associated with the session. * Returns the SecureStorageService associated with the session.

View File

@ -1,50 +0,0 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.initsync
import androidx.lifecycle.LiveData
interface SyncStatusService {
fun getSyncStatusLive(): LiveData<Status>
sealed class Status {
/**
* For initial sync.
*/
abstract class InitialSyncStatus : Status()
object Idle : InitialSyncStatus()
data class InitialSyncProgressing(
val initSyncStep: InitSyncStep,
val percentProgress: Int = 0
) : 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()
}
}

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package org.matrix.android.sdk.api.session.initsync package org.matrix.android.sdk.api.session.sync
enum class InitSyncStep { enum class InitialSyncStep {
ServerComputing, ServerComputing,
Downloading, Downloading,
ImportingAccount, ImportingAccount,

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.sync
sealed interface SyncRequestState {
/**
* For initial sync.
*/
interface InitialSyncRequestState : SyncRequestState
object Idle : InitialSyncRequestState
data class InitialSyncProgressing(
val initialSyncStep: InitialSyncStep,
val percentProgress: Int = 0
) : InitialSyncRequestState
/**
* For incremental sync.
*/
interface IncrementalSyncRequestState : SyncRequestState
object IncrementalSyncIdle : IncrementalSyncRequestState
data class IncrementalSyncParsing(
val rooms: Int,
val toDevice: Int
) : IncrementalSyncRequestState
object IncrementalSyncError : IncrementalSyncRequestState
object IncrementalSyncDone : IncrementalSyncRequestState
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.sync
import androidx.lifecycle.LiveData
import kotlinx.coroutines.flow.SharedFlow
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
interface SyncService {
/**
* This method start the sync thread.
*/
fun startSync(fromForeground: Boolean)
/**
* This method stop the sync thread.
*/
fun stopSync()
/**
* Requires a one time background sync.
*/
fun requireBackgroundSync()
/**
* Launches infinite self rescheduling background syncs via the WorkManager.
*
* While dozing, syncs will only occur during maintenance windows.
* For reliability it's recommended to also start a long running foreground service
* along with disabling battery optimizations.
*/
fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
fun stopAnyBackgroundSync()
/**
* This method returns the current sync state.
* @return the current [SyncState].
*/
fun getSyncState(): SyncState
/**
* This method allows to listen the sync state.
* @return a [LiveData] of [SyncState].
*/
fun getSyncStateLive(): LiveData<SyncState>
/**
* Get the [SyncRequestState] as a LiveData.
*/
fun getSyncRequestStateLive(): LiveData<SyncRequestState>
/**
* This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
*/
fun syncFlow(): SharedFlow<SyncResponse>
/**
* This methods return true if an initial sync has been processed.
*/
fun hasAlreadySynced(): Boolean
}

View File

@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean
* in order to be able to perform a sync even if the app is not running. * in order to be able to perform a sync even if the app is not running.
* The <receiver> and <service> must be declared in the Manifest or the app using the SDK * The <receiver> and <service> must be declared in the Manifest or the app using the SDK
*/ */
abstract class SyncService : Service() { abstract class SyncAndroidService : Service() {
private var sessionId: String? = null private var sessionId: String? = null
private var mIsSelfDestroyed: Boolean = false private var mIsSelfDestroyed: Boolean = false
@ -158,9 +158,9 @@ abstract class SyncService : Service() {
// never do that in foreground, let the syncThread work // never do that in foreground, let the syncThread work
syncTask.execute(params) syncTask.execute(params)
// Start sync if we were doing an initial sync and the syncThread is not launched yet // Start sync if we were doing an initial sync and the syncThread is not launched yet
if (isInitialSync && session.getSyncState() == SyncState.Idle) { if (isInitialSync && session.syncService().getSyncState() == SyncState.Idle) {
val isForeground = !backgroundDetectionObserver.isInBackground val isForeground = !backgroundDetectionObserver.isInBackground
session.startSync(isForeground) session.syncService().startSync(isForeground)
} }
stopMe() stopMe()
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
@ -210,7 +210,7 @@ abstract class SyncService : Service() {
session = sessionComponent.session() session = sessionComponent.session()
sessionId = safeSessionId sessionId = safeSessionId
syncTask = sessionComponent.syncTask() syncTask = sessionComponent.syncTask()
isInitialSync = !session.hasAlreadySynced() isInitialSync = !session.syncService().hasAlreadySynced()
networkConnectivityChecker = sessionComponent.networkConnectivityChecker() networkConnectivityChecker = sessionComponent.networkConnectivityChecker()
taskExecutor = sessionComponent.taskExecutor() taskExecutor = sessionComponent.taskExecutor()
coroutineDispatchers = sessionComponent.coroutineDispatchers() coroutineDispatchers = sessionComponent.coroutineDispatchers()

View File

@ -55,7 +55,7 @@ internal class SessionManager @Inject constructor(
fun stopSession(sessionId: String) { fun stopSession(sessionId: String) {
val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId") val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId")
sessionComponent.session().stopSync() sessionComponent.session().syncService().stopSync()
} }
fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent { fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {

View File

@ -44,7 +44,6 @@ 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.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
@ -61,6 +60,7 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi
import org.matrix.android.sdk.api.session.signout.SignOutService import org.matrix.android.sdk.api.session.signout.SignOutService
import org.matrix.android.sdk.api.session.space.SpaceService import org.matrix.android.sdk.api.session.space.SpaceService
import org.matrix.android.sdk.api.session.sync.FilterService import org.matrix.android.sdk.api.session.sync.FilterService
import org.matrix.android.sdk.api.session.sync.SyncService
import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
import org.matrix.android.sdk.api.session.typing.TypingUsersTracker import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
@ -76,13 +76,8 @@ import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.network.GlobalErrorHandler import org.matrix.android.sdk.internal.network.GlobalErrorHandler
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
import org.matrix.android.sdk.internal.session.sync.job.SyncThread
import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
import org.matrix.android.sdk.internal.util.createUIHandler import org.matrix.android.sdk.internal.util.createUIHandler
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider
@SessionScope @SessionScope
internal class DefaultSession @Inject constructor( internal class DefaultSession @Inject constructor(
@ -112,16 +107,14 @@ internal class DefaultSession @Inject constructor(
private val permalinkService: Lazy<PermalinkService>, private val permalinkService: Lazy<PermalinkService>,
private val secureStorageService: Lazy<SecureStorageService>, private val secureStorageService: Lazy<SecureStorageService>,
private val profileService: Lazy<ProfileService>, private val profileService: Lazy<ProfileService>,
private val syncService: Lazy<SyncService>,
private val mediaService: Lazy<MediaService>, private val mediaService: Lazy<MediaService>,
private val widgetService: Lazy<WidgetService>, private val widgetService: Lazy<WidgetService>,
private val syncThreadProvider: Provider<SyncThread>,
private val contentUrlResolver: ContentUrlResolver, private val contentUrlResolver: ContentUrlResolver,
private val syncTokenStore: SyncTokenStore,
private val sessionParamsStore: SessionParamsStore, private val sessionParamsStore: SessionParamsStore,
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 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>,
@ -138,14 +131,11 @@ internal class DefaultSession @Inject constructor(
private val toDeviceService: Lazy<ToDeviceService>, private val toDeviceService: Lazy<ToDeviceService>,
private val eventStreamService: Lazy<EventStreamService>, private val eventStreamService: Lazy<EventStreamService>,
@UnauthenticatedWithCertificate @UnauthenticatedWithCertificate
private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient> private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>,
private val sessionState: SessionState,
) : Session, ) : Session,
GlobalErrorHandler.Listener { GlobalErrorHandler.Listener {
private var isOpen = false
private var syncThread: SyncThread? = null
private val uiHandler = createUIHandler() private val uiHandler = createUIHandler()
override val isOpenable: Boolean override val isOpenable: Boolean
@ -153,8 +143,7 @@ internal class DefaultSession @Inject constructor(
@MainThread @MainThread
override fun open() { override fun open() {
assert(!isOpen) sessionState.setIsOpen(true)
isOpen = true
globalErrorHandler.listener = this globalErrorHandler.listener = this
cryptoService.get().ensureDevice() cryptoService.get().ensureDevice()
uiHandler.post { uiHandler.post {
@ -167,40 +156,9 @@ internal class DefaultSession @Inject constructor(
} }
} }
override fun requireBackgroundSync() {
SyncWorker.requireBackgroundSync(workManagerProvider, sessionId)
}
override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) {
SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds)
}
override fun stopAnyBackgroundSync() {
SyncWorker.stopAnyBackgroundSync(workManagerProvider)
}
override fun startSync(fromForeground: Boolean) {
Timber.i("Starting sync thread")
assert(isOpen)
val localSyncThread = getSyncThread()
localSyncThread.setInitialForeground(fromForeground)
if (!localSyncThread.isAlive) {
localSyncThread.start()
} else {
localSyncThread.restart()
Timber.w("Attempt to start an already started thread")
}
}
override fun stopSync() {
assert(isOpen)
syncThread?.kill()
syncThread = null
}
override fun close() { override fun close() {
assert(isOpen) assert(sessionState.isOpen)
stopSync() syncService.get().stopSync()
// timelineEventDecryptor.destroy() // timelineEventDecryptor.destroy()
uiHandler.post { uiHandler.post {
lifecycleObservers.forEach { it.onSessionStopped(this) } lifecycleObservers.forEach { it.onSessionStopped(this) }
@ -210,28 +168,12 @@ internal class DefaultSession @Inject constructor(
} }
cryptoService.get().close() cryptoService.get().close()
globalErrorHandler.listener = null globalErrorHandler.listener = null
isOpen = false sessionState.setIsOpen(false)
}
override fun getSyncStateLive() = getSyncThread().liveState()
override fun syncFlow() = getSyncThread().syncFlow()
override fun getSyncState() = getSyncThread().currentState()
override fun hasAlreadySynced(): Boolean {
return syncTokenStore.getLastToken() != null
}
private fun getSyncThread(): SyncThread {
return syncThread ?: syncThreadProvider.get().also {
syncThread = it
}
} }
override suspend fun clearCache() { override suspend fun clearCache() {
stopSync() syncService.get().stopSync()
stopAnyBackgroundSync() syncService.get().stopAnyBackgroundSync()
uiHandler.post { uiHandler.post {
lifecycleObservers.forEach { lifecycleObservers.forEach {
it.onClearCache(this) it.onClearCache(this)
@ -271,7 +213,7 @@ internal class DefaultSession @Inject constructor(
override fun pushersService(): PushersService = pushersService.get() override fun pushersService(): PushersService = pushersService.get()
override fun eventService(): EventService = eventService.get() override fun eventService(): EventService = eventService.get()
override fun termsService(): TermsService = termsService.get() override fun termsService(): TermsService = termsService.get()
override fun syncStatusService(): SyncStatusService = syncStatusService.get() override fun syncService(): SyncService = syncService.get()
override fun secureStorageService(): SecureStorageService = secureStorageService.get() override fun secureStorageService(): SecureStorageService = secureStorageService.get()
override fun profileService(): ProfileService = profileService.get() override fun profileService(): ProfileService = profileService.get()
override fun presenceService(): PresenceService = presenceService.get() override fun presenceService(): PresenceService = presenceService.get()

View File

@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.session.ToDeviceService
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.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
@ -82,7 +81,6 @@ 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.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
@ -362,9 +360,6 @@ internal abstract class SessionModule {
@IntoSet @IntoSet
abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver
@Binds
abstract fun bindSyncStatusService(service: DefaultSyncStatusService): SyncStatusService
@Binds @Binds
abstract fun bindSecureStorageService(service: DefaultSecureStorageService): SecureStorageService abstract fun bindSecureStorageService(service: DefaultSecureStorageService): SecureStorageService

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session
import javax.inject.Inject
@SessionScope
internal class SessionState @Inject constructor() {
var isOpen = false
private set
/**
* Set the new state. Throw if already in the new state.
*/
fun setIsOpen(newState: Boolean) {
assert(newState != isOpen)
isOpen = newState
}
}

View File

@ -75,6 +75,7 @@ internal class DeactivateLiveLocationShareWorker(context: Context, params: Worke
private suspend fun deactivateLiveLocationShare(params: Params) { private suspend fun deactivateLiveLocationShare(params: Params) {
awaitTransaction(realmConfiguration) { realm -> awaitTransaction(realmConfiguration) { realm ->
Timber.d("deactivating live with id=${params.eventId}")
val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.get( val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.get(
realm = realm, realm = realm,
roomId = params.roomId, roomId = params.roomId,

View File

@ -67,16 +67,18 @@ internal class LiveLocationAggregationProcessor @Inject constructor(
eventId = targetEventId eventId = targetEventId
) )
Timber.d("updating summary of id=$targetEventId with isLive=${content.isLive}") // remote event can stay with isLive == true while the local summary is no more active
val isActive = aggregatedSummary.isActive.orTrue() && isLive
val endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) } val endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) }
Timber.d("updating summary of id=$targetEventId with isActive=$isActive and endTimestamp=$endOfLiveTimestampMillis")
aggregatedSummary.endOfLiveTimestampMillis = endOfLiveTimestampMillis aggregatedSummary.endOfLiveTimestampMillis = endOfLiveTimestampMillis
aggregatedSummary.isActive = isLive aggregatedSummary.isActive = isActive
aggregatedSummary.userId = event.senderId aggregatedSummary.userId = event.senderId
deactivateAllPreviousBeacons(realm, roomId, event.senderId, targetEventId) deactivateAllPreviousBeacons(realm, roomId, event.senderId, targetEventId)
if (isLive) { if (isActive) {
scheduleDeactivationAfterTimeout(targetEventId, roomId, endOfLiveTimestampMillis) scheduleDeactivationAfterTimeout(targetEventId, roomId, endOfLiveTimestampMillis)
} else { } else {
cancelDeactivationAfterTimeout(targetEventId, roomId) cancelDeactivationAfterTimeout(targetEventId, roomId)
@ -90,6 +92,7 @@ internal class LiveLocationAggregationProcessor @Inject constructor(
val workData = WorkerParamsFactory.toData(workParams) val workData = WorkerParamsFactory.toData(workParams)
val workName = DeactivateLiveLocationShareWorker.getWorkName(eventId = eventId, roomId = roomId) val workName = DeactivateLiveLocationShareWorker.getWorkName(eventId = eventId, roomId = roomId)
val workDelayMillis = (endOfLiveTimestampMillis - clock.epochMillis()).coerceAtLeast(0) val workDelayMillis = (endOfLiveTimestampMillis - clock.epochMillis()).coerceAtLeast(0)
Timber.d("scheduling deactivation of $eventId after $workDelayMillis millis")
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<DeactivateLiveLocationShareWorker>() val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<DeactivateLiveLocationShareWorker>()
.setInitialDelay(workDelayMillis, TimeUnit.MILLISECONDS) .setInitialDelay(workDelayMillis, TimeUnit.MILLISECONDS)
.setInputData(workData) .setInputData(workData)

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.sync
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.session.sync.SyncService
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.session.SessionState
import org.matrix.android.sdk.internal.session.sync.job.SyncThread
import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Provider
internal class DefaultSyncService @Inject constructor(
@SessionId val sessionId: String,
private val workManagerProvider: WorkManagerProvider,
private val syncThreadProvider: Provider<SyncThread>,
private val syncTokenStore: SyncTokenStore,
private val syncRequestStateTracker: SyncRequestStateTracker,
private val sessionState: SessionState,
) : SyncService {
private var syncThread: SyncThread? = null
override fun requireBackgroundSync() {
SyncWorker.requireBackgroundSync(workManagerProvider, sessionId)
}
override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) {
SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds)
}
override fun stopAnyBackgroundSync() {
SyncWorker.stopAnyBackgroundSync(workManagerProvider)
}
override fun startSync(fromForeground: Boolean) {
Timber.i("Starting sync thread")
assert(sessionState.isOpen)
val localSyncThread = getSyncThread()
localSyncThread.setInitialForeground(fromForeground)
if (!localSyncThread.isAlive) {
localSyncThread.start()
} else {
localSyncThread.restart()
Timber.w("Attempt to start an already started thread")
}
}
override fun stopSync() {
assert(sessionState.isOpen)
syncThread?.kill()
syncThread = null
}
override fun getSyncStateLive() = getSyncThread().liveState()
override fun syncFlow() = getSyncThread().syncFlow()
override fun getSyncState() = getSyncThread().currentState()
override fun getSyncRequestStateLive(): LiveData<SyncRequestState> {
return syncRequestStateTracker.syncRequestState
}
override fun hasAlreadySynced(): Boolean {
return syncTokenStore.getLastToken() != null
}
private fun getSyncThread(): SyncThread {
return syncThread ?: syncThreadProvider.get().also {
syncThread = it
}
}
}

View File

@ -14,18 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
package org.matrix.android.sdk.internal.session.initsync package org.matrix.android.sdk.internal.session.sync
import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStep
internal inline fun <T> reportSubtask( internal inline fun <T> reportSubtask(
reporter: ProgressReporter?, reporter: ProgressReporter?,
initSyncStep: InitSyncStep, initialSyncStep: InitialSyncStep,
totalProgress: Int, totalProgress: Int,
parentWeight: Float, parentWeight: Float,
block: () -> T block: () -> T
): T { ): T {
reporter?.startTask(initSyncStep, totalProgress, parentWeight) reporter?.startTask(initialSyncStep, totalProgress, parentWeight)
return block().also { return block().also {
reporter?.endTask() reporter?.endTask()
} }
@ -33,12 +33,12 @@ internal inline fun <T> reportSubtask(
internal inline fun <K, V, R> Map<out K, V>.mapWithProgress( internal inline fun <K, V, R> Map<out K, V>.mapWithProgress(
reporter: ProgressReporter?, reporter: ProgressReporter?,
initSyncStep: InitSyncStep, initialSyncStep: InitialSyncStep,
parentWeight: Float, parentWeight: Float,
transform: (Map.Entry<K, V>) -> R transform: (Map.Entry<K, V>) -> R
): List<R> { ): List<R> {
var current = 0F var current = 0F
reporter?.startTask(initSyncStep, count() + 1, parentWeight) reporter?.startTask(initialSyncStep, count() + 1, parentWeight)
return map { return map {
reporter?.reportProgress(current) reporter?.reportProgress(current)
current++ current++

View File

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package org.matrix.android.sdk.internal.session.initsync package org.matrix.android.sdk.internal.session.sync
import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStep
internal interface ProgressReporter { internal interface ProgressReporter {
fun startTask( fun startTask(
initSyncStep: InitSyncStep, initialSyncStep: InitialSyncStep,
totalProgress: Int, totalProgress: Int,
parentWeight: Float parentWeight: Float
) )

View File

@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import org.matrix.android.sdk.api.session.sync.SyncService
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import retrofit2.Retrofit import retrofit2.Retrofit
@ -35,6 +36,9 @@ internal abstract class SyncModule {
} }
} }
@Binds
abstract fun bindSyncService(service: DefaultSyncService): SyncService
@Binds @Binds
abstract fun bindSyncTask(task: DefaultSyncTask): SyncTask abstract fun bindSyncTask(task: DefaultSyncTask): SyncTask

View File

@ -13,42 +13,37 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.matrix.android.sdk.internal.session.initsync
import androidx.lifecycle.LiveData package org.matrix.android.sdk.internal.session.sync
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStep
import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.sync.SyncRequestState
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 DefaultSyncStatusService @Inject constructor() : internal class SyncRequestStateTracker @Inject constructor() :
SyncStatusService,
ProgressReporter { ProgressReporter {
private val status = MutableLiveData<SyncStatusService.Status>() val syncRequestState = MutableLiveData<SyncRequestState>()
private var rootTask: TaskInfo? = null private var rootTask: TaskInfo? = null
override fun getSyncStatusLive(): LiveData<SyncStatusService.Status> {
return status
}
// Only to be used for incremental sync // Only to be used for incremental sync
fun setStatus(newStatus: SyncStatusService.Status.IncrementalSyncStatus) { fun setSyncRequestState(newSyncRequestState: SyncRequestState.IncrementalSyncRequestState) {
status.postValue(newStatus) syncRequestState.postValue(newSyncRequestState)
} }
/** /**
* Create a rootTask. * Create a rootTask.
*/ */
fun startRoot( fun startRoot(
initSyncStep: InitSyncStep, initialSyncStep: InitialSyncStep,
totalProgress: Int totalProgress: Int
) { ) {
endAll() endAll()
rootTask = TaskInfo(initSyncStep, totalProgress, null, 1F) rootTask = TaskInfo(initialSyncStep, totalProgress, null, 1F)
reportProgress(0F) reportProgress(0F)
} }
@ -56,13 +51,13 @@ internal class DefaultSyncStatusService @Inject constructor() :
* Add a child to the leaf. * Add a child to the leaf.
*/ */
override fun startTask( override fun startTask(
initSyncStep: InitSyncStep, initialSyncStep: InitialSyncStep,
totalProgress: Int, totalProgress: Int,
parentWeight: Float parentWeight: Float
) { ) {
val currentLeaf = rootTask?.leaf() ?: return val currentLeaf = rootTask?.leaf() ?: return
currentLeaf.child = TaskInfo( currentLeaf.child = TaskInfo(
initSyncStep = initSyncStep, initialSyncStep = initialSyncStep,
totalProgress = totalProgress, totalProgress = totalProgress,
parent = currentLeaf, parent = currentLeaf,
parentWeight = parentWeight parentWeight = parentWeight
@ -76,7 +71,7 @@ internal class DefaultSyncStatusService @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(SyncStatusService.Status.InitialSyncProgressing(leaf.initSyncStep, root.currentProgress.toInt())) syncRequestState.postValue(SyncRequestState.InitialSyncProgressing(leaf.initialSyncStep, root.currentProgress.toInt()))
} }
} }
} }
@ -91,13 +86,13 @@ internal class DefaultSyncStatusService @Inject constructor() :
// And close it // And close it
endedTask.parent.child = null endedTask.parent.child = null
} else { } else {
status.postValue(SyncStatusService.Status.Idle) syncRequestState.postValue(SyncRequestState.Idle)
} }
} }
} }
fun endAll() { fun endAll() {
rootTask = null rootTask = null
status.postValue(SyncStatusService.Status.Idle) syncRequestState.postValue(SyncRequestState.Idle)
} }
} }

View File

@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.sync
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
import org.matrix.android.sdk.api.session.pushrules.PushRuleService import org.matrix.android.sdk.api.session.pushrules.PushRuleService
import org.matrix.android.sdk.api.session.pushrules.RuleScope import org.matrix.android.sdk.api.session.pushrules.RuleScope
import org.matrix.android.sdk.api.session.sync.InitialSyncStep
import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
import org.matrix.android.sdk.api.session.sync.model.SyncResponse import org.matrix.android.sdk.api.session.sync.model.SyncResponse
@ -32,8 +32,6 @@ import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.session.SessionListeners import org.matrix.android.sdk.internal.session.SessionListeners
import org.matrix.android.sdk.internal.session.dispatchTo import org.matrix.android.sdk.internal.session.dispatchTo
import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
import org.matrix.android.sdk.internal.session.initsync.reportSubtask
import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask
import org.matrix.android.sdk.internal.session.sync.handler.CryptoSyncHandler import org.matrix.android.sdk.internal.session.sync.handler.CryptoSyncHandler
import org.matrix.android.sdk.internal.session.sync.handler.GroupSyncHandler import org.matrix.android.sdk.internal.session.sync.handler.GroupSyncHandler
@ -90,7 +88,7 @@ internal class SyncResponseHandler @Inject constructor(
// to ensure to decrypt them properly // to ensure to decrypt them properly
measureTimeMillis { measureTimeMillis {
Timber.v("Handle toDevice") Timber.v("Handle toDevice")
reportSubtask(reporter, InitSyncStep.ImportingAccountCrypto, 100, 0.1f) { reportSubtask(reporter, InitialSyncStep.ImportingAccountCrypto, 100, 0.1f) {
if (syncResponse.toDevice != null) { if (syncResponse.toDevice != null) {
cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter) cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter)
} }
@ -111,7 +109,7 @@ internal class SyncResponseHandler @Inject constructor(
// IMPORTANT nothing should be suspend here as we are accessing the realm instance (thread local) // IMPORTANT nothing should be suspend here as we are accessing the realm instance (thread local)
measureTimeMillis { measureTimeMillis {
Timber.v("Handle rooms") Timber.v("Handle rooms")
reportSubtask(reporter, InitSyncStep.ImportingAccountRoom, 1, 0.7f) { reportSubtask(reporter, InitialSyncStep.ImportingAccountRoom, 1, 0.7f) {
if (syncResponse.rooms != null) { if (syncResponse.rooms != null) {
roomSyncHandler.handle(realm, syncResponse.rooms, isInitialSync, aggregator, reporter) roomSyncHandler.handle(realm, syncResponse.rooms, isInitialSync, aggregator, reporter)
} }
@ -121,7 +119,7 @@ internal class SyncResponseHandler @Inject constructor(
} }
measureTimeMillis { measureTimeMillis {
reportSubtask(reporter, InitSyncStep.ImportingAccountGroups, 1, 0.1f) { reportSubtask(reporter, InitialSyncStep.ImportingAccountGroups, 1, 0.1f) {
Timber.v("Handle groups") Timber.v("Handle groups")
if (syncResponse.groups != null) { if (syncResponse.groups != null) {
groupSyncHandler.handle(realm, syncResponse.groups, reporter) groupSyncHandler.handle(realm, syncResponse.groups, reporter)
@ -132,7 +130,7 @@ internal class SyncResponseHandler @Inject constructor(
} }
measureTimeMillis { measureTimeMillis {
reportSubtask(reporter, InitSyncStep.ImportingAccountData, 1, 0.1f) { reportSubtask(reporter, InitialSyncStep.ImportingAccountData, 1, 0.1f) {
Timber.v("Handle accountData") Timber.v("Handle accountData")
userAccountDataSyncHandler.handle(realm, syncResponse.accountData) userAccountDataSyncHandler.handle(realm, syncResponse.accountData)
} }

View File

@ -21,10 +21,10 @@ import okhttp3.ResponseBody
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.logger.LoggerTag
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
import org.matrix.android.sdk.api.session.statistics.StatisticEvent import org.matrix.android.sdk.api.session.statistics.StatisticEvent
import org.matrix.android.sdk.api.session.sync.InitialSyncStep
import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.session.sync.initialSyncStrategy import org.matrix.android.sdk.api.session.sync.initialSyncStrategy
import org.matrix.android.sdk.api.session.sync.model.LazyRoomSyncEphemeral import org.matrix.android.sdk.api.session.sync.model.LazyRoomSyncEphemeral
import org.matrix.android.sdk.api.session.sync.model.SyncResponse import org.matrix.android.sdk.api.session.sync.model.SyncResponse
@ -38,8 +38,6 @@ import org.matrix.android.sdk.internal.session.SessionListeners
import org.matrix.android.sdk.internal.session.dispatchTo import org.matrix.android.sdk.internal.session.dispatchTo
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.DefaultSyncStatusService
import org.matrix.android.sdk.internal.session.initsync.reportSubtask
import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser
import org.matrix.android.sdk.internal.session.user.UserStore import org.matrix.android.sdk.internal.session.user.UserStore
import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.task.Task
@ -68,7 +66,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 defaultSyncStatusService: DefaultSyncStatusService, private val syncRequestStateTracker: SyncRequestStateTracker,
private val syncTokenStore: SyncTokenStore, private val syncTokenStore: SyncTokenStore,
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask, private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask,
private val userStore: UserStore, private val userStore: UserStore,
@ -115,7 +113,7 @@ internal class DefaultSyncTask @Inject constructor(
displayName = user?.displayName, displayName = user?.displayName,
avatarUrl = user?.avatarUrl avatarUrl = user?.avatarUrl
) )
defaultSyncStatusService.startRoot(InitSyncStep.ImportingAccount, 100) syncRequestStateTracker.startRoot(InitialSyncStep.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))
@ -132,7 +130,7 @@ internal class DefaultSyncTask @Inject constructor(
roomSyncEphemeralTemporaryStore.reset() roomSyncEphemeralTemporaryStore.reset()
workingDir.mkdirs() workingDir.mkdirs()
val file = downloadInitSyncResponse(requestParams, syncStatisticsData) val file = downloadInitSyncResponse(requestParams, syncStatisticsData)
syncResponseToReturn = reportSubtask(defaultSyncStatusService, InitSyncStep.ImportingAccount, 1, 0.7F) { syncResponseToReturn = reportSubtask(syncRequestStateTracker, InitialSyncStep.ImportingAccount, 1, 0.7F) {
handleSyncFile(file, initSyncStrategy) handleSyncFile(file, initSyncStrategy)
} }
// Delete all files // Delete all files
@ -150,15 +148,15 @@ internal class DefaultSyncTask @Inject constructor(
syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime() syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime()
syncStatisticsData.downloadInitSyncTime = syncStatisticsData.requestInitSyncTime syncStatisticsData.downloadInitSyncTime = syncStatisticsData.requestInitSyncTime
logDuration("INIT_SYNC Database insertion", loggerTag, clock) { logDuration("INIT_SYNC Database insertion", loggerTag, clock) {
syncResponseHandler.handleResponse(syncResponse, token, defaultSyncStatusService) syncResponseHandler.handleResponse(syncResponse, token, syncRequestStateTracker)
} }
syncResponseToReturn = syncResponse syncResponseToReturn = syncResponse
} }
} }
defaultSyncStatusService.endAll() syncRequestStateTracker.endAll()
} else { } else {
Timber.tag(loggerTag.value).d("Start incremental sync request with since token $token") Timber.tag(loggerTag.value).d("Start incremental sync request with since token $token")
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncIdle) syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncIdle)
val syncResponse = try { val syncResponse = try {
executeRequest(globalErrorReceiver) { executeRequest(globalErrorReceiver) {
syncAPI.sync( syncAPI.sync(
@ -168,7 +166,7 @@ internal class DefaultSyncTask @Inject constructor(
} }
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
Timber.tag(loggerTag.value).e(throwable, "Incremental sync request error") Timber.tag(loggerTag.value).e(throwable, "Incremental sync request error")
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncError) syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncError)
throw throwable throw throwable
} }
val nbRooms = syncResponse.rooms?.invite.orEmpty().size + syncResponse.rooms?.join.orEmpty().size + syncResponse.rooms?.leave.orEmpty().size val nbRooms = syncResponse.rooms?.invite.orEmpty().size + syncResponse.rooms?.join.orEmpty().size + syncResponse.rooms?.leave.orEmpty().size
@ -177,8 +175,8 @@ internal class DefaultSyncTask @Inject constructor(
Timber.tag(loggerTag.value).d( Timber.tag(loggerTag.value).d(
"Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s). Got nextBatch: $nextBatch" "Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s). Got nextBatch: $nextBatch"
) )
defaultSyncStatusService.setStatus( syncRequestStateTracker.setSyncRequestState(
SyncStatusService.Status.IncrementalSyncParsing( SyncRequestState.IncrementalSyncParsing(
rooms = nbRooms, rooms = nbRooms,
toDevice = nbToDevice toDevice = nbToDevice
) )
@ -186,7 +184,7 @@ internal class DefaultSyncTask @Inject constructor(
syncResponseHandler.handleResponse(syncResponse, token, null) syncResponseHandler.handleResponse(syncResponse, token, null)
syncResponseToReturn = syncResponse syncResponseToReturn = syncResponse
Timber.tag(loggerTag.value).d("Incremental sync done") Timber.tag(loggerTag.value).d("Incremental sync done")
defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncDone) syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncDone)
} }
syncStatisticsData.treatmentSyncTime = SystemClock.elapsedRealtime() syncStatisticsData.treatmentSyncTime = SystemClock.elapsedRealtime()
syncStatisticsData.nbOfRooms = syncResponseToReturn?.rooms?.join?.size ?: 0 syncStatisticsData.nbOfRooms = syncResponseToReturn?.rooms?.join?.size ?: 0
@ -201,20 +199,20 @@ internal class DefaultSyncTask @Inject constructor(
val status = initialSyncStatusRepository.getStep() val status = initialSyncStatusRepository.getStep()
if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) { if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) {
Timber.tag(loggerTag.value).d("INIT_SYNC file is already here") Timber.tag(loggerTag.value).d("INIT_SYNC file is already here")
reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.3f) { reportSubtask(syncRequestStateTracker, InitialSyncStep.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", loggerTag, clock) { val syncResponse = logDuration("INIT_SYNC Perform server request", loggerTag, clock) {
reportSubtask(defaultSyncStatusService, InitSyncStep.ServerComputing, 1, 0.2f) { reportSubtask(syncRequestStateTracker, InitialSyncStep.ServerComputing, 1, 0.2f) {
getSyncResponse(requestParams, MAX_NUMBER_OF_RETRY_AFTER_TIMEOUT) getSyncResponse(requestParams, MAX_NUMBER_OF_RETRY_AFTER_TIMEOUT)
} }
} }
syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime() syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime()
if (syncResponse.isSuccessful) { if (syncResponse.isSuccessful) {
logDuration("INIT_SYNC Download and save to file", loggerTag, clock) { logDuration("INIT_SYNC Download and save to file", loggerTag, clock) {
reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.1f) { reportSubtask(syncRequestStateTracker, InitialSyncStep.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)
@ -263,7 +261,7 @@ internal class DefaultSyncTask @Inject constructor(
Timber.tag(loggerTag.value).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", loggerTag, clock) { logDuration("INIT_SYNC Database insertion", loggerTag, clock) {
syncResponseHandler.handleResponse(syncResponse, null, defaultSyncStatusService) syncResponseHandler.handleResponse(syncResponse, null, syncRequestStateTracker)
} }
initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_SUCCESS) initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_SUCCESS)
syncResponse syncResponse

View File

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package org.matrix.android.sdk.internal.session.initsync package org.matrix.android.sdk.internal.session.sync
import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStep
import timber.log.Timber import timber.log.Timber
internal class TaskInfo( internal class TaskInfo(
val initSyncStep: InitSyncStep, val initialSyncStep: InitialSyncStep,
val totalProgress: Int, val totalProgress: Int,
val parent: TaskInfo?, val parent: TaskInfo?,
val parentWeight: Float val parentWeight: Float

View File

@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
import org.matrix.android.sdk.internal.session.initsync.ProgressReporter import org.matrix.android.sdk.internal.session.sync.ProgressReporter
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject

View File

@ -17,16 +17,16 @@
package org.matrix.android.sdk.internal.session.sync.handler package org.matrix.android.sdk.internal.session.sync.handler
import io.realm.Realm import io.realm.Realm
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
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.sync.InitialSyncStep
import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
import org.matrix.android.sdk.api.session.sync.model.InvitedGroupSync import org.matrix.android.sdk.api.session.sync.model.InvitedGroupSync
import org.matrix.android.sdk.internal.database.model.GroupEntity import org.matrix.android.sdk.internal.database.model.GroupEntity
import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.session.initsync.ProgressReporter import org.matrix.android.sdk.internal.session.sync.ProgressReporter
import org.matrix.android.sdk.internal.session.initsync.mapWithProgress import org.matrix.android.sdk.internal.session.sync.mapWithProgress
import javax.inject.Inject import javax.inject.Inject
internal class GroupSyncHandler @Inject constructor() { internal class GroupSyncHandler @Inject constructor() {
@ -51,18 +51,18 @@ internal class GroupSyncHandler @Inject constructor() {
private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: ProgressReporter?) { private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: ProgressReporter?) {
val groups = when (handlingStrategy) { val groups = when (handlingStrategy) {
is HandlingStrategy.JOINED -> is HandlingStrategy.JOINED ->
handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.6f) { handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.6f) {
handleJoinedGroup(realm, it.key) handleJoinedGroup(realm, it.key)
} }
is HandlingStrategy.INVITED -> is HandlingStrategy.INVITED ->
handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.3f) { handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.3f) {
handleInvitedGroup(realm, it.key) handleInvitedGroup(realm, it.key)
} }
is HandlingStrategy.LEFT -> is HandlingStrategy.LEFT ->
handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.1f) { handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.1f) {
handleLeftGroup(realm, it.key) handleLeftGroup(realm, it.key)
} }
} }

View File

@ -27,11 +27,11 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
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.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.session.initsync.InitSyncStep
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.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummaryUpdateType import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummaryUpdateType
import org.matrix.android.sdk.api.session.sync.InitialSyncStep
import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy
import org.matrix.android.sdk.api.session.sync.initialSyncStrategy import org.matrix.android.sdk.api.session.sync.initialSyncStrategy
import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync
@ -67,17 +67,17 @@ import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.clearWith import org.matrix.android.sdk.internal.extensions.clearWith
import org.matrix.android.sdk.internal.session.StreamEventsManager import org.matrix.android.sdk.internal.session.StreamEventsManager
import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
import org.matrix.android.sdk.internal.session.initsync.mapWithProgress
import org.matrix.android.sdk.internal.session.initsync.reportSubtask
import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput
import org.matrix.android.sdk.internal.session.room.typing.TypingEventContent import org.matrix.android.sdk.internal.session.room.typing.TypingEventContent
import org.matrix.android.sdk.internal.session.sync.ProgressReporter
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
import org.matrix.android.sdk.internal.session.sync.mapWithProgress
import org.matrix.android.sdk.internal.session.sync.parsing.RoomSyncAccountDataHandler import org.matrix.android.sdk.internal.session.sync.parsing.RoomSyncAccountDataHandler
import org.matrix.android.sdk.internal.session.sync.reportSubtask
import org.matrix.android.sdk.internal.util.computeBestChunkSize import org.matrix.android.sdk.internal.util.computeBestChunkSize
import org.matrix.android.sdk.internal.util.time.Clock import org.matrix.android.sdk.internal.util.time.Clock
import timber.log.Timber import timber.log.Timber
@ -140,24 +140,24 @@ internal class RoomSyncHandler @Inject constructor(
} }
val syncLocalTimeStampMillis = clock.epochMillis() val syncLocalTimeStampMillis = clock.epochMillis()
val rooms = when (handlingStrategy) { val rooms = when (handlingStrategy) {
is HandlingStrategy.JOINED -> { is HandlingStrategy.JOINED -> {
if (isInitialSync && initialSyncStrategy is InitialSyncStrategy.Optimized) { if (isInitialSync && initialSyncStrategy is InitialSyncStrategy.Optimized) {
insertJoinRoomsFromInitSync(realm, handlingStrategy, syncLocalTimeStampMillis, aggregator, reporter) insertJoinRoomsFromInitSync(realm, handlingStrategy, syncLocalTimeStampMillis, aggregator, reporter)
// Rooms are already inserted, return an empty list // Rooms are already inserted, return an empty list
emptyList() emptyList()
} else { } else {
handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountJoinedRooms, 0.6f) { handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountJoinedRooms, 0.6f) {
handleJoinedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis, aggregator) handleJoinedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis, aggregator)
} }
} }
} }
is HandlingStrategy.INVITED -> is HandlingStrategy.INVITED ->
handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountInvitedRooms, 0.1f) { handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountInvitedRooms, 0.1f) {
handleInvitedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis) handleInvitedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis)
} }
is HandlingStrategy.LEFT -> { is HandlingStrategy.LEFT -> {
handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountLeftRooms, 0.3f) { handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountLeftRooms, 0.3f) {
handleLeftRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis) handleLeftRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis)
} }
} }
@ -178,7 +178,7 @@ internal class RoomSyncHandler @Inject constructor(
) )
if (bestChunkSize.shouldChunk()) { if (bestChunkSize.shouldChunk()) {
reportSubtask(reporter, InitSyncStep.ImportingAccountJoinedRooms, bestChunkSize.numberOfChunks, 0.6f) { reportSubtask(reporter, InitialSyncStep.ImportingAccountJoinedRooms, bestChunkSize.numberOfChunks, 0.6f) {
Timber.d("INIT_SYNC ${handlingStrategy.data.keys.size} rooms to insert, split with $bestChunkSize") Timber.d("INIT_SYNC ${handlingStrategy.data.keys.size} rooms to insert, split with $bestChunkSize")
// I cannot find a better way to chunk a map, so chunk the keys and then create new maps // I cannot find a better way to chunk a map, so chunk the keys and then create new maps
handlingStrategy.data.keys handlingStrategy.data.keys
@ -202,7 +202,7 @@ internal class RoomSyncHandler @Inject constructor(
} }
} else { } else {
// No need to split // No need to split
val rooms = handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountJoinedRooms, 0.6f) { val rooms = handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountJoinedRooms, 0.6f) {
handleJoinedRoom(realm, it.key, it.value, EventInsertType.INITIAL_SYNC, syncLocalTimeStampMillis, aggregator) handleJoinedRoom(realm, it.key, it.value, EventInsertType.INITIAL_SYNC, syncLocalTimeStampMillis, aggregator)
} }
realm.insertOrUpdate(rooms) realm.insertOrUpdate(rooms)
@ -578,12 +578,12 @@ internal class RoomSyncHandler @Inject constructor(
readReceiptHandler.handle(realm, roomId, readReceiptContent, isInitialSync, aggregator) readReceiptHandler.handle(realm, roomId, readReceiptContent, isInitialSync, aggregator)
} }
} }
EventType.TYPING -> { EventType.TYPING -> {
event.content.toModel<TypingEventContent>()?.let { typingEventContent -> event.content.toModel<TypingEventContent>()?.let { typingEventContent ->
result = result.copy(typingUserIds = typingEventContent.typingUserIds) result = result.copy(typingUserIds = typingEventContent.typingUserIds)
} }
} }
else -> Timber.w("Ephemeral event type '${event.type}' not yet supported") else -> Timber.w("Ephemeral event type '${event.type}' not yet supported")
} }
} }

View File

@ -142,7 +142,7 @@ fun initialSyncIdlingResource(session: Session): IdlingResource {
override fun getName() = "InitialSyncIdlingResource for ${session.myUserId}" override fun getName() = "InitialSyncIdlingResource for ${session.myUserId}"
override fun isIdleNow(): Boolean { override fun isIdleNow(): Boolean {
val isIdle = session.hasAlreadySynced() val isIdle = session.syncService().hasAlreadySynced()
return isIdle return isIdle
} }
@ -151,16 +151,16 @@ fun initialSyncIdlingResource(session: Session): IdlingResource {
} }
override fun onChanged(t: SyncState?) { override fun onChanged(t: SyncState?) {
val isIdle = session.hasAlreadySynced() val isIdle = session.syncService().hasAlreadySynced()
if (isIdle) { if (isIdle) {
callback?.onTransitionToIdle() callback?.onTransitionToIdle()
session.getSyncStateLive().removeObserver(this) session.syncService().getSyncStateLive().removeObserver(this)
} }
} }
} }
runOnUiThread { runOnUiThread {
session.getSyncStateLive().observeForever(res) session.syncService().getSyncStateLive().observeForever(res)
} }
return res return res

View File

@ -116,14 +116,14 @@ abstract class VerificationTestBase {
GlobalScope.launch(Dispatchers.Main) { session.open() } GlobalScope.launch(Dispatchers.Main) { session.open() }
session.startSync(true) session.syncService().startSync(true)
val syncLiveData = runBlocking(Dispatchers.Main) { val syncLiveData = runBlocking(Dispatchers.Main) {
session.getSyncStateLive() session.syncService().getSyncStateLive()
} }
val syncObserver = object : Observer<SyncState> { val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) { override fun onChanged(t: SyncState?) {
if (session.hasAlreadySynced()) { if (session.syncService().hasAlreadySynced()) {
lock.countDown() lock.countDown()
syncLiveData.removeObserver(this) syncLiveData.removeObserver(this)
} }

View File

@ -37,7 +37,7 @@ object BackgroundSyncStarter {
BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> {
// we rely on periodic worker // we rely on periodic worker
Timber.i("## Sync: Work scheduled to periodically sync in ${vectorPreferences.backgroundSyncDelay()}s") Timber.i("## Sync: Work scheduled to periodically sync in ${vectorPreferences.backgroundSyncDelay()}s")
activeSession.startAutomaticBackgroundSync( activeSession.syncService().startAutomaticBackgroundSync(
vectorPreferences.backgroundSyncTimeOut().toLong(), vectorPreferences.backgroundSyncTimeOut().toLong(),
vectorPreferences.backgroundSyncDelay().toLong() vectorPreferences.backgroundSyncDelay().toLong()
) )

View File

@ -26,9 +26,9 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.platform.PendingIntentCompat import im.vector.app.core.platform.PendingIntentCompat
import im.vector.app.core.services.VectorSyncService import im.vector.app.core.services.VectorSyncAndroidService
import im.vector.app.core.time.Clock import im.vector.app.core.time.Clock
import org.matrix.android.sdk.api.session.sync.job.SyncService import org.matrix.android.sdk.api.session.sync.job.SyncAndroidService
import timber.log.Timber import timber.log.Timber
class AlarmSyncBroadcastReceiver : BroadcastReceiver() { class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
@ -43,8 +43,8 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
val vectorPreferences = singletonEntryPoint.vectorPreferences() val vectorPreferences = singletonEntryPoint.vectorPreferences()
val clock = singletonEntryPoint.clock() val clock = singletonEntryPoint.clock()
val sessionId = intent.getStringExtra(SyncService.EXTRA_SESSION_ID) ?: return val sessionId = intent.getStringExtra(SyncAndroidService.EXTRA_SESSION_ID) ?: return
VectorSyncService.newPeriodicIntent( VectorSyncAndroidService.newPeriodicIntent(
context = context, context = context,
sessionId = sessionId, sessionId = sessionId,
syncTimeoutSeconds = vectorPreferences.backgroundSyncTimeOut(), syncTimeoutSeconds = vectorPreferences.backgroundSyncTimeOut(),
@ -69,8 +69,8 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
// Reschedule // Reschedule
Timber.v("## Sync: Scheduling alarm for background sync in $delayInSeconds seconds") Timber.v("## Sync: Scheduling alarm for background sync in $delayInSeconds seconds")
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply { val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply {
putExtra(SyncService.EXTRA_SESSION_ID, sessionId) putExtra(SyncAndroidService.EXTRA_SESSION_ID, sessionId)
putExtra(SyncService.EXTRA_PERIODIC, true) putExtra(SyncAndroidService.EXTRA_PERIODIC, true)
} }
val pIntent = PendingIntent.getBroadcast( val pIntent = PendingIntent.getBroadcast(
context, context,
@ -100,7 +100,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
alarmMgr.cancel(pIntent) alarmMgr.cancel(pIntent)
// Stop current service to restart // Stop current service to restart
VectorSyncService.stopIntent(context).let { VectorSyncAndroidService.stopIntent(context).let {
try { try {
ContextCompat.startForegroundService(context, it) ContextCompat.startForegroundService(context, it)
} catch (ex: Throwable) { } catch (ex: Throwable) {

View File

@ -63,7 +63,7 @@ object FcmHelper {
fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) { fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) {
// try to stop all regardless of background mode // try to stop all regardless of background mode
activeSessionHolder.getSafeActiveSession()?.stopAnyBackgroundSync() activeSessionHolder.getSafeActiveSession()?.syncService()?.stopAnyBackgroundSync()
AlarmSyncBroadcastReceiver.cancelAlarm(context) AlarmSyncBroadcastReceiver.cancelAlarm(context)
} }

View File

@ -164,7 +164,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
getEventFastLane(session, roomId, eventId) getEventFastLane(session, roomId, eventId)
Timber.tag(loggerTag.value).d("Requesting background sync") Timber.tag(loggerTag.value).d("Requesting background sync")
session.requireBackgroundSync() session.syncService().requireBackgroundSync()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -358,7 +358,7 @@
<!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite and for lintGplayRelease check :/ --> <!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite and for lintGplayRelease check :/ -->
<service <service
android:name=".core.services.VectorSyncService" android:name=".core.services.VectorSyncAndroidService"
android:exported="false" android:exported="false"
tools:ignore="Instantiatable" /> tools:ignore="Instantiatable" />

View File

@ -41,8 +41,8 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.group.model.GroupSummary import org.matrix.android.sdk.api.session.group.model.GroupSummary
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.SyncRequestState
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -147,9 +147,9 @@ class AppStateHandler @Inject constructor(
} }
private fun observeSyncStatus(session: Session) { private fun observeSyncStatus(session: Session) {
session.syncStatusService().getSyncStatusLive() session.syncService().getSyncRequestStateLive()
.asFlow() .asFlow()
.filterIsInstance<SyncStatusService.Status.IncrementalSyncDone>() .filterIsInstance<SyncRequestState.IncrementalSyncDone>()
.map { session.spaceService().getRootSpaceSummaries().size } .map { session.spaceService().getRootSpaceSummaries().size }
.distinctUntilChanged() .distinctUntilChanged()
.onEach { spacesNumber -> .onEach { spacesNumber ->

View File

@ -36,7 +36,7 @@ import kotlinx.coroutines.launch
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 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.initsync.SyncStatusService import org.matrix.android.sdk.api.session.sync.SyncRequestState
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -260,11 +260,11 @@ class AutoRageShaker @Inject constructor(
} }
this.currentActiveSessionId = sessionId this.currentActiveSessionId = sessionId
hasSynced = session.hasAlreadySynced() hasSynced = session.syncService().hasAlreadySynced()
session.syncStatusService().getSyncStatusLive() session.syncService().getSyncRequestStateLive()
.asFlow() .asFlow()
.onEach { .onEach {
hasSynced = it !is SyncStatusService.Status.InitialSyncProgressing hasSynced = it !is SyncRequestState.InitialSyncProgressing
} }
.launchIn(session.coroutineScope) .launchIn(session.coroutineScope)
activeSessionIds.add(sessionId) activeSessionIds.add(sessionId)

View File

@ -176,7 +176,7 @@ class VectorApplication :
Timber.i("App entered foreground") Timber.i("App entered foreground")
FcmHelper.onEnterForeground(appContext, activeSessionHolder) FcmHelper.onEnterForeground(appContext, activeSessionHolder)
activeSessionHolder.getSafeActiveSession()?.also { activeSessionHolder.getSafeActiveSession()?.also {
it.stopAnyBackgroundSync() it.syncService().stopAnyBackgroundSync()
} }
} }

View File

@ -20,7 +20,7 @@ import android.content.Context
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import im.vector.app.core.services.VectorSyncService import im.vector.app.core.services.VectorSyncAndroidService
import im.vector.app.features.session.VectorSessionStore import im.vector.app.features.session.VectorSessionStore
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
@ -40,9 +40,9 @@ fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) {
fun Session.startSyncing(context: Context) { fun Session.startSyncing(context: Context) {
val applicationContext = context.applicationContext val applicationContext = context.applicationContext
if (!hasAlreadySynced()) { if (!syncService().hasAlreadySynced()) {
// initial sync is done as a service so it can continue below app lifecycle // initial sync is done as a service so it can continue below app lifecycle
VectorSyncService.newOneShotIntent( VectorSyncAndroidService.newOneShotIntent(
context = applicationContext, context = applicationContext,
sessionId = sessionId sessionId = sessionId
) )
@ -57,7 +57,7 @@ fun Session.startSyncing(context: Context) {
} else { } else {
val isAtLeastStarted = ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) val isAtLeastStarted = ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
Timber.v("--> is at least started? $isAtLeastStarted") Timber.v("--> is at least started? $isAtLeastStarted")
startSync(isAtLeastStarted) syncService().startSync(isAtLeastStarted)
} }
} }

View File

@ -26,7 +26,7 @@ import javax.inject.Inject
class LocaleProvider @Inject constructor(private val resources: Resources) { class LocaleProvider @Inject constructor(private val resources: Resources) {
fun current(): Locale { fun current(): Locale {
return ConfigurationCompat.getLocales(resources.configuration)[0] return ConfigurationCompat.getLocales(resources.configuration).get(0) ?: Locale.getDefault()
} }
} }

View File

@ -38,12 +38,12 @@ import im.vector.app.core.time.DefaultClock
import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.notifications.NotificationUtils
import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.BackgroundSyncMode
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.session.sync.job.SyncService import org.matrix.android.sdk.api.session.sync.job.SyncAndroidService
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class VectorSyncService : SyncService() { class VectorSyncAndroidService : SyncAndroidService() {
companion object { companion object {
@ -51,7 +51,7 @@ class VectorSyncService : SyncService() {
context: Context, context: Context,
sessionId: String sessionId: String
): Intent { ): Intent {
return Intent(context, VectorSyncService::class.java).also { return Intent(context, VectorSyncAndroidService::class.java).also {
it.putExtra(EXTRA_SESSION_ID, sessionId) it.putExtra(EXTRA_SESSION_ID, sessionId)
it.putExtra(EXTRA_TIMEOUT_SECONDS, 0) it.putExtra(EXTRA_TIMEOUT_SECONDS, 0)
it.putExtra(EXTRA_PERIODIC, false) it.putExtra(EXTRA_PERIODIC, false)
@ -65,7 +65,7 @@ class VectorSyncService : SyncService() {
syncDelaySeconds: Int, syncDelaySeconds: Int,
isNetworkBack: Boolean isNetworkBack: Boolean
): Intent { ): Intent {
return Intent(context, VectorSyncService::class.java).also { return Intent(context, VectorSyncAndroidService::class.java).also {
it.putExtra(EXTRA_SESSION_ID, sessionId) it.putExtra(EXTRA_SESSION_ID, sessionId)
it.putExtra(EXTRA_TIMEOUT_SECONDS, syncTimeoutSeconds) it.putExtra(EXTRA_TIMEOUT_SECONDS, syncTimeoutSeconds)
it.putExtra(EXTRA_PERIODIC, true) it.putExtra(EXTRA_PERIODIC, true)
@ -75,7 +75,7 @@ class VectorSyncService : SyncService() {
} }
fun stopIntent(context: Context): Intent { fun stopIntent(context: Context): Intent {
return Intent(context, VectorSyncService::class.java).also { return Intent(context, VectorSyncAndroidService::class.java).also {
it.action = ACTION_STOP it.action = ACTION_STOP
} }
} }
@ -209,7 +209,7 @@ private fun Context.rescheduleSyncService(
) { ) {
Timber.d("## Sync: rescheduleSyncService") Timber.d("## Sync: rescheduleSyncService")
val intent = if (isPeriodic) { val intent = if (isPeriodic) {
VectorSyncService.newPeriodicIntent( VectorSyncAndroidService.newPeriodicIntent(
context = this, context = this,
sessionId = sessionId, sessionId = sessionId,
syncTimeoutSeconds = syncTimeoutSeconds, syncTimeoutSeconds = syncTimeoutSeconds,
@ -217,7 +217,7 @@ private fun Context.rescheduleSyncService(
isNetworkBack = isNetworkBack isNetworkBack = isNetworkBack
) )
} else { } else {
VectorSyncService.newOneShotIntent( VectorSyncAndroidService.newOneShotIntent(
context = this, context = this,
sessionId = sessionId sessionId = sessionId
) )

View File

@ -37,7 +37,7 @@ import kotlinx.coroutines.launch
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.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.initsync.SyncStatusService import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import timber.log.Timber import timber.log.Timber
import java.util.UUID import java.util.UUID
@ -66,11 +66,11 @@ class AnalyticsAccountDataViewModel @AssistedInject constructor(
private fun observeInitSync() { private fun observeInitSync() {
combine( combine(
session.syncStatusService().getSyncStatusLive().asFlow(), session.syncService().getSyncRequestStateLive().asFlow(),
analytics.getUserConsent(), analytics.getUserConsent(),
analytics.getAnalyticsId() analytics.getAnalyticsId()
) { status, userConsent, analyticsId -> ) { status, userConsent, analyticsId ->
if (status is SyncStatusService.Status.IncrementalSyncIdle && if (status is SyncRequestState.IncrementalSyncIdle &&
userConsent && userConsent &&
analyticsId.isEmpty() && analyticsId.isEmpty() &&
!checkDone) { !checkDone) {

View File

@ -105,6 +105,12 @@ data class Interaction(
*/ */
WebHomeExploreRoomsButton, WebHomeExploreRoomsButton,
/**
* User clicked on the mini avatar uploader in the home page of Element
* Web/Desktop.
*/
WebHomeMiniAvatarUploadButton,
/** /**
* User clicked the explore rooms button next to the search field at the * User clicked the explore rooms button next to the search field at the
* top of the left panel in Element Web/Desktop. * top of the left panel in Element Web/Desktop.

View File

@ -273,7 +273,7 @@ class WebRtcCallManager @Inject constructor(
// did we start background sync? so we should stop it // did we start background sync? so we should stop it
if (isInBackground) { if (isInBackground) {
if (FcmHelper.isPushSupported()) { if (FcmHelper.isPushSupported()) {
currentSession?.stopAnyBackgroundSync() currentSession?.syncService()?.stopAnyBackgroundSync()
} else { } else {
// for fdroid we should not stop, it should continue syncing // for fdroid we should not stop, it should continue syncing
// maybe we should restore default timeout/delay though? // maybe we should restore default timeout/delay though?
@ -380,7 +380,7 @@ class WebRtcCallManager @Inject constructor(
if (isInBackground) { if (isInBackground) {
if (FcmHelper.isPushSupported()) { if (FcmHelper.isPushSupported()) {
// only for push version as fdroid version is already doing it? // only for push version as fdroid version is already doing it?
currentSession?.startAutomaticBackgroundSync(30, 0) currentSession?.syncService()?.startAutomaticBackgroundSync(30, 0)
} else { } else {
// Maybe increase sync freq? but how to set back to default values? // Maybe increase sync freq? but how to set back to default values?
} }

View File

@ -81,9 +81,9 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
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.session.sync.InitialSyncStrategy import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.session.sync.initialSyncStrategy import org.matrix.android.sdk.api.session.sync.initialSyncStrategy
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import timber.log.Timber import timber.log.Timber
@ -199,15 +199,15 @@ class HomeActivity :
.stream() .stream()
.onEach { sharedAction -> .onEach { sharedAction ->
when (sharedAction) { when (sharedAction) {
is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START) is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START)
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START) is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
is HomeActivitySharedAction.OpenGroup -> openGroup(sharedAction.shouldClearFragment) is HomeActivitySharedAction.OpenGroup -> openGroup(sharedAction.shouldClearFragment)
is HomeActivitySharedAction.OpenSpacePreview -> startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId)) is HomeActivitySharedAction.OpenSpacePreview -> startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId))
is HomeActivitySharedAction.AddSpace -> createSpaceResultLauncher.launch(SpaceCreationActivity.newIntent(this)) is HomeActivitySharedAction.AddSpace -> createSpaceResultLauncher.launch(SpaceCreationActivity.newIntent(this))
is HomeActivitySharedAction.ShowSpaceSettings -> showSpaceSettings(sharedAction.spaceId) is HomeActivitySharedAction.ShowSpaceSettings -> showSpaceSettings(sharedAction.spaceId)
is HomeActivitySharedAction.OpenSpaceInvite -> openSpaceInvite(sharedAction.spaceId) is HomeActivitySharedAction.OpenSpaceInvite -> openSpaceInvite(sharedAction.spaceId)
HomeActivitySharedAction.SendSpaceFeedBack -> bugReporter.openBugReportScreen(this, ReportType.SPACE_BETA_FEEDBACK) HomeActivitySharedAction.SendSpaceFeedBack -> bugReporter.openBugReportScreen(this, ReportType.SPACE_BETA_FEEDBACK)
HomeActivitySharedAction.CloseGroup -> closeGroup() HomeActivitySharedAction.CloseGroup -> closeGroup()
} }
} }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
@ -226,20 +226,20 @@ class HomeActivity :
homeActivityViewModel.observeViewEvents { homeActivityViewModel.observeViewEvents {
when (it) { when (it) {
is HomeActivityViewEvents.AskPasswordToInitCrossSigning -> handleAskPasswordToInitCrossSigning(it) is HomeActivityViewEvents.AskPasswordToInitCrossSigning -> handleAskPasswordToInitCrossSigning(it)
is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it) is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it)
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush() HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
HomeActivityViewEvents.StartRecoverySetupFlow -> handleStartRecoverySetup() HomeActivityViewEvents.StartRecoverySetupFlow -> handleStartRecoverySetup()
is HomeActivityViewEvents.ForceVerification -> { is HomeActivityViewEvents.ForceVerification -> {
if (it.sendRequest) { if (it.sendRequest) {
navigator.requestSelfSessionVerification(this) navigator.requestSelfSessionVerification(this)
} else { } else {
navigator.waitSessionVerification(this) navigator.waitSessionVerification(this)
} }
} }
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it) is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
HomeActivityViewEvents.ShowAnalyticsOptIn -> handleShowAnalyticsOptIn() HomeActivityViewEvents.ShowAnalyticsOptIn -> handleShowAnalyticsOptIn()
HomeActivityViewEvents.NotifyUserForThreadsMigration -> handleNotifyUserForThreadsMigration() HomeActivityViewEvents.NotifyUserForThreadsMigration -> handleNotifyUserForThreadsMigration()
is HomeActivityViewEvents.MigrateThreads -> migrateThreadsIfNeeded(it.checkSession) is HomeActivityViewEvents.MigrateThreads -> migrateThreadsIfNeeded(it.checkSession)
} }
} }
homeActivityViewModel.onEach { renderState(it) } homeActivityViewModel.onEach { renderState(it) }
@ -337,12 +337,12 @@ class HomeActivity :
when { when {
deepLink.startsWith(USER_LINK_PREFIX) -> deepLink.substring(USER_LINK_PREFIX.length) deepLink.startsWith(USER_LINK_PREFIX) -> deepLink.substring(USER_LINK_PREFIX.length)
deepLink.startsWith(ROOM_LINK_PREFIX) -> deepLink.substring(ROOM_LINK_PREFIX.length) deepLink.startsWith(ROOM_LINK_PREFIX) -> deepLink.substring(ROOM_LINK_PREFIX.length)
else -> null else -> null
}?.let { permalinkId -> }?.let { permalinkId ->
activeSessionHolder.getSafeActiveSession()?.permalinkService()?.createPermalink(permalinkId) activeSessionHolder.getSafeActiveSession()?.permalinkService()?.createPermalink(permalinkId)
} }
} }
else -> deepLink else -> deepLink
} }
lifecycleScope.launch { lifecycleScope.launch {
@ -373,9 +373,9 @@ class HomeActivity :
} }
private fun renderState(state: HomeActivityViewState) { private fun renderState(state: HomeActivityViewState) {
when (val status = state.syncStatusServiceStatus) { when (val status = state.syncRequestState) {
is SyncStatusService.Status.InitialSyncProgressing -> { is SyncRequestState.InitialSyncProgressing -> {
val initSyncStepStr = initSyncStepFormatter.format(status.initSyncStep) val initSyncStepStr = initSyncStepFormatter.format(status.initialSyncStep)
Timber.v("$initSyncStepStr ${status.percentProgress}") Timber.v("$initSyncStepStr ${status.percentProgress}")
views.waitingView.root.setOnClickListener { views.waitingView.root.setOnClickListener {
// block interactions // block interactions
@ -392,7 +392,7 @@ class HomeActivity :
} }
views.waitingView.root.isVisible = true views.waitingView.root.isVisible = true
} }
else -> { else -> {
// Idle or Incremental sync status // Idle or Incremental sync status
views.waitingView.root.isVisible = false views.waitingView.root.isVisible = false
} }
@ -544,15 +544,15 @@ class HomeActivity :
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_home_suggestion -> { R.id.menu_home_suggestion -> {
bugReporter.openBugReportScreen(this, ReportType.SUGGESTION) bugReporter.openBugReportScreen(this, ReportType.SUGGESTION)
return true return true
} }
R.id.menu_home_report_bug -> { R.id.menu_home_report_bug -> {
bugReporter.openBugReportScreen(this, ReportType.BUG_REPORT) bugReporter.openBugReportScreen(this, ReportType.BUG_REPORT)
return true return true
} }
R.id.menu_home_init_sync_legacy -> { R.id.menu_home_init_sync_legacy -> {
// Configure the SDK // Configure the SDK
initialSyncStrategy = InitialSyncStrategy.Legacy initialSyncStrategy = InitialSyncStrategy.Legacy
// And clear cache // And clear cache
@ -566,11 +566,11 @@ class HomeActivity :
MainActivity.restartApp(this, MainActivityArgs(clearCache = true)) MainActivity.restartApp(this, MainActivityArgs(clearCache = true))
return true return true
} }
R.id.menu_home_filter -> { R.id.menu_home_filter -> {
navigator.openRoomsFiltering(this) navigator.openRoomsFiltering(this)
return true return true
} }
R.id.menu_home_setting -> { R.id.menu_home_setting -> {
navigator.openSettings(this) navigator.openSettings(this)
return true return true
} }

View File

@ -60,10 +60,10 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningServic
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.getUser
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.pushrules.RuleIds
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.session.sync.SyncRequestState
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.api.util.awaitCallback import org.matrix.android.sdk.api.util.awaitCallback
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
@ -198,7 +198,7 @@ class HomeActivityViewModel @AssistedInject constructor(
vectorPreferences.userNotifiedAboutThreads() vectorPreferences.userNotifiedAboutThreads()
} }
// Migrate users with enabled lab settings // Migrate users with enabled lab settings
vectorPreferences.shouldNotifyUserAboutThreads() && vectorPreferences.shouldMigrateThreads() -> { vectorPreferences.shouldNotifyUserAboutThreads() && vectorPreferences.shouldMigrateThreads() -> {
Timber.i("----> Migrate threads with enabled labs") Timber.i("----> Migrate threads with enabled labs")
// If user had io.element.thread enabled then enable the new thread support, // If user had io.element.thread enabled then enable the new thread support,
// clear cache to sync messages appropriately // clear cache to sync messages appropriately
@ -208,7 +208,7 @@ class HomeActivityViewModel @AssistedInject constructor(
_viewEvents.post(HomeActivityViewEvents.MigrateThreads(checkSession = false)) _viewEvents.post(HomeActivityViewEvents.MigrateThreads(checkSession = false))
} }
// Enable all users // Enable all users
vectorPreferences.shouldMigrateThreads() && vectorPreferences.areThreadMessagesEnabled() -> { vectorPreferences.shouldMigrateThreads() && vectorPreferences.areThreadMessagesEnabled() -> {
Timber.i("----> Try to migrate threads") Timber.i("----> Try to migrate threads")
_viewEvents.post(HomeActivityViewEvents.MigrateThreads(checkSession = true)) _viewEvents.post(HomeActivityViewEvents.MigrateThreads(checkSession = true))
} }
@ -218,25 +218,25 @@ class HomeActivityViewModel @AssistedInject constructor(
private fun observeInitialSync() { private fun observeInitialSync() {
val session = activeSessionHolder.getSafeActiveSession() ?: return val session = activeSessionHolder.getSafeActiveSession() ?: return
session.syncStatusService().getSyncStatusLive() session.syncService().getSyncRequestStateLive()
.asFlow() .asFlow()
.onEach { status -> .onEach { status ->
when (status) { when (status) {
is SyncStatusService.Status.Idle -> { is SyncRequestState.Idle -> {
maybeVerifyOrBootstrapCrossSigning() maybeVerifyOrBootstrapCrossSigning()
} }
else -> Unit else -> Unit
} }
setState { setState {
copy( copy(
syncStatusServiceStatus = status syncRequestState = status
) )
} }
} }
.launchIn(viewModelScope) .launchIn(viewModelScope)
if (session.hasAlreadySynced()) { if (session.syncService().hasAlreadySynced()) {
maybeVerifyOrBootstrapCrossSigning() maybeVerifyOrBootstrapCrossSigning()
} }
} }
@ -426,7 +426,7 @@ class HomeActivityViewModel @AssistedInject constructor(
HomeActivityViewActions.PushPromptHasBeenReviewed -> { HomeActivityViewActions.PushPromptHasBeenReviewed -> {
vectorPreferences.setDidAskUserToEnableSessionPush() vectorPreferences.setDidAskUserToEnableSessionPush()
} }
HomeActivityViewActions.ViewStarted -> { HomeActivityViewActions.ViewStarted -> {
initialize() initialize()
} }
} }

View File

@ -18,9 +18,9 @@ package im.vector.app.features.home
import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.MavericksState
import im.vector.app.features.onboarding.AuthenticationDescription import im.vector.app.features.onboarding.AuthenticationDescription
import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.sync.SyncRequestState
data class HomeActivityViewState( data class HomeActivityViewState(
val syncStatusServiceStatus: SyncStatusService.Status = SyncStatusService.Status.Idle, val syncRequestState: SyncRequestState = SyncRequestState.Idle,
val authenticationDescription: AuthenticationDescription? = null val authenticationDescription: AuthenticationDescription? = null
) : MavericksState ) : MavericksState

View File

@ -444,7 +444,7 @@ class HomeDetailFragment @Inject constructor(
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( views.syncStateView.render(
it.syncState, it.syncState,
it.incrementalSyncStatus, it.incrementalSyncRequestState,
it.pushCounter, it.pushCounter,
vectorPreferences.developerShowDebugInfo() vectorPreferences.developerShowDebugInfo()
) )

View File

@ -50,10 +50,10 @@ import org.matrix.android.sdk.api.query.SpaceFilter
import org.matrix.android.sdk.api.query.toActiveSpaceOrOrphanRooms import org.matrix.android.sdk.api.query.toActiveSpaceOrOrphanRooms
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.NewSessionListener import org.matrix.android.sdk.api.session.crypto.NewSessionListener
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
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import timber.log.Timber import timber.log.Timber
@ -199,11 +199,11 @@ class HomeDetailViewModel @AssistedInject constructor(
copy(syncState = syncState) copy(syncState = syncState)
} }
session.syncStatusService().getSyncStatusLive() session.syncService().getSyncRequestStateLive()
.asFlow() .asFlow()
.filterIsInstance<SyncStatusService.Status.IncrementalSyncStatus>() .filterIsInstance<SyncRequestState.IncrementalSyncRequestState>()
.setOnEach { .setOnEach {
copy(incrementalSyncStatus = it) copy(incrementalSyncRequestState = it)
} }
} }

View File

@ -22,8 +22,8 @@ import com.airbnb.mvrx.MavericksState
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.SyncRequestState
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
@ -40,7 +40,7 @@ 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 incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState = SyncRequestState.IncrementalSyncIdle,
val pushCounter: Int = 0, val pushCounter: Int = 0,
val pstnSupportFlag: Boolean = false, val pstnSupportFlag: Boolean = false,
val forceDialPadTab: Boolean = false val forceDialPadTab: Boolean = false

View File

@ -18,25 +18,25 @@ package im.vector.app.features.home
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStep
import javax.inject.Inject import javax.inject.Inject
class InitSyncStepFormatter @Inject constructor( class InitSyncStepFormatter @Inject constructor(
private val stringProvider: StringProvider private val stringProvider: StringProvider
) { ) {
fun format(initSyncStep: InitSyncStep): String { fun format(initialSyncStep: InitialSyncStep): String {
return stringProvider.getString( return stringProvider.getString(
when (initSyncStep) { when (initialSyncStep) {
InitSyncStep.ServerComputing -> R.string.initial_sync_start_server_computing InitialSyncStep.ServerComputing -> R.string.initial_sync_start_server_computing
InitSyncStep.Downloading -> R.string.initial_sync_start_downloading InitialSyncStep.Downloading -> R.string.initial_sync_start_downloading
InitSyncStep.ImportingAccount -> R.string.initial_sync_start_importing_account InitialSyncStep.ImportingAccount -> R.string.initial_sync_start_importing_account
InitSyncStep.ImportingAccountCrypto -> R.string.initial_sync_start_importing_account_crypto InitialSyncStep.ImportingAccountCrypto -> R.string.initial_sync_start_importing_account_crypto
InitSyncStep.ImportingAccountRoom -> R.string.initial_sync_start_importing_account_rooms InitialSyncStep.ImportingAccountRoom -> R.string.initial_sync_start_importing_account_rooms
InitSyncStep.ImportingAccountGroups -> R.string.initial_sync_start_importing_account_groups InitialSyncStep.ImportingAccountGroups -> R.string.initial_sync_start_importing_account_groups
InitSyncStep.ImportingAccountData -> R.string.initial_sync_start_importing_account_data InitialSyncStep.ImportingAccountData -> R.string.initial_sync_start_importing_account_data
InitSyncStep.ImportingAccountJoinedRooms -> R.string.initial_sync_start_importing_account_joined_rooms InitialSyncStep.ImportingAccountJoinedRooms -> R.string.initial_sync_start_importing_account_joined_rooms
InitSyncStep.ImportingAccountInvitedRooms -> R.string.initial_sync_start_importing_account_invited_rooms InitialSyncStep.ImportingAccountInvitedRooms -> R.string.initial_sync_start_importing_account_invited_rooms
InitSyncStep.ImportingAccountLeftRooms -> R.string.initial_sync_start_importing_account_left_rooms InitialSyncStep.ImportingAccountLeftRooms -> R.string.initial_sync_start_importing_account_left_rooms
} }
) )
} }

View File

@ -22,11 +22,11 @@ import com.airbnb.mvrx.Uninitialized
import im.vector.app.features.home.room.detail.arguments.TimelineArgs import im.vector.app.features.home.room.detail.arguments.TimelineArgs
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
import org.matrix.android.sdk.api.session.room.sender.SenderInfo import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.threads.ThreadNotificationBadgeState import org.matrix.android.sdk.api.session.threads.ThreadNotificationBadgeState
import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.Widget
@ -59,7 +59,7 @@ 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 incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState = SyncRequestState.IncrementalSyncIdle,
val pushCounter: Int = 0, val pushCounter: Int = 0,
val highlightedEventId: String? = null, val highlightedEventId: String? = null,
val unreadState: UnreadState = UnreadState.Unknown, val unreadState: UnreadState = UnreadState.Unknown,

View File

@ -68,6 +68,7 @@ import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.vanniktech.emoji.EmojiPopup import com.vanniktech.emoji.EmojiPopup
import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.animations.play import im.vector.app.core.animations.play
import im.vector.app.core.dialogs.ConfirmationDialogBuilder import im.vector.app.core.dialogs.ConfirmationDialogBuilder
@ -430,7 +431,7 @@ class TimelineFragment @Inject constructor(
timelineViewModel.onEach( timelineViewModel.onEach(
RoomDetailViewState::syncState, RoomDetailViewState::syncState,
RoomDetailViewState::incrementalSyncStatus, RoomDetailViewState::incrementalSyncRequestState,
RoomDetailViewState::pushCounter RoomDetailViewState::pushCounter
) { syncState, incrementalSyncStatus, pushCounter -> ) { syncState, incrementalSyncStatus, pushCounter ->
views.syncStateView.render( views.syncStateView.render(
@ -1552,7 +1553,7 @@ class TimelineFragment @Inject constructor(
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@TimelineFragment) attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@TimelineFragment)
attachmentTypeSelector.setAttachmentVisibility( attachmentTypeSelector.setAttachmentVisibility(
AttachmentTypeSelectorView.Type.LOCATION, AttachmentTypeSelectorView.Type.LOCATION,
vectorPreferences.isLocationSharingEnabled() BuildConfig.enableLocationSharing
) )
attachmentTypeSelector.setAttachmentVisibility( attachmentTypeSelector.setAttachmentVisibility(
AttachmentTypeSelectorView.Type.POLL, !isThreadTimeLine() AttachmentTypeSelectorView.Type.POLL, !isThreadTimeLine()

View File

@ -90,7 +90,6 @@ 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.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
import org.matrix.android.sdk.api.session.room.getStateEvent import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
@ -105,6 +104,7 @@ import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.read.ReadService
import org.matrix.android.sdk.api.session.room.timeline.Timeline 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.TimelineEvent
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.session.threads.ThreadNotificationBadgeState import org.matrix.android.sdk.api.session.threads.ThreadNotificationBadgeState
import org.matrix.android.sdk.api.session.threads.ThreadNotificationState import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
import org.matrix.android.sdk.api.session.widgets.model.WidgetType import org.matrix.android.sdk.api.session.widgets.model.WidgetType
@ -1130,11 +1130,11 @@ class TimelineViewModel @AssistedInject constructor(
copy(syncState = syncState) copy(syncState = syncState)
} }
session.syncStatusService().getSyncStatusLive() session.syncService().getSyncRequestStateLive()
.asFlow() .asFlow()
.filterIsInstance<SyncStatusService.Status.IncrementalSyncStatus>() .filterIsInstance<SyncRequestState.IncrementalSyncRequestState>()
.setOnEach { .setOnEach {
copy(incrementalSyncStatus = it) copy(incrementalSyncRequestState = it)
} }
} }

View File

@ -200,24 +200,18 @@ class MessageItemFactory @Inject constructor(
// val all = event.root.toContent() // val all = event.root.toContent()
// val ev = all.toModel<Event>() // val ev = all.toModel<Event>()
val messageItem = when (messageContent) { val messageItem = when (messageContent) {
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, highlight, callback, attributes) is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessageTextContent -> buildItemForTextContent(messageContent, informationData, highlight, callback, attributes) is MessageTextContent -> buildItemForTextContent(messageContent, informationData, highlight, callback, attributes)
is MessageImageInfoContent -> buildImageMessageItem(messageContent, informationData, highlight, callback, attributes) is MessageImageInfoContent -> buildImageMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, highlight, callback, attributes) is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, highlight, callback, attributes) is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessageFileContent -> buildFileMessageItem(messageContent, highlight, attributes) is MessageFileContent -> buildFileMessageItem(messageContent, highlight, attributes)
is MessageAudioContent -> buildAudioContent(params, messageContent, informationData, highlight, attributes) is MessageAudioContent -> buildAudioContent(params, messageContent, informationData, highlight, attributes)
is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes) is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes) is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes)
is MessageLocationContent -> { is MessageLocationContent -> buildLocationItem(messageContent, informationData, highlight, attributes)
if (vectorPreferences.labsRenderLocationsInTimeline()) { is MessageBeaconInfoContent -> liveLocationShareMessageItemFactory.create(params.event, highlight, attributes)
buildLocationItem(messageContent, informationData, highlight, attributes) else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
} else {
buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes)
}
}
is MessageBeaconInfoContent -> liveLocationShareMessageItemFactory.create(params.event, highlight, attributes)
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
} }
return messageItem?.apply { return messageItem?.apply {
layout(informationData.messageLayout.layoutRes) layout(informationData.messageLayout.layoutRes)
@ -283,11 +277,11 @@ class MessageItemFactory @Inject constructor(
pollResponseSummary: PollResponseData?, pollResponseSummary: PollResponseData?,
pollContent: MessagePollContent, pollContent: MessagePollContent,
): PollState = when { ): PollState = when {
!informationData.sendState.isSent() -> Sending !informationData.sendState.isSent() -> Sending
pollResponseSummary?.isClosed.orFalse() -> Ended pollResponseSummary?.isClosed.orFalse() -> Ended
pollContent.getBestPollCreationInfo()?.kind == PollType.UNDISCLOSED -> Undisclosed pollContent.getBestPollCreationInfo()?.kind == PollType.UNDISCLOSED -> Undisclosed
pollResponseSummary?.myVote?.isNotEmpty().orFalse() -> Voted(pollResponseSummary?.totalVotes ?: 0) pollResponseSummary?.myVote?.isNotEmpty().orFalse() -> Voted(pollResponseSummary?.totalVotes ?: 0)
else -> Ready else -> Ready
} }
private fun List<PollAnswer>.mapToOptions( private fun List<PollAnswer>.mapToOptions(
@ -305,11 +299,11 @@ class MessageItemFactory @Inject constructor(
val isWinner = winnerVoteCount != 0 && voteCount == winnerVoteCount val isWinner = winnerVoteCount != 0 && voteCount == winnerVoteCount
when (pollState) { when (pollState) {
Sending -> PollSending(optionId, optionAnswer) Sending -> PollSending(optionId, optionAnswer)
Ready -> PollReady(optionId, optionAnswer) Ready -> PollReady(optionId, optionAnswer)
is Voted -> PollVoted(optionId, optionAnswer, voteCount, votePercentage, isMyVote) is Voted -> PollVoted(optionId, optionAnswer, voteCount, votePercentage, isMyVote)
Undisclosed -> PollUndisclosed(optionId, optionAnswer, isMyVote) Undisclosed -> PollUndisclosed(optionId, optionAnswer, isMyVote)
Ended -> PollEnded(optionId, optionAnswer, voteCount, votePercentage, isWinner) Ended -> PollEnded(optionId, optionAnswer, voteCount, votePercentage, isWinner)
} }
} }
@ -329,11 +323,11 @@ class MessageItemFactory @Inject constructor(
): String { ): String {
val votes = pollResponseSummary?.totalVotes ?: 0 val votes = pollResponseSummary?.totalVotes ?: 0
return when { return when {
pollState is Ended -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_after_ended, votes, votes) pollState is Ended -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_after_ended, votes, votes)
pollState is Undisclosed -> "" pollState is Undisclosed -> ""
pollState is Voted -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_voted, votes, votes) pollState is Voted -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_voted, votes, votes)
votes == 0 -> stringProvider.getString(R.string.poll_no_votes_cast) votes == 0 -> stringProvider.getString(R.string.poll_no_votes_cast)
else -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_not_voted, votes, votes) else -> stringProvider.getQuantityString(R.plurals.poll_total_vote_count_before_ended_and_not_voted, votes, votes)
} }
} }

View File

@ -62,16 +62,15 @@ class TimelineMessageLayoutFactory @Inject constructor(
MessageType.MSGTYPE_STICKER_LOCAL, MessageType.MSGTYPE_STICKER_LOCAL,
MessageType.MSGTYPE_EMOTE, MessageType.MSGTYPE_EMOTE,
MessageType.MSGTYPE_BEACON_INFO, MessageType.MSGTYPE_BEACON_INFO,
MessageType.MSGTYPE_LOCATION,
MessageType.MSGTYPE_BEACON_LOCATION_DATA,
) )
private val MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE = setOf( private val MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE = setOf(
MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_IMAGE,
MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_BEACON_INFO, MessageType.MSGTYPE_BEACON_INFO,
)
private val MSG_TYPES_WITH_LOCATION_DATA = setOf(
MessageType.MSGTYPE_LOCATION, MessageType.MSGTYPE_LOCATION,
MessageType.MSGTYPE_BEACON_LOCATION_DATA MessageType.MSGTYPE_BEACON_LOCATION_DATA,
) )
} }
@ -147,23 +146,20 @@ class TimelineMessageLayoutFactory @Inject constructor(
private fun MessageContent?.isPseudoBubble(): Boolean { private fun MessageContent?.isPseudoBubble(): Boolean {
if (this == null) return false if (this == null) return false
if (msgType == MessageType.MSGTYPE_LOCATION) return vectorPreferences.labsRenderLocationsInTimeline()
return this.msgType in MSG_TYPES_WITH_PSEUDO_BUBBLE_LAYOUT return this.msgType in MSG_TYPES_WITH_PSEUDO_BUBBLE_LAYOUT
} }
private fun MessageContent?.timestampInsideMessage(): Boolean { private fun MessageContent?.timestampInsideMessage(): Boolean {
return when { return when {
this == null -> false this == null -> false
msgType in MSG_TYPES_WITH_LOCATION_DATA -> vectorPreferences.labsRenderLocationsInTimeline() else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
} }
} }
private fun MessageContent?.shouldAddMessageOverlay(): Boolean { private fun MessageContent?.shouldAddMessageOverlay(): Boolean {
return when { return when {
this == null || msgType == MessageType.MSGTYPE_BEACON_INFO -> false this == null || msgType == MessageType.MSGTYPE_BEACON_INFO -> false
msgType == MessageType.MSGTYPE_LOCATION -> vectorPreferences.labsRenderLocationsInTimeline() else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
else -> msgType in MSG_TYPES_WITH_TIMESTAMP_INSIDE_MESSAGE
} }
} }
@ -214,10 +210,10 @@ class TimelineMessageLayoutFactory @Inject constructor(
return when (event?.root?.getClearType()) { return when (event?.root?.getClearType()) {
EventType.KEY_VERIFICATION_DONE, EventType.KEY_VERIFICATION_DONE,
EventType.KEY_VERIFICATION_CANCEL -> true EventType.KEY_VERIFICATION_CANCEL -> true
EventType.MESSAGE -> { EventType.MESSAGE -> {
event.getLastMessageContent() is MessageVerificationRequestContent event.getLastMessageContent() is MessageVerificationRequestContent
} }
else -> false else -> false
} }
} }
} }

View File

@ -191,9 +191,6 @@ class VectorPreferences @Inject constructor(
private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH" private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH"
// Location Sharing
const val SETTINGS_PREF_ENABLE_LOCATION_SHARING = "SETTINGS_PREF_ENABLE_LOCATION_SHARING"
private const val MEDIA_SAVING_3_DAYS = 0 private const val MEDIA_SAVING_3_DAYS = 0
private const val MEDIA_SAVING_1_WEEK = 1 private const val MEDIA_SAVING_1_WEEK = 1
private const val MEDIA_SAVING_1_MONTH = 2 private const val MEDIA_SAVING_1_MONTH = 2
@ -203,7 +200,6 @@ class VectorPreferences @Inject constructor(
private const val TAKE_PHOTO_VIDEO_MODE = "TAKE_PHOTO_VIDEO_MODE" private const val TAKE_PHOTO_VIDEO_MODE = "TAKE_PHOTO_VIDEO_MODE"
private const val SETTINGS_LABS_RENDER_LOCATIONS_IN_TIMELINE = "SETTINGS_LABS_RENDER_LOCATIONS_IN_TIMELINE"
private const val SETTINGS_LABS_ENABLE_LIVE_LOCATION = "SETTINGS_LABS_ENABLE_LIVE_LOCATION" private const val SETTINGS_LABS_ENABLE_LIVE_LOCATION = "SETTINGS_LABS_ENABLE_LIVE_LOCATION"
// This key will be used to identify clients with the old thread support enabled io.element.thread // This key will be used to identify clients with the old thread support enabled io.element.thread
@ -1044,14 +1040,6 @@ class VectorPreferences @Inject constructor(
} }
} }
fun isLocationSharingEnabled(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_PREF_ENABLE_LOCATION_SHARING, false) && BuildConfig.enableLocationSharing
}
fun labsRenderLocationsInTimeline(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_LABS_RENDER_LOCATIONS_IN_TIMELINE, true)
}
fun labsEnableLiveLocation(): Boolean { fun labsEnableLiveLocation(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_LIVE_LOCATION, false) return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_LIVE_LOCATION, false)
} }

View File

@ -24,7 +24,6 @@ import androidx.core.view.children
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference import androidx.preference.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.dialogs.PhotoOrVideoDialog import im.vector.app.core.dialogs.PhotoOrVideoDialog
import im.vector.app.core.extensions.restart import im.vector.app.core.extensions.restart
@ -173,8 +172,6 @@ class VectorSettingsPreferencesFragment @Inject constructor(
}) })
true true
} }
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_PREF_ENABLE_LOCATION_SHARING)?.isVisible = BuildConfig.enableLocationSharing
} }
private fun updateTakePhotoOrVideoPreferenceSummary() { private fun updateTakePhotoOrVideoPreferenceSummary() {

View File

@ -211,7 +211,7 @@ class SoftLogoutViewModel @AssistedInject constructor(
private fun onSessionRestored() { private fun onSessionRestored() {
activeSessionHolder.setActiveSession(session) activeSessionHolder.setActiveSession(session)
// Start the sync // Start the sync
session.startSync(true) session.syncService().startSync(true)
// TODO Configure and start ? Check that the push still works... // TODO Configure and start ? Check that the push still works...
setState { setState {

View File

@ -24,7 +24,7 @@ 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.SyncRequestState
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) :
@ -41,14 +41,14 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun render( fun render(
newState: SyncState, newState: SyncState,
incrementalSyncStatus: SyncStatusService.Status.IncrementalSyncStatus, incrementalSyncRequestState: SyncRequestState.IncrementalSyncRequestState,
pushCounter: Int, pushCounter: Int,
showDebugInfo: Boolean showDebugInfo: Boolean
) { ) {
views.syncStateDebugInfo.isVisible = showDebugInfo views.syncStateDebugInfo.isVisible = showDebugInfo
if (showDebugInfo) { if (showDebugInfo) {
views.syncStateDebugInfoText.text = views.syncStateDebugInfoText.text =
"Sync thread : ${newState.toHumanReadable()}\nSync request: ${incrementalSyncStatus.toHumanReadable()}" "Sync thread : ${newState.toHumanReadable()}\nSync request: ${incrementalSyncRequestState.toHumanReadable()}"
views.syncStateDebugInfoPushCounter.text = views.syncStateDebugInfoPushCounter.text =
"Push: $pushCounter" "Push: $pushCounter"
} }
@ -66,23 +66,23 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute
private fun SyncState.toHumanReadable(): String { private fun SyncState.toHumanReadable(): String {
return when (this) { return when (this) {
SyncState.Idle -> "Idle" SyncState.Idle -> "Idle"
SyncState.InvalidToken -> "InvalidToken" SyncState.InvalidToken -> "InvalidToken"
SyncState.Killed -> "Killed" SyncState.Killed -> "Killed"
SyncState.Killing -> "Killing" SyncState.Killing -> "Killing"
SyncState.NoNetwork -> "NoNetwork" SyncState.NoNetwork -> "NoNetwork"
SyncState.Paused -> "Paused" SyncState.Paused -> "Paused"
is SyncState.Running -> "$this" is SyncState.Running -> "$this"
} }
} }
private fun SyncStatusService.Status.IncrementalSyncStatus.toHumanReadable(): String { private fun SyncRequestState.IncrementalSyncRequestState.toHumanReadable(): String {
return when (this) { return when (this) {
SyncStatusService.Status.IncrementalSyncIdle -> "Idle" SyncRequestState.IncrementalSyncIdle -> "Idle"
is SyncStatusService.Status.IncrementalSyncParsing -> "Parsing ${this.rooms} room(s) ${this.toDevice} toDevice(s)" is SyncRequestState.IncrementalSyncParsing -> "Parsing ${this.rooms} room(s) ${this.toDevice} toDevice(s)"
SyncStatusService.Status.IncrementalSyncError -> "Error" SyncRequestState.IncrementalSyncError -> "Error"
SyncStatusService.Status.IncrementalSyncDone -> "Done" SyncRequestState.IncrementalSyncDone -> "Done"
else -> "?" else -> "?"
} }
} }
} }

View File

@ -3017,9 +3017,12 @@
<string name="location_not_available_dialog_title">${app_name} could not access your location</string> <string name="location_not_available_dialog_title">${app_name} could not access your location</string>
<string name="location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string> <string name="location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string>
<string name="location_share_external">Open with</string> <string name="location_share_external">Open with</string>
<string name="settings_enable_location_sharing">Enable location sharing</string> <!--TODO delete-->
<string name="settings_enable_location_sharing_summary">Once enabled you will be able to send your location to any room</string> <string name="settings_enable_location_sharing" tools:ignore="UnusedResources">Enable location sharing</string>
<string name="labs_render_locations_in_timeline">Render user locations in the timeline</string> <!--TODO delete-->
<string name="settings_enable_location_sharing_summary" tools:ignore="UnusedResources">Once enabled you will be able to send your location to any room</string>
<!--TODO delete-->
<string name="labs_render_locations_in_timeline" tools:ignore="UnusedResources">Render user locations in the timeline</string>
<string name="location_timeline_failed_to_load_map">Failed to load map</string> <string name="location_timeline_failed_to_load_map">Failed to load map</string>
<string name="location_share_live_enabled">Live location enabled</string> <string name="location_share_live_enabled">Live location enabled</string>
<string name="location_share_live_started">Loading live location…</string> <string name="location_share_live_started">Loading live location…</string>

View File

@ -64,11 +64,6 @@
android:summary="@string/labs_auto_report_uisi_desc" android:summary="@string/labs_auto_report_uisi_desc"
android:title="@string/labs_auto_report_uisi" /> android:title="@string/labs_auto_report_uisi" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="true"
android:key="SETTINGS_LABS_RENDER_LOCATIONS_IN_TIMELINE"
android:title="@string/labs_render_locations_in_timeline" />
<im.vector.app.core.preference.VectorSwitchPreference <im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="SETTINGS_LABS_ENABLE_LIVE_LOCATION" android:key="SETTINGS_LABS_ENABLE_LIVE_LOCATION"

View File

@ -72,12 +72,6 @@
android:title="@string/option_take_photo_video" android:title="@string/option_take_photo_video"
tools:summary="@string/option_always_ask" /> tools:summary="@string/option_always_ask" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="false"
android:key="SETTINGS_PREF_ENABLE_LOCATION_SHARING"
android:summary="@string/settings_enable_location_sharing_summary"
android:title="@string/settings_enable_location_sharing" />
</im.vector.app.core.preference.VectorPreferenceCategory> </im.vector.app.core.preference.VectorPreferenceCategory>
<im.vector.app.core.preference.VectorPreferenceCategory android:title="@string/settings_category_timeline"> <im.vector.app.core.preference.VectorPreferenceCategory android:title="@string/settings_category_timeline">