diff --git a/CHANGES.md b/CHANGES.md index 3a9e37a511..08da482e86 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,9 +12,10 @@ Improvements: - Enable proper cancellation of suspending functions (including db transaction) - Enhances network connectivity checks in SDK - Add "View Edit History" item in the message bottom sheet (#401) + - Cancel sync request on pause and timeout to 0 after pause (#404) Other changes: - - + - Show sync progress also in room detail screen (#403) Bugfix: - Edited message: link confusion when (edited) appears in body (#398) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt index 0b9365dc06..f6ff11c1fe 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt @@ -30,6 +30,7 @@ import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.BackgroundDetectionObserver +import kotlinx.coroutines.CancellationException import timber.log.Timber import java.net.SocketTimeoutException import java.util.concurrent.CountDownLatch @@ -70,6 +71,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, if (state is SyncState.RUNNING) { Timber.v("Pause sync...") updateStateTo(SyncState.PAUSED) + cancelableTask?.cancel() + lock.notify() } } @@ -90,18 +93,25 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, backgroundDetectionObserver.register(this) while (state != SyncState.KILLING) { + Timber.v("Entering loop, state: $state") + if (!networkConnectivityChecker.isConnected() || state == SyncState.PAUSED) { - Timber.v("Sync is Paused. Waiting...") + Timber.v("No network or sync is Paused. Waiting...") synchronized(lock) { lock.wait() } + Timber.v("...unlocked") } else { if (state !is SyncState.RUNNING) { updateStateTo(SyncState.RUNNING(afterPause = true)) } - Timber.v("[$this] Execute sync request with timeout $DEFAULT_LONG_POOL_TIMEOUT") + + // No timeout after a pause + val timeout = state.let { if (it is SyncState.RUNNING && it.afterPause) 0 else DEFAULT_LONG_POOL_TIMEOUT } + + Timber.v("Execute sync request with timeout $timeout") val latch = CountDownLatch(1) - val params = SyncTask.Params(DEFAULT_LONG_POOL_TIMEOUT) + val params = SyncTask.Params(timeout) cancelableTask = syncTask.configureWith(params) { this.callbackThread = TaskThread.SYNC @@ -109,29 +119,31 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, this.callback = object : MatrixCallback { override fun onSuccess(data: Unit) { + Timber.v("onSuccess") latch.countDown() } override fun onFailure(failure: Throwable) { - if (failure is Failure.NetworkConnection - && failure.cause is SocketTimeoutException) { + if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) { // Timeout are not critical Timber.v("Timeout") - } else { - Timber.e(failure) - } - - if (failure !is Failure.NetworkConnection - || failure.cause is JsonEncodingException) { - // Wait 10s before retrying - sleep(RETRY_WAIT_TIME_MS) - } - - if (failure is Failure.ServerError + } else if (failure is Failure.Unknown && failure.throwable is CancellationException) { + Timber.v("Cancelled") + } else if (failure is Failure.ServerError && (failure.error.code == MatrixError.UNKNOWN_TOKEN || failure.error.code == MatrixError.MISSING_TOKEN)) { // No token or invalid token, stop the thread + Timber.w(failure) updateStateTo(SyncState.KILLING) + } else { + Timber.e(failure) + + if (failure !is Failure.NetworkConnection || failure.cause is JsonEncodingException) { + // Wait 10s before retrying + Timber.v("Wait 10s") + sleep(RETRY_WAIT_TIME_MS) + } } + latch.countDown() } } @@ -139,8 +151,10 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, .executeBy(taskExecutor) latch.await() - if (state is SyncState.RUNNING) { - updateStateTo(SyncState.RUNNING(afterPause = false)) + state.let { + if (it is SyncState.RUNNING && it.afterPause) { + updateStateTo(SyncState.RUNNING(afterPause = false)) + } } Timber.v("...Continue") diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index ebaa006b72..70793becce 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -65,6 +65,7 @@ import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent import im.vector.matrix.android.api.session.room.timeline.getTextEditableContent +import im.vector.matrix.android.api.session.sync.SyncState import im.vector.matrix.android.api.session.user.model.User import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent @@ -247,6 +248,14 @@ class RoomDetailFragment : is SendMode.REPLY -> enterSpecialMode(mode.timelineEvent, R.drawable.ic_reply, false) } } + + roomDetailViewModel.selectSubscribe(RoomDetailViewState::syncState) { syncState -> + syncProgressBar.visibility = when (syncState) { + is SyncState.RUNNING -> if (syncState.afterPause) View.VISIBLE else View.GONE + else -> View.GONE + } + syncProgressBarWrap.visibility = syncProgressBar.visibility + } } private fun setupNotificationView() { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index fe87117dcd..ec372a4d62 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -103,6 +103,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } init { + observeSyncState() observeRoomSummary() observeEventDisplayedActions() observeSummaryState() @@ -631,6 +632,17 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro .disposeOnClear() } + private fun observeSyncState() { + session.rx() + .liveSyncState() + .subscribe { syncState -> + setState { + copy(syncState = syncState) + } + } + .disposeOnClear() + } + private fun observeRoomSummary() { room.rx().liveRoomSummary() .execute { async -> diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt index 77c1c63cb6..d8358efe16 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewState.kt @@ -21,9 +21,9 @@ import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.RoomSummary -import im.vector.matrix.android.api.session.room.model.tombstone.RoomTombstoneContent import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.matrix.android.api.session.sync.SyncState import im.vector.matrix.android.api.session.user.model.User /** @@ -50,7 +50,8 @@ data class RoomDetailViewState( val sendMode: SendMode = SendMode.REGULAR, val isEncrypted: Boolean = false, val tombstoneEvent: Event? = null, - val tombstoneEventHandling: Async = Uninitialized + val tombstoneEventHandling: Async = Uninitialized, + val syncState: SyncState = SyncState.IDLE ) : MvRxState { constructor(args: RoomDetailArgs) : this(roomId = args.roomId, eventId = args.eventId) diff --git a/vector/src/main/res/layout/fragment_room_detail.xml b/vector/src/main/res/layout/fragment_room_detail.xml index 81a5b33dad..dee37e9d0f 100644 --- a/vector/src/main/res/layout/fragment_room_detail.xml +++ b/vector/src/main/res/layout/fragment_room_detail.xml @@ -11,8 +11,8 @@ style="@style/VectorToolbarStyle" android:layout_width="0dp" android:layout_height="?actionBarSize" - android:transitionName="toolbar" android:elevation="4dp" + android:transitionName="toolbar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -71,6 +71,29 @@ + + + + + +