From 0dd9e943c7096d30a26fed9108508ba4eaeafb99 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Jul 2022 21:40:48 +0200 Subject: [PATCH 1/8] Delegate the creation of the Session to MainActivity instead of VectorApplication to unblock the main thread. This fix is not necessary anymore, since the session is restored either in `MainActivity` or in `VectorMessagingReceiver`. Ref: b7a54ead681c0396662d47b2df70605c16f9e0ad --- .../im/vector/app/features/MainViewModel.kt | 66 +++++++++++++++++++ .../java/im/vector/app/VectorApplication.kt | 18 ----- .../vector/app/core/di/ActiveSessionSetter.kt | 37 +++++++++++ .../app/core/di/MavericksViewModelModule.kt | 6 ++ .../core/pushers/VectorMessagingReceiver.kt | 7 ++ .../im/vector/app/features/MainActivity.kt | 20 ++++++ 6 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/features/MainViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt diff --git a/vector/src/debug/java/im/vector/app/features/MainViewModel.kt b/vector/src/debug/java/im/vector/app/features/MainViewModel.kt new file mode 100644 index 0000000000..51fdabebc8 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/MainViewModel.kt @@ -0,0 +1,66 @@ +/* + * 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.features + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionSetter +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.VectorDummyViewState +import im.vector.app.core.platform.VectorViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.platform.VectorViewModelAction +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +sealed interface MainViewAction : VectorViewModelAction { + object StartApp : MainViewAction +} + +sealed interface MainViewEvent : VectorViewEvents { + object AppStarted : MainViewEvent +} + +class MainViewModel @AssistedInject constructor( + @Assisted val initialState: VectorDummyViewState, + private val activeSessionSetter: ActiveSessionSetter, +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: VectorDummyViewState): MainViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + override fun handle(action: MainViewAction) { + when (action) { + MainViewAction.StartApp -> handleStartApp() + } + } + + private fun handleStartApp() { + viewModelScope.launch(Dispatchers.IO) { + // This can take time because of DB migration(s), so do it in a background task. + activeSessionSetter.tryToSetActiveSession(startSync = true) + _viewEvents.post(MainViewEvent.AppStarted) + } + } +} diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 3cb0423ca8..24d9770604 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -41,8 +41,6 @@ import com.vanniktech.emoji.EmojiManager import com.vanniktech.emoji.google.GoogleEmojiProvider import dagger.hilt.android.HiltAndroidApp import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.core.extensions.configureAndStart -import im.vector.app.core.extensions.startSyncing import im.vector.app.features.analytics.VectorAnalytics import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.configuration.VectorConfiguration @@ -165,14 +163,6 @@ class VectorApplication : doNotShowDisclaimerDialog(this) } - if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { - val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!! - activeSessionHolder.setActiveSession(lastAuthenticatedSession) - lastAuthenticatedSession.configureAndStart(applicationContext, startSyncing = false) - } - - ProcessLifecycleOwner.get().lifecycle.addObserver(startSyncOnFirstStart) - ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { Timber.i("App entered foreground") @@ -205,14 +195,6 @@ class VectorApplication : Mapbox.getInstance(this) } - private val startSyncOnFirstStart = object : DefaultLifecycleObserver { - override fun onStart(owner: LifecycleOwner) { - Timber.i("App process started") - authenticationService.getLastAuthenticatedSession()?.startSyncing(appContext) - ProcessLifecycleOwner.get().lifecycle.removeObserver(this) - } - } - private fun enableStrictModeIfNeeded() { if (BuildConfig.ENABLE_STRICT_MODE_LOGS) { StrictMode.setThreadPolicy( diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt new file mode 100644 index 0000000000..59c2037cbe --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt @@ -0,0 +1,37 @@ +/* + * 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 tryToSetActiveSession(startSync: Boolean) { + if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { + val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!! + activeSessionHolder.setActiveSession(lastAuthenticatedSession) + lastAuthenticatedSession.configureAndStart(applicationContext, startSyncing = startSync) + activeSessionHolder.setActiveSession(lastAuthenticatedSession) + } + } +} diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index a3e08036ff..3cd8dc66e9 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -20,6 +20,7 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.multibindings.IntoMap +import im.vector.app.features.MainViewModel import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel import im.vector.app.features.auth.ReAuthViewModel @@ -483,6 +484,11 @@ interface MavericksViewModelModule { @MavericksViewModelKey(AnalyticsAccountDataViewModel::class) fun analyticsAccountDataViewModelFactory(factory: AnalyticsAccountDataViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + @Binds + @IntoMap + @MavericksViewModelKey(MainViewModel::class) + fun mainViewModelFactory(factory: MainViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + @Binds @IntoMap @MavericksViewModelKey(HomeServerCapabilitiesViewModel::class) diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 53a5470ff7..be84dfeaba 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -27,6 +27,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import dagger.hilt.android.AndroidEntryPoint import im.vector.app.BuildConfig 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.pushers.model.PushData import im.vector.app.core.services.GuardServiceStarter @@ -59,6 +60,7 @@ class VectorMessagingReceiver : MessagingReceiver() { @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var notifiableEventResolver: NotifiableEventResolver @Inject lateinit var pushersManager: PushersManager + @Inject lateinit var activeSessionSetter: ActiveSessionSetter @Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var vectorDataStore: VectorDataStore @@ -177,6 +179,11 @@ class VectorMessagingReceiver : MessagingReceiver() { } val session = activeSessionHolder.getSafeActiveSession() + ?: run { + // Active session may not exist yet, if MainActivity has not been launched + activeSessionSetter.tryToSetActiveSession(startSync = false) + activeSessionHolder.getSafeActiveSession() + } if (session == null) { Timber.tag(loggerTag.value).w("## Can't sync from push, no current session") diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index c2f6f2d778..6bc0a2ca86 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -22,6 +22,7 @@ import android.os.Bundle import android.os.Parcelable import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import com.airbnb.mvrx.viewModel import com.bumptech.glide.Glide import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -47,6 +48,8 @@ import im.vector.app.features.signout.hard.SignedOutActivity import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.ui.UiStateRepository import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize @@ -84,6 +87,8 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } + private val mainViewModel: MainViewModel by viewModel() + override fun getBinding() = ActivityMainBinding.inflate(layoutInflater) override fun getOtherThemes() = ActivityOtherThemes.Launcher @@ -103,6 +108,21 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + mainViewModel.viewEvents.stream() + .onEach(::handleViewEvents) + .launchIn(lifecycleScope) + + mainViewModel.handle(MainViewAction.StartApp) + } + + private fun handleViewEvents(event: MainViewEvent) { + when (event) { + MainViewEvent.AppStarted -> handleAppStarted() + } + } + + private fun handleAppStarted() { args = parseArgs() if (args.clearCredentials || args.isUserLoggedOut || args.clearCache) { clearNotifications() From c8a2bfc7385db9fb79c6035f6acf5458701fcfe4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Jul 2022 21:01:28 +0200 Subject: [PATCH 2/8] Always start MainActivity to ensure that current session is set. --- .../im/vector/app/features/MainActivity.kt | 34 ++++++++++++++----- .../app/features/call/VectorCallActivity.kt | 2 +- .../vector/app/features/home/HomeActivity.kt | 4 ++- .../home/room/detail/RoomDetailActivity.kt | 10 ++++-- .../home/room/detail/TimelineFragment.kt | 6 ++-- .../features/navigation/DefaultNavigator.kt | 6 ++-- .../notifications/NotificationUtils.kt | 11 +++--- 7 files changed, 51 insertions(+), 22 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 6bc0a2ca86..c0af9f9e70 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -17,6 +17,7 @@ package im.vector.app.features import android.app.Activity +import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable @@ -76,6 +77,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity companion object { private const val EXTRA_ARGS = "EXTRA_ARGS" + private const val EXTRA_NEXT_INTENT = "EXTRA_NEXT_INTENT" // Special action to clear cache and/or clear credentials fun restartApp(activity: Activity, args: MainActivityArgs) { @@ -85,6 +87,12 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity intent.putExtra(EXTRA_ARGS, args) activity.startActivity(intent) } + + fun getIntentWithNextIntent(context: Context, nextIntent: Intent): Intent { + val intent = Intent(context, MainActivity::class.java) + intent.putExtra(EXTRA_NEXT_INTENT, nextIntent) + return intent + } } private val mainViewModel: MainViewModel by viewModel() @@ -123,15 +131,21 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } private fun handleAppStarted() { - args = parseArgs() - if (args.clearCredentials || args.isUserLoggedOut || args.clearCache) { - clearNotifications() - } - // Handle some wanted cleanup - if (args.clearCache || args.clearCredentials) { - doCleanUp() + if (intent.hasExtra(EXTRA_NEXT_INTENT)) { + // Start the next Activity + val nextIntent = intent.getParcelableExtra(EXTRA_NEXT_INTENT) + startIntentAndFinish(nextIntent) } else { - startNextActivityAndFinish() + args = parseArgs() + if (args.clearCredentials || args.isUserLoggedOut || args.clearCache) { + clearNotifications() + } + // Handle some wanted cleanup + if (args.clearCache || args.clearCredentials) { + doCleanUp() + } else { + startNextActivityAndFinish() + } } } @@ -273,6 +287,10 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity null } } + startIntentAndFinish(intent) + } + + private fun startIntentAndFinish(intent: Intent?) { intent?.let { startActivity(it) } finish() } diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 9d7ada9d63..f8a4c5eeca 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -604,7 +604,7 @@ class VectorCallActivity : private fun returnToChat() { val roomId = withState(callViewModel) { it.roomId } val args = TimelineArgs(roomId) - val intent = RoomDetailActivity.newIntent(this, args).apply { + val intent = RoomDetailActivity.newIntent(this, args, false).apply { flags = FLAG_ACTIVITY_CLEAR_TOP } startActivity(intent) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 926c1eb113..0eb136fc10 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -623,10 +623,12 @@ class HomeActivity : inviteNotificationRoomId = inviteNotificationRoomId ) - return Intent(context, HomeActivity::class.java) + val intent = Intent(context, HomeActivity::class.java) .apply { putExtra(Mavericks.KEY_ARG, args) } + + return MainActivity.getIntentWithNextIntent(context, intent) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt index f1e06dd5ef..a58eed42e1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt @@ -35,6 +35,7 @@ import im.vector.app.core.extensions.keepScreenOn import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivityRoomDetailBinding +import im.vector.app.features.MainActivity import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment @@ -191,10 +192,15 @@ class RoomDetailActivity : const val EXTRA_ROOM_ID = "EXTRA_ROOM_ID" const val ACTION_ROOM_DETAILS_FROM_SHORTCUT = "ROOM_DETAILS_FROM_SHORTCUT" - fun newIntent(context: Context, timelineArgs: TimelineArgs): Intent { - return Intent(context, RoomDetailActivity::class.java).apply { + fun newIntent(context: Context, timelineArgs: TimelineArgs, firstStartMainActivity: Boolean): Intent { + val intent = Intent(context, RoomDetailActivity::class.java).apply { putExtra(EXTRA_ROOM_DETAIL_ARGS, timelineArgs) } + return if (firstStartMainActivity) { + MainActivity.getIntentWithNextIntent(context, intent) + } else { + intent + } } // Shortcuts can't have intents with parcelables diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 31c1004ef9..562f2d4aea 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -1206,9 +1206,9 @@ class TimelineFragment @Inject constructor( getRootThreadEventId()?.let { val newRoom = timelineArgs.copy(threadTimelineArgs = null, eventId = it) context?.let { con -> - val int = RoomDetailActivity.newIntent(con, newRoom) - int.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK - con.startActivity(int) + val intent = RoomDetailActivity.newIntent(con, newRoom, false) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + con.startActivity(intent) } } } diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 291eee307f..7680b40506 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -173,7 +173,7 @@ class DefaultNavigator @Inject constructor( } val args = TimelineArgs(roomId = roomId, eventId = eventId, isInviteAlreadyAccepted = isInviteAlreadyAccepted) - val intent = RoomDetailActivity.newIntent(context, args) + val intent = RoomDetailActivity.newIntent(context, args, false) startActivity(context, intent, buildTask) } @@ -203,7 +203,7 @@ class DefaultNavigator @Inject constructor( eventId = null, openShareSpaceForId = spaceId.takeIf { postSwitchSpaceAction.showShareSheet } ) - val intent = RoomDetailActivity.newIntent(context, args) + val intent = RoomDetailActivity.newIntent(context, args, false) startActivity(context, intent, false) } } @@ -290,7 +290,7 @@ class DefaultNavigator @Inject constructor( override fun openRoomForSharingAndFinish(activity: Activity, roomId: String, sharedData: SharedData) { val args = TimelineArgs(roomId, null, sharedData) - val intent = RoomDetailActivity.newIntent(activity, args) + val intent = RoomDetailActivity.newIntent(activity, args, false) activity.startActivity(intent) activity.finish() } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 71c8167788..0066fab5ce 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -53,6 +53,7 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.core.services.CallAndroidService import im.vector.app.core.time.Clock import im.vector.app.core.utils.startNotificationChannelSettingsIntent +import im.vector.app.features.MainActivity import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.service.CallHeadsUpActionReceiver import im.vector.app.features.call.webrtc.WebRtcCall @@ -241,7 +242,8 @@ class NotificationUtils @Inject constructor( // build the pending intent go to the home screen if this is clicked. val i = HomeActivity.newIntent(context) i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP - val pi = PendingIntent.getActivity(context, 0, i, PendingIntentCompat.FLAG_IMMUTABLE) + val mainIntent = MainActivity.getIntentWithNextIntent(context, i) + val pi = PendingIntent.getActivity(context, 0, mainIntent, PendingIntentCompat.FLAG_IMMUTABLE) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) @@ -531,7 +533,7 @@ class NotificationUtils @Inject constructor( val contentPendingIntent = TaskStackBuilder.create(context) .addNextIntentWithParentStack(HomeActivity.newIntent(context)) - .addNextIntent(RoomDetailActivity.newIntent(context, TimelineArgs(callInformation.nativeRoomId))) + .addNextIntent(RoomDetailActivity.newIntent(context, TimelineArgs(callInformation.nativeRoomId), true)) .getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) builder.setContentIntent(contentPendingIntent) @@ -828,7 +830,7 @@ class NotificationUtils @Inject constructor( } private fun buildOpenRoomIntent(roomId: String): PendingIntent? { - val roomIntentTap = RoomDetailActivity.newIntent(context, TimelineArgs(roomId = roomId, switchToParentSpace = true)) + val roomIntentTap = RoomDetailActivity.newIntent(context, TimelineArgs(roomId = roomId, switchToParentSpace = true), true) roomIntentTap.action = TAP_TO_VIEW_ACTION // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that roomIntentTap.data = createIgnoredUri("openRoom?$roomId") @@ -847,10 +849,11 @@ class NotificationUtils @Inject constructor( val intent = HomeActivity.newIntent(context, clearNotification = true) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.data = createIgnoredUri("tapSummary") + val mainIntent = MainActivity.getIntentWithNextIntent(context, intent) return PendingIntent.getActivity( context, Random.nextInt(1000), - intent, + mainIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) } From b7826c02a3c32f9516554c74de02559c18a23e19 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 15 Jul 2022 17:17:00 +0200 Subject: [PATCH 3/8] Start SDK before handling permalink or sharing to the app. It also fixes a crash when trying to share to the app if there is no active session: `IncomingShareViewModel` injects the `session` in the constructor. --- .../vector/app/core/di/ActiveSessionSetter.kt | 7 ++- .../app/core/di/MavericksViewModelModule.kt | 6 +-- .../im/vector/app/features/MainActivity.kt | 23 +++++++-- .../app/features/link/LinkHandlerActivity.kt | 26 ++++++++++ .../app/features/share/IncomingShareAction.kt | 2 +- .../features/share/IncomingShareActivity.kt | 51 +++++++++++++++++-- .../features/share/IncomingShareFragment.kt | 19 +------ .../features/share/IncomingShareViewModel.kt | 4 +- .../app/features/start/StartAppAction.kt | 23 +++++++++ .../app/features/start/StartAppViewEvent.kt | 23 +++++++++ .../app/features/start/StartAppViewModel.kt} | 35 +++++-------- .../app/features/start/StartAppViewState.kt | 23 +++++++++ 12 files changed, 188 insertions(+), 54 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/start/StartAppAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt rename vector/src/{debug/java/im/vector/app/features/MainViewModel.kt => main/java/im/vector/app/features/start/StartAppViewModel.kt} (58%) create mode 100644 vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt index 59c2037cbe..09479a230f 100644 --- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt +++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionSetter.kt @@ -26,12 +26,15 @@ class ActiveSessionSetter @Inject constructor( private val authenticationService: AuthenticationService, private val applicationContext: Context, ) { + fun shouldSetActionSession(): Boolean { + return authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession() + } + fun tryToSetActiveSession(startSync: Boolean) { - if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { + if (shouldSetActionSession()) { val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!! activeSessionHolder.setActiveSession(lastAuthenticatedSession) lastAuthenticatedSession.configureAndStart(applicationContext, startSyncing = startSync) - activeSessionHolder.setActiveSession(lastAuthenticatedSession) } } } diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 3cd8dc66e9..a5fa04f1b0 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -20,7 +20,6 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.multibindings.IntoMap -import im.vector.app.features.MainViewModel import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel import im.vector.app.features.auth.ReAuthViewModel @@ -112,6 +111,7 @@ import im.vector.app.features.spaces.manage.SpaceManageSharedViewModel import im.vector.app.features.spaces.people.SpacePeopleViewModel import im.vector.app.features.spaces.preview.SpacePreviewViewModel import im.vector.app.features.spaces.share.ShareSpaceViewModel +import im.vector.app.features.start.StartAppViewModel import im.vector.app.features.terms.ReviewTermsViewModel import im.vector.app.features.usercode.UserCodeSharedViewModel import im.vector.app.features.userdirectory.UserListViewModel @@ -486,8 +486,8 @@ interface MavericksViewModelModule { @Binds @IntoMap - @MavericksViewModelKey(MainViewModel::class) - fun mainViewModelFactory(factory: MainViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + @MavericksViewModelKey(StartAppViewModel::class) + fun startAppViewModelFactory(factory: StartAppViewModel.Factory): MavericksAssistedViewModelFactory<*, *> @Binds @IntoMap diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index c0af9f9e70..f160e77aa0 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -46,6 +46,9 @@ import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.session.VectorSessionStore import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.signout.hard.SignedOutActivity +import im.vector.app.features.start.StartAppAction +import im.vector.app.features.start.StartAppViewEvent +import im.vector.app.features.start.StartAppViewModel import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.ui.UiStateRepository import kotlinx.coroutines.Dispatchers @@ -78,6 +81,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity companion object { private const val EXTRA_ARGS = "EXTRA_ARGS" private const val EXTRA_NEXT_INTENT = "EXTRA_NEXT_INTENT" + private const val EXTRA_INIT_SESSION = "EXTRA_INIT_SESSION" // Special action to clear cache and/or clear credentials fun restartApp(activity: Activity, args: MainActivityArgs) { @@ -88,6 +92,12 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity activity.startActivity(intent) } + fun getIntentToInitSession(activity: Activity): Intent { + val intent = Intent(activity, MainActivity::class.java) + intent.putExtra(EXTRA_INIT_SESSION, true) + return intent + } + fun getIntentWithNextIntent(context: Context, nextIntent: Intent): Intent { val intent = Intent(context, MainActivity::class.java) intent.putExtra(EXTRA_NEXT_INTENT, nextIntent) @@ -95,7 +105,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } - private val mainViewModel: MainViewModel by viewModel() + private val startAppViewModel: StartAppViewModel by viewModel() override fun getBinding() = ActivityMainBinding.inflate(layoutInflater) @@ -117,16 +127,16 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mainViewModel.viewEvents.stream() + startAppViewModel.viewEvents.stream() .onEach(::handleViewEvents) .launchIn(lifecycleScope) - mainViewModel.handle(MainViewAction.StartApp) + startAppViewModel.handle(StartAppAction.StartApp) } - private fun handleViewEvents(event: MainViewEvent) { + private fun handleViewEvents(event: StartAppViewEvent) { when (event) { - MainViewEvent.AppStarted -> handleAppStarted() + StartAppViewEvent.AppStarted -> handleAppStarted() } } @@ -135,6 +145,9 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity // Start the next Activity val nextIntent = intent.getParcelableExtra(EXTRA_NEXT_INTENT) startIntentAndFinish(nextIntent) + } else if (intent.hasExtra(EXTRA_INIT_SESSION)) { + setResult(RESULT_OK) + finish() } else { args = parseArgs() if (args.clearCredentials || args.isUserLoggedOut || args.clearCache) { diff --git a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt index 6de73cb20f..0bdec53f60 100644 --- a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt @@ -18,18 +18,23 @@ package im.vector.app.features.link import android.content.Intent import android.net.Uri +import android.os.Bundle import androidx.lifecycle.lifecycleScope +import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.toast import im.vector.app.databinding.ActivityProgressBinding +import im.vector.app.features.MainActivity import im.vector.app.features.home.HomeActivity import im.vector.app.features.login.LoginConfig import im.vector.app.features.permalink.PermalinkHandler +import im.vector.app.features.start.StartAppViewModel import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.permalinks.PermalinkService import timber.log.Timber @@ -45,12 +50,33 @@ class LinkHandlerActivity : VectorBaseActivity() { @Inject lateinit var errorFormatter: ErrorFormatter @Inject lateinit var permalinkHandler: PermalinkHandler + private val startAppViewModel: StartAppViewModel by viewModel() + override fun getBinding() = ActivityProgressBinding.inflate(layoutInflater) override fun initUiAndData() { handleIntent() } + private val launcher = registerStartForActivityResult { + if (it.resultCode == RESULT_OK) { + handleIntent() + } else { + // User has pressed back on the MainActivity, so finish also this one. + finish() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (startAppViewModel.shouldStartApp()) { + launcher.launch(MainActivity.getIntentToInitSession(this)) + } else { + handleIntent() + } + } + override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) handleIntent() diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareAction.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareAction.kt index 4e9f024b15..70be2b2b6d 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareAction.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareAction.kt @@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary sealed class IncomingShareAction : VectorViewModelAction { data class SelectRoom(val roomSummary: RoomSummary, val enableMultiSelect: Boolean) : IncomingShareAction() object ShareToSelectedRooms : IncomingShareAction() - data class ShareToRoom(val roomSummary: RoomSummary) : IncomingShareAction() + data class ShareToRoom(val roomId: String) : IncomingShareAction() data class ShareMedia(val keepOriginalSize: Boolean) : IncomingShareAction() data class FilterWith(val filter: String) : IncomingShareAction() data class UpdateSharedData(val sharedData: SharedData) : IncomingShareAction() diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt index 439d9b64fa..3d603e3f6a 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt @@ -16,21 +16,66 @@ package im.vector.app.features.share +import android.content.Intent +import android.os.Bundle +import com.airbnb.mvrx.viewModel import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.addFragment +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySimpleBinding +import im.vector.app.features.MainActivity +import im.vector.app.features.start.StartAppViewModel +import javax.inject.Inject @AndroidEntryPoint class IncomingShareActivity : VectorBaseActivity() { + private val startAppViewModel: StartAppViewModel by viewModel() + + @Inject lateinit var activeSessionHolder: ActiveSessionHolder + + private val launcher = registerStartForActivityResult { + if (it.resultCode == RESULT_OK) { + handleAppStarted() + } else { + // User has pressed back on the MainActivity, so finish also this one. + finish() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (startAppViewModel.shouldStartApp()) { + launcher.launch(MainActivity.getIntentToInitSession(this)) + } else { + handleAppStarted() + } + } + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun getCoordinatorLayout() = views.coordinatorLayout - override fun initUiAndData() { - if (isFirstCreation()) { - addFragment(views.simpleFragmentContainer, IncomingShareFragment::class.java) + private fun handleAppStarted() { + // If we are not logged in, stop the sharing process and open login screen. + // In the future, we might want to relaunch the sharing process after login. + if (!activeSessionHolder.hasActiveSession()) { + startLoginActivity() + } else { + if (isFirstCreation()) { + addFragment(views.simpleFragmentContainer, IncomingShareFragment::class.java) + } } } + + private fun startLoginActivity() { + navigator.openLogin( + context = this, + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK + ) + finish() + } } diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt index 3f8923dd68..3e2ddc469c 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt @@ -30,7 +30,6 @@ import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R -import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.registerStartForActivityResult @@ -40,7 +39,6 @@ import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.attachments.ShareIntentHandler import im.vector.app.features.attachments.preview.AttachmentsPreviewActivity import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs -import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary import javax.inject.Inject @@ -50,7 +48,6 @@ import javax.inject.Inject */ class IncomingShareFragment @Inject constructor( private val incomingShareController: IncomingShareController, - private val sessionHolder: ActiveSessionHolder, private val shareIntentHandler: ShareIntentHandler, ) : VectorBaseFragment(), @@ -63,12 +60,6 @@ class IncomingShareFragment @Inject constructor( } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - // If we are not logged in, stop the sharing process and open login screen. - // In the future, we might want to relaunch the sharing process after login. - if (!sessionHolder.hasActiveSession()) { - startLoginActivity() - return - } super.onViewCreated(view, savedInstanceState) setupRecyclerView() setupToolbar(views.incomingShareToolbar) @@ -88,7 +79,7 @@ class IncomingShareFragment @Inject constructor( // Direct share if (intent.hasExtra(Intent.EXTRA_SHORTCUT_ID)) { val roomId = intent.getStringExtra(Intent.EXTRA_SHORTCUT_ID)!! - sessionHolder.getSafeActiveSession()?.getRoomSummary(roomId)?.let { viewModel.handle(IncomingShareAction.ShareToRoom(it)) } + viewModel.handle(IncomingShareAction.ShareToRoom(roomId)) } isShareManaged } @@ -192,14 +183,6 @@ class IncomingShareFragment @Inject constructor( .show() } - private fun startLoginActivity() { - navigator.openLogin( - context = requireActivity(), - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK - ) - requireActivity().finish() - } - override fun invalidate() = withState(viewModel) { views.sendShareButton.isVisible = it.isInMultiSelectionMode incomingShareController.setData(it) diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt index 1191fd04e8..85629ea150 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt @@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.flow.flow @@ -134,7 +135,8 @@ class IncomingShareViewModel @AssistedInject constructor( private fun handleShareToRoom(action: IncomingShareAction.ShareToRoom) = withState { state -> val sharedData = state.sharedData ?: return@withState - _viewEvents.post(IncomingShareViewEvents.ShareToRoom(action.roomSummary, sharedData, showAlert = false)) + val roomSummary = session.getRoomSummary(action.roomId) ?: return@withState + _viewEvents.post(IncomingShareViewEvents.ShareToRoom(roomSummary, sharedData, showAlert = false)) } private fun handleShareMediaToSelectedRooms(action: IncomingShareAction.ShareMedia) = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppAction.kt b/vector/src/main/java/im/vector/app/features/start/StartAppAction.kt new file mode 100644 index 0000000000..fffb124f12 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/start/StartAppAction.kt @@ -0,0 +1,23 @@ +/* + * 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.features.start + +import im.vector.app.core.platform.VectorViewModelAction + +sealed interface StartAppAction : VectorViewModelAction { + object StartApp : StartAppAction +} diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt new file mode 100644 index 0000000000..9e185cbe04 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt @@ -0,0 +1,23 @@ +/* + * 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.features.start + +import im.vector.app.core.platform.VectorViewEvents + +sealed interface StartAppViewEvent : VectorViewEvents { + object AppStarted : StartAppViewEvent +} diff --git a/vector/src/debug/java/im/vector/app/features/MainViewModel.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt similarity index 58% rename from vector/src/debug/java/im/vector/app/features/MainViewModel.kt rename to vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt index 51fdabebc8..eeec52283d 100644 --- a/vector/src/debug/java/im/vector/app/features/MainViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features +package im.vector.app.features.start import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted @@ -23,36 +23,29 @@ import dagger.assisted.AssistedInject import im.vector.app.core.di.ActiveSessionSetter import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.platform.VectorDummyViewState -import im.vector.app.core.platform.VectorViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.core.platform.VectorViewModelAction import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -sealed interface MainViewAction : VectorViewModelAction { - object StartApp : MainViewAction -} - -sealed interface MainViewEvent : VectorViewEvents { - object AppStarted : MainViewEvent -} - -class MainViewModel @AssistedInject constructor( - @Assisted val initialState: VectorDummyViewState, +class StartAppViewModel @AssistedInject constructor( + @Assisted val initialState: StartAppViewState, private val activeSessionSetter: ActiveSessionSetter, -) : VectorViewModel(initialState) { +) : VectorViewModel(initialState) { @AssistedFactory - interface Factory : MavericksAssistedViewModelFactory { - override fun create(initialState: VectorDummyViewState): MainViewModel + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: StartAppViewState): StartAppViewModel } - companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() - override fun handle(action: MainViewAction) { + fun shouldStartApp(): Boolean { + return activeSessionSetter.shouldSetActionSession() + } + + override fun handle(action: StartAppAction) { when (action) { - MainViewAction.StartApp -> handleStartApp() + StartAppAction.StartApp -> handleStartApp() } } @@ -60,7 +53,7 @@ class MainViewModel @AssistedInject constructor( viewModelScope.launch(Dispatchers.IO) { // This can take time because of DB migration(s), so do it in a background task. activeSessionSetter.tryToSetActiveSession(startSync = true) - _viewEvents.post(MainViewEvent.AppStarted) + _viewEvents.post(StartAppViewEvent.AppStarted) } } } diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt new file mode 100644 index 0000000000..50418e90dc --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt @@ -0,0 +1,23 @@ +/* + * 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.features.start + +import com.airbnb.mvrx.MavericksState + +data class StartAppViewState( + val duration: Long = 0 +) : MavericksState From 0bedfc80878d8ef3ec5c3a6d6dda46d8951df57c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 15 Jul 2022 17:32:49 +0200 Subject: [PATCH 4/8] Add a message when migrating the data (after 1 seconds) --- .../im/vector/app/features/MainActivity.kt | 12 ++++++++++++ .../app/features/start/StartAppViewModel.kt | 14 ++++++++++++++ vector/src/main/res/layout/activity_main.xml | 19 +++++++++++++++++-- vector/src/main/res/values/strings.xml | 1 + 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index f160e77aa0..805a52958a 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.viewModel @@ -49,6 +50,7 @@ import im.vector.app.features.signout.hard.SignedOutActivity import im.vector.app.features.start.StartAppAction import im.vector.app.features.start.StartAppViewEvent import im.vector.app.features.start.StartAppViewModel +import im.vector.app.features.start.StartAppViewState import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.ui.UiStateRepository import kotlinx.coroutines.Dispatchers @@ -127,6 +129,9 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + startAppViewModel.onEach { + renderState(it) + } startAppViewModel.viewEvents.stream() .onEach(::handleViewEvents) .launchIn(lifecycleScope) @@ -134,6 +139,13 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity startAppViewModel.handle(StartAppAction.StartApp) } + private fun renderState(state: StartAppViewState) { + if (state.duration > 0) { + views.status.setText(R.string.updating_your_data) + } + views.status.isVisible = state.duration > 0 + } + private fun handleViewEvents(event: StartAppViewEvent) { when (event) { StartAppViewEvent.AppStarted -> handleAppStarted() diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt index eeec52283d..b66a072195 100644 --- a/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt @@ -24,8 +24,12 @@ import im.vector.app.core.di.ActiveSessionSetter import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel +import im.vector.lib.core.utils.flow.tickerFlow import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import kotlin.time.Duration.Companion.seconds class StartAppViewModel @AssistedInject constructor( @Assisted val initialState: StartAppViewState, @@ -50,10 +54,20 @@ class StartAppViewModel @AssistedInject constructor( } private fun handleStartApp() { + startTimer() viewModelScope.launch(Dispatchers.IO) { // This can take time because of DB migration(s), so do it in a background task. activeSessionSetter.tryToSetActiveSession(startSync = true) _viewEvents.post(StartAppViewEvent.AppStarted) } } + + private fun startTimer() { + setState { copy(duration = 0) } + tickerFlow(viewModelScope, 1.seconds.inWholeMilliseconds) + .onEach { + setState { copy(duration = duration + 1) } + } + .launchIn(viewModelScope) + } } diff --git a/vector/src/main/res/layout/activity_main.xml b/vector/src/main/res/layout/activity_main.xml index c7bca50acb..ba5925f000 100644 --- a/vector/src/main/res/layout/activity_main.xml +++ b/vector/src/main/res/layout/activity_main.xml @@ -1,5 +1,4 @@ - - + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index ed0cf691e2..cf844d29b0 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1625,6 +1625,7 @@ No network. Please check your Internet connection. "Change network" "Please wait…" + Updating your data… "All Communities" From b294c9a1fd82a1ef23e618079109c979e6d07770 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 18 Jul 2022 15:00:51 +0200 Subject: [PATCH 5/8] Do not always start MainActivity first when launching HomeActivity --- .../im/vector/app/features/MainActivity.kt | 2 +- .../vector/app/features/home/HomeActivity.kt | 7 ++++++- .../app/features/login/LoginActivity.kt | 2 +- .../notifications/NotificationUtils.kt | 20 +++++++++++-------- .../app/features/onboarding/Login2Variant.kt | 3 ++- .../onboarding/ftueauth/FtueAuthVariant.kt | 6 +++++- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 805a52958a..968d3670a9 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -300,7 +300,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity // We have a session. // Check it can be opened if (sessionHolder.getActiveSession().isOpenable) { - HomeActivity.newIntent(this, existingSession = true) + HomeActivity.newIntent(this, firstStartMainActivity = false, existingSession = true) } else { // The token is still invalid navigator.softLogout(this) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 0eb136fc10..ff114e4db9 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -611,6 +611,7 @@ class HomeActivity : companion object { fun newIntent( context: Context, + firstStartMainActivity: Boolean, clearNotification: Boolean = false, authenticationDescription: AuthenticationDescription? = null, existingSession: Boolean = false, @@ -628,7 +629,11 @@ class HomeActivity : putExtra(Mavericks.KEY_ARG, args) } - return MainActivity.getIntentWithNextIntent(context, intent) + return if (firstStartMainActivity) { + MainActivity.getIntentWithNextIntent(context, intent) + } else { + intent + } } } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt index 4cbebd67a3..763d1eed38 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt @@ -221,7 +221,7 @@ open class LoginActivity : VectorBaseActivity(), UnlockedA analyticsScreenName = MobileScreen.ScreenName.Register } val authDescription = inferAuthDescription(loginViewState) - val intent = HomeActivity.newIntent(this, authenticationDescription = authDescription) + val intent = HomeActivity.newIntent(this, firstStartMainActivity = false, authenticationDescription = authDescription) startActivity(intent) finish() return diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 0066fab5ce..514952b66c 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -240,7 +240,7 @@ class NotificationUtils @Inject constructor( @SuppressLint("NewApi") fun buildForegroundServiceNotification(@StringRes subTitleResId: Int, withProgress: Boolean = true): Notification { // build the pending intent go to the home screen if this is clicked. - val i = HomeActivity.newIntent(context) + val i = HomeActivity.newIntent(context, firstStartMainActivity = false) i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP val mainIntent = MainActivity.getIntentWithNextIntent(context, i) val pi = PendingIntent.getActivity(context, 0, mainIntent, PendingIntentCompat.FLAG_IMMUTABLE) @@ -346,7 +346,7 @@ class NotificationUtils @Inject constructor( ) val answerCallPendingIntent = TaskStackBuilder.create(context) - .addNextIntentWithParentStack(HomeActivity.newIntent(context)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context, firstStartMainActivity = false)) .addNextIntent( VectorCallActivity.newIntent( context = context, @@ -470,7 +470,7 @@ class NotificationUtils @Inject constructor( ) val contentPendingIntent = TaskStackBuilder.create(context) - .addNextIntentWithParentStack(HomeActivity.newIntent(context)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context, firstStartMainActivity = false)) .addNextIntent(VectorCallActivity.newIntent(context, call, null)) .getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) @@ -532,7 +532,7 @@ class NotificationUtils @Inject constructor( .setCategory(NotificationCompat.CATEGORY_CALL) val contentPendingIntent = TaskStackBuilder.create(context) - .addNextIntentWithParentStack(HomeActivity.newIntent(context)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context, firstStartMainActivity = false)) .addNextIntent(RoomDetailActivity.newIntent(context, TimelineArgs(callInformation.nativeRoomId), true)) .getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) @@ -767,7 +767,11 @@ class NotificationUtils @Inject constructor( joinIntentPendingIntent ) - val contentIntent = HomeActivity.newIntent(context, inviteNotificationRoomId = inviteNotifiableEvent.roomId) + val contentIntent = HomeActivity.newIntent( + context, + firstStartMainActivity = true, + inviteNotificationRoomId = inviteNotifiableEvent.roomId + ) contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that contentIntent.data = createIgnoredUri(inviteNotifiableEvent.eventId) @@ -808,7 +812,7 @@ class NotificationUtils @Inject constructor( .setColor(accentColor) .setAutoCancel(true) .apply { - val contentIntent = HomeActivity.newIntent(context) + val contentIntent = HomeActivity.newIntent(context, firstStartMainActivity = true) contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that contentIntent.data = createIgnoredUri(simpleNotifiableEvent.eventId) @@ -837,7 +841,7 @@ class NotificationUtils @Inject constructor( // Recreate the back stack return TaskStackBuilder.create(context) - .addNextIntentWithParentStack(HomeActivity.newIntent(context)) + .addNextIntentWithParentStack(HomeActivity.newIntent(context, firstStartMainActivity = false)) .addNextIntent(roomIntentTap) .getPendingIntent( clock.epochMillis().toInt(), @@ -846,7 +850,7 @@ class NotificationUtils @Inject constructor( } private fun buildOpenHomePendingIntentForSummary(): PendingIntent { - val intent = HomeActivity.newIntent(context, clearNotification = true) + val intent = HomeActivity.newIntent(context, firstStartMainActivity = false, clearNotification = true) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.data = createIgnoredUri("tapSummary") val mainIntent = MainActivity.getIntentWithNextIntent(context, intent) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/Login2Variant.kt b/vector/src/main/java/im/vector/app/features/onboarding/Login2Variant.kt index 0d7c83e360..7def6d62f0 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/Login2Variant.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/Login2Variant.kt @@ -302,7 +302,8 @@ class Login2Variant( private fun terminate() { val intent = HomeActivity.newIntent( - activity + activity, + firstStartMainActivity = false, ) activity.startActivity(intent) activity.finish() diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt index bb8c523b5f..867ab45834 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt @@ -482,7 +482,11 @@ class FtueAuthVariant( private fun navigateToHome() { withState(onboardingViewModel) { - val intent = HomeActivity.newIntent(activity, authenticationDescription = it.selectedAuthenticationState.description) + val intent = HomeActivity.newIntent( + activity, + firstStartMainActivity = false, + authenticationDescription = it.selectedAuthenticationState.description + ) activity.startActivity(intent) activity.finish() } From 9dda647c52edb618a17fdc4a9ca000a4505ea5e0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 19 Jul 2022 16:46:04 +0200 Subject: [PATCH 6/8] Add Foreground service when data are updated. --- vector/src/main/AndroidManifest.xml | 5 ++ .../im/vector/app/features/MainActivity.kt | 7 +++ .../notifications/NotificationUtils.kt | 13 ++++ .../features/start/StartAppAndroidService.kt | 63 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/start/StartAppAndroidService.kt diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 1c104f3bbf..b7bdac6879 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -380,6 +380,11 @@ android:exported="false" android:foregroundServiceType="location" /> + + (), UnlockedActivity views.status.setText(R.string.updating_your_data) } views.status.isVisible = state.duration > 0 + if (state.duration == 1L && startAppViewModel.shouldStartApp()) { + // Start foreground service, because the operation may take a while + val intent = Intent(this, StartAppAndroidService::class.java) + ContextCompat.startForegroundService(this, intent) + } } private fun handleViewEvents(event: StartAppViewEvent) { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 514952b66c..2948565d58 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -568,6 +568,19 @@ class NotificationUtils @Inject constructor( .build() } + /** + * Creates a notification that indicates the application is initializing. + */ + fun buildStartAppNotification(): Notification { + return NotificationCompat.Builder(context, LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID) + .setContentTitle(stringProvider.getString(R.string.updating_your_data)) + .setSmallIcon(R.drawable.sync) + .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) + .setCategory(NotificationCompat.CATEGORY_SERVICE) + .setPriority(NotificationCompat.PRIORITY_LOW) + .build() + } + fun buildDownloadFileNotification(uri: Uri, fileName: String, mimeType: String): Notification { return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) .setGroup(stringProvider.getString(R.string.app_name)) diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppAndroidService.kt b/vector/src/main/java/im/vector/app/features/start/StartAppAndroidService.kt new file mode 100644 index 0000000000..e8e0eac863 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/start/StartAppAndroidService.kt @@ -0,0 +1,63 @@ +/* + * 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.features.start + +import android.content.Intent +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.di.NamedGlobalScope +import im.vector.app.core.services.VectorAndroidService +import im.vector.app.features.notifications.NotificationUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import javax.inject.Inject +import kotlin.random.Random +import kotlin.time.Duration.Companion.seconds + +/** + * A simple foreground service that let the app (and the SDK) time to initialize. + * Will self stop itself once the active session is set. + */ +@AndroidEntryPoint +class StartAppAndroidService : VectorAndroidService() { + + @NamedGlobalScope @Inject lateinit var globalScope: CoroutineScope + @Inject lateinit var notificationUtils: NotificationUtils + @Inject lateinit var activeSessionHolder: ActiveSessionHolder + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + showStickyNotification() + startPollingActiveSession() + return START_STICKY + } + + private fun startPollingActiveSession() { + globalScope.launch { + do { + delay(1.seconds.inWholeMilliseconds) + } while (activeSessionHolder.hasActiveSession().not()) + myStopSelf() + } + } + + private fun showStickyNotification() { + val notificationId = Random.nextInt() + val notification = notificationUtils.buildStartAppNotification() + startForeground(notificationId, notification) + } +} From 3063c0da496499ad93cd0b4bbbbe0e2d66723e5c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 20 Jul 2022 09:36:30 +0200 Subject: [PATCH 7/8] Avoid updating the UI every seconds --- .../im/vector/app/features/MainActivity.kt | 18 +++++++++++------- .../app/features/start/StartAppViewEvent.kt | 8 ++++++++ .../app/features/start/StartAppViewModel.kt | 19 ++++++++----------- .../app/features/start/StartAppViewState.kt | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 041ee44c1c..61127e2c82 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -142,23 +142,27 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } private fun renderState(state: StartAppViewState) { - if (state.duration > 0) { + if (state.mayBeLongToProcess) { views.status.setText(R.string.updating_your_data) } - views.status.isVisible = state.duration > 0 - if (state.duration == 1L && startAppViewModel.shouldStartApp()) { - // Start foreground service, because the operation may take a while - val intent = Intent(this, StartAppAndroidService::class.java) - ContextCompat.startForegroundService(this, intent) - } + views.status.isVisible = state.mayBeLongToProcess } private fun handleViewEvents(event: StartAppViewEvent) { when (event) { + StartAppViewEvent.StartForegroundService -> handleStartForegroundService() StartAppViewEvent.AppStarted -> handleAppStarted() } } + private fun handleStartForegroundService() { + if (startAppViewModel.shouldStartApp()) { + // Start foreground service, because the operation may take a while + val intent = Intent(this, StartAppAndroidService::class.java) + ContextCompat.startForegroundService(this, intent) + } + } + private fun handleAppStarted() { if (intent.hasExtra(EXTRA_NEXT_INTENT)) { // Start the next Activity diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt index 9e185cbe04..986d41f983 100644 --- a/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewEvent.kt @@ -19,5 +19,13 @@ package im.vector.app.features.start import im.vector.app.core.platform.VectorViewEvents sealed interface StartAppViewEvent : VectorViewEvents { + /** + * Will be sent if the process is taking more than 1 second. + */ + object StartForegroundService : StartAppViewEvent + + /** + * Will be sent when the current Session has been set. + */ object AppStarted : StartAppViewEvent } diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt index b66a072195..62a7517f5a 100644 --- a/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewModel.kt @@ -24,10 +24,8 @@ import im.vector.app.core.di.ActiveSessionSetter import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel -import im.vector.lib.core.utils.flow.tickerFlow import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.time.Duration.Companion.seconds @@ -54,7 +52,7 @@ class StartAppViewModel @AssistedInject constructor( } private fun handleStartApp() { - startTimer() + handleLongProcessing() viewModelScope.launch(Dispatchers.IO) { // This can take time because of DB migration(s), so do it in a background task. activeSessionSetter.tryToSetActiveSession(startSync = true) @@ -62,12 +60,11 @@ class StartAppViewModel @AssistedInject constructor( } } - private fun startTimer() { - setState { copy(duration = 0) } - tickerFlow(viewModelScope, 1.seconds.inWholeMilliseconds) - .onEach { - setState { copy(duration = duration + 1) } - } - .launchIn(viewModelScope) + private fun handleLongProcessing() { + viewModelScope.launch(Dispatchers.Default) { + delay(1.seconds.inWholeMilliseconds) + setState { copy(mayBeLongToProcess = true) } + _viewEvents.post(StartAppViewEvent.StartForegroundService) + } } } diff --git a/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt b/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt index 50418e90dc..3ff933f054 100644 --- a/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt +++ b/vector/src/main/java/im/vector/app/features/start/StartAppViewState.kt @@ -19,5 +19,5 @@ package im.vector.app.features.start import com.airbnb.mvrx.MavericksState data class StartAppViewState( - val duration: Long = 0 + val mayBeLongToProcess: Boolean = false ) : MavericksState From b83f6f2cb7a532c49190448fd811d783bff0ebe9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 21 Jul 2022 10:30:18 +0200 Subject: [PATCH 8/8] Changelog --- changelog.d/6548.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6548.feature diff --git a/changelog.d/6548.feature b/changelog.d/6548.feature new file mode 100644 index 0000000000..8c40a37063 --- /dev/null +++ b/changelog.d/6548.feature @@ -0,0 +1 @@ +Move initialization of the Session to a background thread. MainActivity is restoring the session now, instead of VectorApplication. Useful when for instance a long migration of a database is required.