Skip to content

Commit fabdc20

Browse files
authored
Merge pull request #6548 from vector-im/feature/bma/realm_migration_bg
Realm migration bg
2 parents fb05ab3 + b83f6f2 commit fabdc20

28 files changed

+511
-76
lines changed

changelog.d/6548.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

vector/src/main/AndroidManifest.xml

+5
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@
380380
android:exported="false"
381381
android:foregroundServiceType="location" />
382382

383+
<service
384+
android:name=".features.start.StartAppAndroidService"
385+
android:exported="false"
386+
android:foregroundServiceType="dataSync" />
387+
383388
<service
384389
android:name=".features.call.webrtc.ScreenCaptureAndroidService"
385390
android:exported="false"

vector/src/main/java/im/vector/app/VectorApplication.kt

-18
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ import com.vanniktech.emoji.EmojiManager
4141
import com.vanniktech.emoji.google.GoogleEmojiProvider
4242
import dagger.hilt.android.HiltAndroidApp
4343
import im.vector.app.core.di.ActiveSessionHolder
44-
import im.vector.app.core.extensions.configureAndStart
45-
import im.vector.app.core.extensions.startSyncing
4644
import im.vector.app.features.analytics.VectorAnalytics
4745
import im.vector.app.features.call.webrtc.WebRtcCallManager
4846
import im.vector.app.features.configuration.VectorConfiguration
@@ -165,14 +163,6 @@ class VectorApplication :
165163
doNotShowDisclaimerDialog(this)
166164
}
167165

168-
if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
169-
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
170-
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
171-
lastAuthenticatedSession.configureAndStart(applicationContext, startSyncing = false)
172-
}
173-
174-
ProcessLifecycleOwner.get().lifecycle.addObserver(startSyncOnFirstStart)
175-
176166
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
177167
override fun onResume(owner: LifecycleOwner) {
178168
Timber.i("App entered foreground")
@@ -205,14 +195,6 @@ class VectorApplication :
205195
Mapbox.getInstance(this)
206196
}
207197

208-
private val startSyncOnFirstStart = object : DefaultLifecycleObserver {
209-
override fun onStart(owner: LifecycleOwner) {
210-
Timber.i("App process started")
211-
authenticationService.getLastAuthenticatedSession()?.startSyncing(appContext)
212-
ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
213-
}
214-
}
215-
216198
private fun enableStrictModeIfNeeded() {
217199
if (BuildConfig.ENABLE_STRICT_MODE_LOGS) {
218200
StrictMode.setThreadPolicy(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2022 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.core.di
18+
19+
import android.content.Context
20+
import im.vector.app.core.extensions.configureAndStart
21+
import org.matrix.android.sdk.api.auth.AuthenticationService
22+
import javax.inject.Inject
23+
24+
class ActiveSessionSetter @Inject constructor(
25+
private val activeSessionHolder: ActiveSessionHolder,
26+
private val authenticationService: AuthenticationService,
27+
private val applicationContext: Context,
28+
) {
29+
fun shouldSetActionSession(): Boolean {
30+
return authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()
31+
}
32+
33+
fun tryToSetActiveSession(startSync: Boolean) {
34+
if (shouldSetActionSession()) {
35+
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
36+
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
37+
lastAuthenticatedSession.configureAndStart(applicationContext, startSyncing = startSync)
38+
}
39+
}
40+
}

vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt

+6
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ import im.vector.app.features.spaces.manage.SpaceManageSharedViewModel
111111
import im.vector.app.features.spaces.people.SpacePeopleViewModel
112112
import im.vector.app.features.spaces.preview.SpacePreviewViewModel
113113
import im.vector.app.features.spaces.share.ShareSpaceViewModel
114+
import im.vector.app.features.start.StartAppViewModel
114115
import im.vector.app.features.terms.ReviewTermsViewModel
115116
import im.vector.app.features.usercode.UserCodeSharedViewModel
116117
import im.vector.app.features.userdirectory.UserListViewModel
@@ -483,6 +484,11 @@ interface MavericksViewModelModule {
483484
@MavericksViewModelKey(AnalyticsAccountDataViewModel::class)
484485
fun analyticsAccountDataViewModelFactory(factory: AnalyticsAccountDataViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
485486

487+
@Binds
488+
@IntoMap
489+
@MavericksViewModelKey(StartAppViewModel::class)
490+
fun startAppViewModelFactory(factory: StartAppViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
491+
486492
@Binds
487493
@IntoMap
488494
@MavericksViewModelKey(HomeServerCapabilitiesViewModel::class)

vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
2727
import dagger.hilt.android.AndroidEntryPoint
2828
import im.vector.app.BuildConfig
2929
import im.vector.app.core.di.ActiveSessionHolder
30+
import im.vector.app.core.di.ActiveSessionSetter
3031
import im.vector.app.core.network.WifiDetector
3132
import im.vector.app.core.pushers.model.PushData
3233
import im.vector.app.core.services.GuardServiceStarter
@@ -59,6 +60,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
5960
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
6061
@Inject lateinit var notifiableEventResolver: NotifiableEventResolver
6162
@Inject lateinit var pushersManager: PushersManager
63+
@Inject lateinit var activeSessionSetter: ActiveSessionSetter
6264
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
6365
@Inject lateinit var vectorPreferences: VectorPreferences
6466
@Inject lateinit var vectorDataStore: VectorDataStore
@@ -177,6 +179,11 @@ class VectorMessagingReceiver : MessagingReceiver() {
177179
}
178180

179181
val session = activeSessionHolder.getSafeActiveSession()
182+
?: run {
183+
// Active session may not exist yet, if MainActivity has not been launched
184+
activeSessionSetter.tryToSetActiveSession(startSync = false)
185+
activeSessionHolder.getSafeActiveSession()
186+
}
180187

181188
if (session == null) {
182189
Timber.tag(loggerTag.value).w("## Can't sync from push, no current session")

vector/src/main/java/im/vector/app/features/MainActivity.kt

+82-8
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
package im.vector.app.features
1818

1919
import android.app.Activity
20+
import android.content.Context
2021
import android.content.Intent
2122
import android.os.Bundle
2223
import android.os.Parcelable
24+
import androidx.core.content.ContextCompat
25+
import androidx.core.view.isVisible
2326
import androidx.lifecycle.Lifecycle
2427
import androidx.lifecycle.lifecycleScope
28+
import com.airbnb.mvrx.viewModel
2529
import com.bumptech.glide.Glide
2630
import com.google.android.material.dialog.MaterialAlertDialogBuilder
2731
import dagger.hilt.android.AndroidEntryPoint
@@ -44,9 +48,16 @@ import im.vector.app.features.popup.PopupAlertManager
4448
import im.vector.app.features.session.VectorSessionStore
4549
import im.vector.app.features.settings.VectorPreferences
4650
import im.vector.app.features.signout.hard.SignedOutActivity
51+
import im.vector.app.features.start.StartAppAction
52+
import im.vector.app.features.start.StartAppAndroidService
53+
import im.vector.app.features.start.StartAppViewEvent
54+
import im.vector.app.features.start.StartAppViewModel
55+
import im.vector.app.features.start.StartAppViewState
4756
import im.vector.app.features.themes.ActivityOtherThemes
4857
import im.vector.app.features.ui.UiStateRepository
4958
import kotlinx.coroutines.Dispatchers
59+
import kotlinx.coroutines.flow.launchIn
60+
import kotlinx.coroutines.flow.onEach
5061
import kotlinx.coroutines.launch
5162
import kotlinx.coroutines.withContext
5263
import kotlinx.parcelize.Parcelize
@@ -73,6 +84,8 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
7384

7485
companion object {
7586
private const val EXTRA_ARGS = "EXTRA_ARGS"
87+
private const val EXTRA_NEXT_INTENT = "EXTRA_NEXT_INTENT"
88+
private const val EXTRA_INIT_SESSION = "EXTRA_INIT_SESSION"
7689

7790
// Special action to clear cache and/or clear credentials
7891
fun restartApp(activity: Activity, args: MainActivityArgs) {
@@ -82,8 +95,22 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
8295
intent.putExtra(EXTRA_ARGS, args)
8396
activity.startActivity(intent)
8497
}
98+
99+
fun getIntentToInitSession(activity: Activity): Intent {
100+
val intent = Intent(activity, MainActivity::class.java)
101+
intent.putExtra(EXTRA_INIT_SESSION, true)
102+
return intent
103+
}
104+
105+
fun getIntentWithNextIntent(context: Context, nextIntent: Intent): Intent {
106+
val intent = Intent(context, MainActivity::class.java)
107+
intent.putExtra(EXTRA_NEXT_INTENT, nextIntent)
108+
return intent
109+
}
85110
}
86111

112+
private val startAppViewModel: StartAppViewModel by viewModel()
113+
87114
override fun getBinding() = ActivityMainBinding.inflate(layoutInflater)
88115

89116
override fun getOtherThemes() = ActivityOtherThemes.Launcher
@@ -103,15 +130,58 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
103130

104131
override fun onCreate(savedInstanceState: Bundle?) {
105132
super.onCreate(savedInstanceState)
106-
args = parseArgs()
107-
if (args.clearCredentials || args.isUserLoggedOut || args.clearCache) {
108-
clearNotifications()
133+
134+
startAppViewModel.onEach {
135+
renderState(it)
136+
}
137+
startAppViewModel.viewEvents.stream()
138+
.onEach(::handleViewEvents)
139+
.launchIn(lifecycleScope)
140+
141+
startAppViewModel.handle(StartAppAction.StartApp)
142+
}
143+
144+
private fun renderState(state: StartAppViewState) {
145+
if (state.mayBeLongToProcess) {
146+
views.status.setText(R.string.updating_your_data)
147+
}
148+
views.status.isVisible = state.mayBeLongToProcess
149+
}
150+
151+
private fun handleViewEvents(event: StartAppViewEvent) {
152+
when (event) {
153+
StartAppViewEvent.StartForegroundService -> handleStartForegroundService()
154+
StartAppViewEvent.AppStarted -> handleAppStarted()
155+
}
156+
}
157+
158+
private fun handleStartForegroundService() {
159+
if (startAppViewModel.shouldStartApp()) {
160+
// Start foreground service, because the operation may take a while
161+
val intent = Intent(this, StartAppAndroidService::class.java)
162+
ContextCompat.startForegroundService(this, intent)
109163
}
110-
// Handle some wanted cleanup
111-
if (args.clearCache || args.clearCredentials) {
112-
doCleanUp()
164+
}
165+
166+
private fun handleAppStarted() {
167+
if (intent.hasExtra(EXTRA_NEXT_INTENT)) {
168+
// Start the next Activity
169+
val nextIntent = intent.getParcelableExtra<Intent>(EXTRA_NEXT_INTENT)
170+
startIntentAndFinish(nextIntent)
171+
} else if (intent.hasExtra(EXTRA_INIT_SESSION)) {
172+
setResult(RESULT_OK)
173+
finish()
113174
} else {
114-
startNextActivityAndFinish()
175+
args = parseArgs()
176+
if (args.clearCredentials || args.isUserLoggedOut || args.clearCache) {
177+
clearNotifications()
178+
}
179+
// Handle some wanted cleanup
180+
if (args.clearCache || args.clearCredentials) {
181+
doCleanUp()
182+
} else {
183+
startNextActivityAndFinish()
184+
}
115185
}
116186
}
117187

@@ -241,7 +311,7 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
241311
// We have a session.
242312
// Check it can be opened
243313
if (sessionHolder.getActiveSession().isOpenable) {
244-
HomeActivity.newIntent(this, existingSession = true)
314+
HomeActivity.newIntent(this, firstStartMainActivity = false, existingSession = true)
245315
} else {
246316
// The token is still invalid
247317
navigator.softLogout(this)
@@ -253,6 +323,10 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
253323
null
254324
}
255325
}
326+
startIntentAndFinish(intent)
327+
}
328+
329+
private fun startIntentAndFinish(intent: Intent?) {
256330
intent?.let { startActivity(it) }
257331
finish()
258332
}

vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ class VectorCallActivity :
604604
private fun returnToChat() {
605605
val roomId = withState(callViewModel) { it.roomId }
606606
val args = TimelineArgs(roomId)
607-
val intent = RoomDetailActivity.newIntent(this, args).apply {
607+
val intent = RoomDetailActivity.newIntent(this, args, false).apply {
608608
flags = FLAG_ACTIVITY_CLEAR_TOP
609609
}
610610
startActivity(intent)

vector/src/main/java/im/vector/app/features/home/HomeActivity.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ class HomeActivity :
611611
companion object {
612612
fun newIntent(
613613
context: Context,
614+
firstStartMainActivity: Boolean,
614615
clearNotification: Boolean = false,
615616
authenticationDescription: AuthenticationDescription? = null,
616617
existingSession: Boolean = false,
@@ -623,10 +624,16 @@ class HomeActivity :
623624
inviteNotificationRoomId = inviteNotificationRoomId
624625
)
625626

626-
return Intent(context, HomeActivity::class.java)
627+
val intent = Intent(context, HomeActivity::class.java)
627628
.apply {
628629
putExtra(Mavericks.KEY_ARG, args)
629630
}
631+
632+
return if (firstStartMainActivity) {
633+
MainActivity.getIntentWithNextIntent(context, intent)
634+
} else {
635+
intent
636+
}
630637
}
631638
}
632639

vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import im.vector.app.core.extensions.keepScreenOn
3535
import im.vector.app.core.extensions.replaceFragment
3636
import im.vector.app.core.platform.VectorBaseActivity
3737
import im.vector.app.databinding.ActivityRoomDetailBinding
38+
import im.vector.app.features.MainActivity
3839
import im.vector.app.features.analytics.plan.MobileScreen
3940
import im.vector.app.features.analytics.plan.ViewRoom
4041
import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
@@ -191,10 +192,15 @@ class RoomDetailActivity :
191192
const val EXTRA_ROOM_ID = "EXTRA_ROOM_ID"
192193
const val ACTION_ROOM_DETAILS_FROM_SHORTCUT = "ROOM_DETAILS_FROM_SHORTCUT"
193194

194-
fun newIntent(context: Context, timelineArgs: TimelineArgs): Intent {
195-
return Intent(context, RoomDetailActivity::class.java).apply {
195+
fun newIntent(context: Context, timelineArgs: TimelineArgs, firstStartMainActivity: Boolean): Intent {
196+
val intent = Intent(context, RoomDetailActivity::class.java).apply {
196197
putExtra(EXTRA_ROOM_DETAIL_ARGS, timelineArgs)
197198
}
199+
return if (firstStartMainActivity) {
200+
MainActivity.getIntentWithNextIntent(context, intent)
201+
} else {
202+
intent
203+
}
198204
}
199205

200206
// Shortcuts can't have intents with parcelables

vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1206,9 +1206,9 @@ class TimelineFragment @Inject constructor(
12061206
getRootThreadEventId()?.let {
12071207
val newRoom = timelineArgs.copy(threadTimelineArgs = null, eventId = it)
12081208
context?.let { con ->
1209-
val int = RoomDetailActivity.newIntent(con, newRoom)
1210-
int.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
1211-
con.startActivity(int)
1209+
val intent = RoomDetailActivity.newIntent(con, newRoom, false)
1210+
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
1211+
con.startActivity(intent)
12121212
}
12131213
}
12141214
}

0 commit comments

Comments
 (0)