Merge tag 'v1.4.31' into sc

Change-Id: I91353e1ae897942cd95f745d62c9250596c7112e
This commit is contained in:
SpiritCroc 2022-08-01 19:39:29 +02:00
commit 382e3726d6
9 changed files with 108 additions and 72 deletions

View File

@ -1,3 +1,12 @@
Changes in Element v1.4.31 (2022-08-01)
=======================================
Bugfixes 🐛
----------
- Fixes crash when returning to the app after backgrounding ([#6709](https://github.com/vector-im/element-android/issues/6709))
- Fix message content sometimes appearing in the log ([#6706](https://github.com/vector-im/element-android/issues/6706))
Changes in Element v1.4.30 (2022-07-29) Changes in Element v1.4.30 (2022-07-29)
======================================= =======================================

View File

@ -0,0 +1,2 @@
Main changes in this version: Enables the improved sign in and sign up journeys.
Full changelog: https://github.com/vector-im/element-android/releases

View File

@ -60,7 +60,7 @@ android {
// that the app's state is completely cleared between tests. // that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true' testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.4.30\"" buildConfigField "String", "SDK_VERSION", "\"1.4.31\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""

View File

@ -36,7 +36,7 @@ ext.versionMinor = 4
// Note: even values are reserved for regular release, odd values for hotfix release. // Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value // When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release. // is the value for the next regular release.
ext.versionPatch = 30 ext.versionPatch = 31
ext.scVersion = 55 ext.scVersion = 55

View File

@ -16,8 +16,10 @@
package im.vector.app.core.di package im.vector.app.core.di
import android.content.Context
import arrow.core.Option import arrow.core.Option
import im.vector.app.ActiveSessionDataSource import im.vector.app.ActiveSessionDataSource
import im.vector.app.core.extensions.configureAndStart
import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.pushers.UnifiedPushHelper
import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
@ -25,6 +27,8 @@ import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
import im.vector.app.features.notifications.PushRuleTriggerListener import im.vector.app.features.notifications.PushRuleTriggerListener
import im.vector.app.features.session.SessionListener import im.vector.app.features.session.SessionListener
import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@ -41,7 +45,10 @@ class ActiveSessionHolder @Inject constructor(
private val sessionListener: SessionListener, private val sessionListener: SessionListener,
private val imageManager: ImageManager, private val imageManager: ImageManager,
private val unifiedPushHelper: UnifiedPushHelper, private val unifiedPushHelper: UnifiedPushHelper,
private val guardServiceStarter: GuardServiceStarter private val guardServiceStarter: GuardServiceStarter,
private val sessionInitializer: SessionInitializer,
private val applicationContext: Context,
private val authenticationService: AuthenticationService,
) { ) {
private var activeSessionReference: AtomicReference<Session?> = AtomicReference() private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
@ -80,18 +87,27 @@ class ActiveSessionHolder @Inject constructor(
} }
fun hasActiveSession(): Boolean { fun hasActiveSession(): Boolean {
return activeSessionReference.get() != null return activeSessionReference.get() != null || authenticationService.hasAuthenticatedSessions()
} }
fun getSafeActiveSession(): Session? { fun getSafeActiveSession(): Session? {
return activeSessionReference.get() return runBlocking { getOrInitializeSession(startSync = true) }
} }
fun getActiveSession(): Session { fun getActiveSession(): Session {
return activeSessionReference.get() return getSafeActiveSession()
?: throw IllegalStateException("You should authenticate before using this") ?: throw IllegalStateException("You should authenticate before using this")
} }
suspend fun getOrInitializeSession(startSync: Boolean): Session? {
return activeSessionReference.get() ?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
setActiveSession(session)
session.configureAndStart(applicationContext, startSyncing = startSync)
}
}
fun isWaitingForSessionInitialization() = activeSessionReference.get() == null && authenticationService.hasAuthenticatedSessions()
// TODO Stop sync ? // TODO Stop sync ?
// fun switchToSession(sessionParams: SessionParams) { // fun switchToSession(sessionParams: SessionParams) {
// val newActiveSession = authenticationService.getSession(sessionParams) // val newActiveSession = authenticationService.getSession(sessionParams)

View File

@ -1,40 +0,0 @@
/*
* Copyright 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.di
import android.content.Context
import im.vector.app.core.extensions.configureAndStart
import org.matrix.android.sdk.api.auth.AuthenticationService
import javax.inject.Inject
class ActiveSessionSetter @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
private val authenticationService: AuthenticationService,
private val applicationContext: Context,
) {
fun shouldSetActionSession(): Boolean {
return authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()
}
fun tryToSetActiveSession(startSync: Boolean) {
if (shouldSetActionSession()) {
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
lastAuthenticatedSession.configureAndStart(applicationContext, startSyncing = startSync)
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.di
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject
private val initializerSemaphore = Semaphore(permits = 1)
class SessionInitializer @Inject constructor(
private val authenticationService: AuthenticationService,
) {
/**
* A thread safe way to initialize the last authenticated Session instance.
*
* @param readCurrentSession expects an in-memory Session to be provided or null if not yet set.
* @param initializer callback to allow additional initialization on the Session, such as setting the in-memory Session instance.
* @return the initialized Session or null when no authenticated sessions are available.
*/
suspend fun tryInitialize(readCurrentSession: () -> Session?, initializer: (Session) -> Unit): Session? {
return initializerSemaphore.withPermit {
val currentInMemorySession = readCurrentSession()
when {
currentInMemorySession != null -> currentInMemorySession
authenticationService.hasAuthenticatedSessions() -> {
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
lastAuthenticatedSession.also { initializer(lastAuthenticatedSession) }
}
else -> null
}
}
}
}

View File

@ -27,7 +27,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.BuildConfig import im.vector.app.BuildConfig
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.ActiveSessionSetter
import im.vector.app.core.network.WifiDetector import im.vector.app.core.network.WifiDetector
import im.vector.app.core.pushers.model.PushData import im.vector.app.core.pushers.model.PushData
import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.services.GuardServiceStarter
@ -38,6 +37,7 @@ import im.vector.app.features.settings.BackgroundSyncMode
import im.vector.app.features.settings.VectorDataStore import im.vector.app.features.settings.VectorDataStore
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -60,7 +60,6 @@ class VectorMessagingReceiver : MessagingReceiver() {
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
@Inject lateinit var notifiableEventResolver: NotifiableEventResolver @Inject lateinit var notifiableEventResolver: NotifiableEventResolver
@Inject lateinit var pushersManager: PushersManager @Inject lateinit var pushersManager: PushersManager
@Inject lateinit var activeSessionSetter: ActiveSessionSetter
@Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var vectorDataStore: VectorDataStore @Inject lateinit var vectorDataStore: VectorDataStore
@ -116,7 +115,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
// we are in foreground, let the sync do the things? // we are in foreground, let the sync do the things?
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore") Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
} else { } else {
onMessageReceivedInternal(pushData) coroutineScope.launch(Dispatchers.IO) { onMessageReceivedInternal(pushData) }
} }
} }
} }
@ -170,7 +169,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
* *
* @param pushData Object containing message data. * @param pushData Object containing message data.
*/ */
private fun onMessageReceivedInternal(pushData: PushData) { private suspend fun onMessageReceivedInternal(pushData: PushData) {
try { try {
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $pushData") Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $pushData")
@ -178,12 +177,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()") Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()")
} }
val session = activeSessionHolder.getSafeActiveSession() val session = activeSessionHolder.getOrInitializeSession(startSync = false)
?: run {
// Active session may not exist yet, if MainActivity has not been launched
activeSessionSetter.tryToSetActiveSession(startSync = false)
activeSessionHolder.getSafeActiveSession()
}
if (session == null) { if (session == null) {
Timber.tag(loggerTag.value).w("## Can't sync from push, no current session") Timber.tag(loggerTag.value).w("## Can't sync from push, no current session")
@ -204,7 +198,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
} }
} }
private fun getEventFastLane(session: Session, pushData: PushData) { private suspend fun getEventFastLane(session: Session, pushData: PushData) {
pushData.roomId ?: return pushData.roomId ?: return
pushData.eventId ?: return pushData.eventId ?: return
@ -218,18 +212,16 @@ class VectorMessagingReceiver : MessagingReceiver() {
return return
} }
coroutineScope.launch { Timber.tag(loggerTag.value).d("Fast lane: start request")
Timber.tag(loggerTag.value).d("Fast lane: start request") val event = tryOrNull { session.eventService().getEvent(pushData.roomId, pushData.eventId) } ?: return
val event = tryOrNull { session.eventService().getEvent(pushData.roomId, pushData.eventId) } ?: return@launch
val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event, canBeReplaced = true) val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event, canBeReplaced = true)
resolvedEvent resolvedEvent
?.also { Timber.tag(loggerTag.value).d("Fast lane: notify drawer") } ?.also { Timber.tag(loggerTag.value).d("Fast lane: notify drawer") }
?.let { ?.let {
notificationDrawerManager.updateEvents { it.onNotifiableEventReceived(resolvedEvent) } notificationDrawerManager.updateEvents { it.onNotifiableEventReceived(resolvedEvent) }
} }
}
} }
// check if the event was not yet received // check if the event was not yet received

View File

@ -20,9 +20,10 @@ import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.core.di.ActiveSessionSetter import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.dispatchers.CoroutineDispatchers
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -31,7 +32,8 @@ import kotlin.time.Duration.Companion.seconds
class StartAppViewModel @AssistedInject constructor( class StartAppViewModel @AssistedInject constructor(
@Assisted val initialState: StartAppViewState, @Assisted val initialState: StartAppViewState,
private val activeSessionSetter: ActiveSessionSetter, private val sessionHolder: ActiveSessionHolder,
private val dispatchers: CoroutineDispatchers,
) : VectorViewModel<StartAppViewState, StartAppAction, StartAppViewEvent>(initialState) { ) : VectorViewModel<StartAppViewState, StartAppAction, StartAppViewEvent>(initialState) {
@AssistedFactory @AssistedFactory
@ -42,7 +44,7 @@ class StartAppViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory<StartAppViewModel, StartAppViewState> by hiltMavericksViewModelFactory() companion object : MavericksViewModelFactory<StartAppViewModel, StartAppViewState> by hiltMavericksViewModelFactory()
fun shouldStartApp(): Boolean { fun shouldStartApp(): Boolean {
return activeSessionSetter.shouldSetActionSession() return sessionHolder.isWaitingForSessionInitialization()
} }
override fun handle(action: StartAppAction) { override fun handle(action: StartAppAction) {
@ -53,13 +55,17 @@ class StartAppViewModel @AssistedInject constructor(
private fun handleStartApp() { private fun handleStartApp() {
handleLongProcessing() handleLongProcessing()
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(dispatchers.io) {
// This can take time because of DB migration(s), so do it in a background task. // This can take time because of DB migration(s), so do it in a background task.
activeSessionSetter.tryToSetActiveSession(startSync = true) eagerlyInitializeSession()
_viewEvents.post(StartAppViewEvent.AppStarted) _viewEvents.post(StartAppViewEvent.AppStarted)
} }
} }
private suspend fun eagerlyInitializeSession() {
sessionHolder.getOrInitializeSession(startSync = true)
}
private fun handleLongProcessing() { private fun handleLongProcessing() {
viewModelScope.launch(Dispatchers.Default) { viewModelScope.launch(Dispatchers.Default) {
delay(1.seconds.inWholeMilliseconds) delay(1.seconds.inWholeMilliseconds)