Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b0ce658
MS-402 Prevent a navigation race condition on logout
luhmirin-s Apr 11, 2024
3228817
Merge pull request #668 from Simprints/bugfix/MS-402-logout-crash
luhmirin-s Apr 15, 2024
19763f1
[MS-409] fix LICENSE_MISSING mapping
meladRaouf Apr 15, 2024
5630565
Merge pull request #676 from Simprints/MS-409-Map-LICENSE_MISSING-ale…
meladRaouf Apr 15, 2024
e08618a
[MS-412] Untie camera initialization from fragment initialization
BurningAXE Apr 15, 2024
27b3374
[MS-413] sign out after stopping the background sync
meladRaouf Apr 16, 2024
d446880
[MS-405] Saving the Action Request in the bundle so it can survive th…
alexandr-simprints Apr 16, 2024
721577a
Merge pull request #680 from Simprints/MS-405-simprints-unexpected-er…
alexandr-simprints Apr 16, 2024
0b9e480
Merge pull request #678 from Simprints/MS-412-Minimizing-SID-during-f…
BurningAXE Apr 16, 2024
467a689
[MS-416] Move Bluetooth permissions check in onResume() to reflect ch…
BurningAXE Apr 16, 2024
fc58d27
[MS-413] Force callers to logout to wait for the logout operation to …
meladRaouf Apr 16, 2024
3013f01
[MS-417] Mark DeviceConfigDownSyncWorker as HiltWorker
meladRaouf Apr 16, 2024
2eb59e3
Merge pull request #682 from Simprints/MS-417-DeviceConfigDownSyncWor…
meladRaouf Apr 17, 2024
f690ed5
Merge pull request #681 from Simprints/MS-416-SID-remains-indefinitel…
BurningAXE Apr 17, 2024
fe18c20
Merge remote-tracking branch 'origin/release/2024.1.0' into MS-413-lo…
meladRaouf Apr 17, 2024
71974c8
[MS-413] Use runBlocking to simplify the code
meladRaouf Apr 17, 2024
9ec2b96
[MS-413] [skip ci] reformat
meladRaouf Apr 17, 2024
8a3c170
[MS-413] Fix tests
meladRaouf Apr 17, 2024
659c177
Merge pull request #679 from Simprints/MS-413-logout-race-condition
meladRaouf Apr 17, 2024
8ae336f
[MS-418] Don't include projectConfigurationUpdatedAt if it's empty
BurningAXE Apr 17, 2024
186c072
[MS-425] Add attendantId and moduleId to tokenizedFields if they are …
BurningAXE Apr 18, 2024
51d9a3f
MS-427 Add request ID to response headers locally
luhmirin-s Apr 22, 2024
987e4ff
Merge pull request #691 from Simprints/bugfix/MS-427-add-request-id-l…
luhmirin-s Apr 22, 2024
b764cff
Merge pull request #685 from Simprints/MS-425-tokenizedFields-paramet…
BurningAXE Apr 22, 2024
440e844
Merge pull request #683 from Simprints/MS-418-projectConfigurationUpd…
BurningAXE Apr 22, 2024
622e1e8
Translate strings.xml in bn
transifex-integration[bot] Apr 12, 2024
57c0c17
[MS-405] Adding serialization modules when marshaling/unmarshalling a…
alexandr-simprints Apr 23, 2024
c8f1c80
Updates for project Simprints ID (#692)
transifex-integration[bot] Apr 23, 2024
86370ca
Merge pull request #694 from Simprints/MS-405-add-serialization-modules
alexandr-simprints Apr 23, 2024
cc3015a
[MS-428] order the signout steps to avoid cleanCredentials before del…
meladRaouf Apr 23, 2024
7722b61
MS-422 Immediate foreground service type for preventing ForegroundSer…
alex-vt Apr 23, 2024
35abfd6
Merge pull request #696 from Simprints/MS-428-cleanCredentials-order
meladRaouf Apr 23, 2024
36c1ff5
Merge pull request #697 from Simprints/bugfix/MS-422-foreground-too-s…
alex-vt Apr 23, 2024
a19e52f
[MS-425] Return JSON path for attendantId and moduleId tokenizedFields
BurningAXE Apr 23, 2024
c75add2
Merge pull request #675 from Simprints/translations/reapplying-to-rel…
luhmirin-s Apr 24, 2024
53b16ca
Merge pull request #698 from Simprints/MS-425-tokenizedFields-paramet…
BurningAXE Apr 24, 2024
87ee602
MS-368 Opting out of setting worker service foreground when battery o…
alex-vt Apr 24, 2024
8ab5915
MS-368 Foreground status for workers to be set as early as possible
alex-vt Apr 24, 2024
3843763
MS-368 Battery optimization check potential exceptions catching
alex-vt Apr 24, 2024
9edf2cb
MS-368 Battery optimization check platform code excluded from test co…
alex-vt Apr 24, 2024
e8b6e0c
Merge pull request #700 from Simprints/bugfix/MS-368-foreground-crash
alex-vt Apr 24, 2024
a13204c
MS-439 Move requestID logic from network interceptors to sync tasks
luhmirin-s May 7, 2024
af0bfc9
Merge pull request #707 from Simprints/bugfix/MS-439-request-id-for-e…
luhmirin-s May 7, 2024
b67f0a7
[MS-437] Make Path (also) Serializable so it can be properly serializ…
BurningAXE May 8, 2024
386da20
[MS-437] Add JSON subtype info for ActionRequest so it can be properl…
BurningAXE May 8, 2024
c0d196d
[MS-437] Ensure OrchestratorViewModel is properly restored when Activ…
BurningAXE May 8, 2024
961dd39
Merge pull request #709 from Simprints/MS-437-Gavi-Ghana-Well-Labeled…
BurningAXE May 8, 2024
9539f8d
[MS-437] Prevent saving of empty VM data when Fragment is destroyed a…
BurningAXE May 9, 2024
6decaf4
Merge pull request #710 from Simprints/MS-437-Gavi-Ghana-Well-Labeled…
BurningAXE May 9, 2024
18c38bb
Merge remote-tracking branch 'origin/main' into merge/main/2024.1.0
meladRaouf May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.simprints.infra.resources.R as IDR


/**
* This is the class presented as the user is capturing theface, they are presented with this fragment, which displays
* As the user is capturing subject's face, they are presented with this fragment, which displays
* live information about distance and whether the face is ready to be captured or not.
* It also displays the capture process of the face and then sends this result to
* [com.simprints.face.capture.screens.confirmation.ConfirmationFragment]
Expand Down Expand Up @@ -66,18 +66,14 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
IDR.string.face_capturing_permission_denied,
Toast.LENGTH_LONG
).show()
} else {
setUpCamera()
}
// init fragment anyway
initFragment()
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (requireActivity().hasPermission(Manifest.permission.CAMERA)) {
initFragment()
} else {
launchPermissionRequest.launch(Manifest.permission.CAMERA)
}
initFragment()
}

private fun initFragment() {
Expand All @@ -96,13 +92,15 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
binding.captureOverlay.rectInCanvas,
Size(binding.captureOverlay.width, binding.captureOverlay.height),
)
setUpCamera()
}
}
}

/** Initialize CameraX, and prepare to bind the camera use cases */
private fun setUpCamera() = lifecycleScope.launch {
if (::cameraExecutor.isInitialized) {
return@launch
}
// Initialize our background executor
cameraExecutor = Executors.newSingleThreadExecutor()
// ImageAnalysis
Expand All @@ -121,6 +119,18 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
preview.setSurfaceProvider(binding.faceCaptureCamera.surfaceProvider)
}

override fun onStart() {
super.onStart()

// Check permission in onStart() so that if user left the app to go to Settings
// and give the permission, it's reflected when they come back to SID
if (requireActivity().hasPermission(Manifest.permission.CAMERA)) {
setUpCamera()
} else {
launchPermissionRequest.launch(Manifest.permission.CAMERA)
}
}

override fun onStop() {
// Shut down our background executor
if(::cameraExecutor.isInitialized) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,17 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import com.simprints.core.ExternalScope
import com.simprints.core.livedata.LiveDataEventWithContent
import com.simprints.feature.dashboard.logout.usecase.LogoutUseCase
import com.simprints.infra.authlogic.AuthManager
import com.simprints.infra.config.store.ConfigRepository
import com.simprints.infra.config.store.models.SettingsPasswordConfig
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
internal class LogoutSyncViewModel @Inject constructor(
private val configRepository: ConfigRepository,
private val logoutUseCase: LogoutUseCase,
@ExternalScope private val externalScope: CoroutineScope,
) : ViewModel() {

val settingsLocked: LiveData<LiveDataEventWithContent<SettingsPasswordConfig>>
Expand All @@ -29,6 +24,7 @@ internal class LogoutSyncViewModel @Inject constructor(


fun logout() {
externalScope.launch { logoutUseCase() }
logoutUseCase()
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package com.simprints.feature.dashboard.logout.usecase

import com.simprints.infra.authlogic.AuthManager
import com.simprints.infra.sync.SyncOrchestrator
import kotlinx.coroutines.runBlocking
import javax.inject.Inject

internal class LogoutUseCase @Inject constructor(
private val syncOrchestrator: SyncOrchestrator,
private val authManager: AuthManager,
) {

suspend operator fun invoke() {
operator fun invoke() = runBlocking {
// Cancel all background sync
syncOrchestrator.cancelBackgroundWork()
syncOrchestrator.deleteEventSyncInfo()
// sign out the user
authManager.signOut()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.simprints.core.ExternalScope
import com.simprints.core.livedata.LiveDataEvent
import com.simprints.core.livedata.LiveDataEventWithContent
import com.simprints.core.livedata.send
Expand Down Expand Up @@ -56,9 +55,8 @@ internal class SyncViewModel @Inject constructor(
private val configRepository: ConfigRepository,
private val timeHelper: TimeHelper,
private val authStore: AuthStore,
private val logoutUseCase: LogoutUseCase,
private val logout: LogoutUseCase,
private val recentUserActivityManager: RecentUserActivityManager,
@ExternalScope private val externalScope: CoroutineScope,
) : ViewModel() {

companion object {
Expand Down Expand Up @@ -106,8 +104,8 @@ internal class SyncViewModel @Inject constructor(
configRepository.getProject(authStore.signedInProjectId).state == ProjectState.PROJECT_ENDING

if (isSyncComplete && isProjectEnding) {
externalScope.launch {
logoutUseCase()
viewModelScope.launch {
logout()
_signOutEventLiveData.postValue(LiveDataEvent())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.simprints.core.ExternalScope
import com.simprints.core.livedata.LiveDataEventWithContent
import com.simprints.core.livedata.send
import com.simprints.feature.dashboard.logout.usecase.LogoutUseCase
Expand All @@ -16,18 +15,16 @@ import com.simprints.infra.eventsync.EventSyncManager
import com.simprints.infra.recent.user.activity.RecentUserActivityManager
import com.simprints.infra.recent.user.activity.domain.RecentUserActivity
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
internal class AboutViewModel @Inject constructor(
private val configRepository: ConfigRepository,
private val logoutUseCase: LogoutUseCase,
private val logout: LogoutUseCase,
private val eventSyncManager: EventSyncManager,
private val recentUserActivityManager: RecentUserActivityManager,
@ExternalScope private val externalScope: CoroutineScope,
) : ViewModel() {

val syncAndSearchConfig: LiveData<SyncAndSearchConfig>
Expand Down Expand Up @@ -75,9 +72,6 @@ internal class AboutViewModel @Inject constructor(
private suspend fun canSyncDataToSimprints(): Boolean =
configRepository.getProjectConfiguration().canSyncDataToSimprints()

private fun logout() {
externalScope.launch { logoutUseCase() }
}

private fun load() = viewModelScope.launch {
val configuration = configRepository.getProjectConfiguration()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import kotlinx.coroutines.CoroutineScope
import org.junit.Before
import org.junit.Rule
import org.junit.Test
Expand Down Expand Up @@ -43,7 +42,6 @@ internal class LogoutSyncViewModelTest {
val viewModel = LogoutSyncViewModel(
configRepository = configRepository,
logoutUseCase = logoutUseCase,
externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher)
)

viewModel.logout()
Expand All @@ -62,7 +60,6 @@ internal class LogoutSyncViewModelTest {
val viewModel = LogoutSyncViewModel(
configRepository = configRepository,
logoutUseCase = logoutUseCase,
externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher),
)
val resultConfig = viewModel.settingsLocked.getOrAwaitValue()
assertThat(resultConfig.peekContent()).isEqualTo(config)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.simprints.feature.dashboard.logout.usecase

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.simprints.infra.authlogic.AuthManager
import com.simprints.infra.sync.SyncOrchestrator
import com.simprints.testtools.common.coroutines.TestCoroutineRule
import io.mockk.MockKAnnotations
import io.mockk.coVerify
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class LogoutUseCaseTest {

@get:Rule
val rule = InstantTaskExecutorRule()

@get:Rule
val testCoroutineRule = TestCoroutineRule()

@MockK
private lateinit var syncOrchestrator: SyncOrchestrator

@MockK
private lateinit var authManager: AuthManager

private lateinit var useCase: LogoutUseCase

@Before
fun setUp() {
MockKAnnotations.init(this, relaxed = true)

useCase = LogoutUseCase(
syncOrchestrator = syncOrchestrator,
authManager = authManager,
)
}

@Test
fun `Fully logs out when called`() = runTest {
useCase.invoke()

coVerify {
syncOrchestrator.cancelBackgroundWork()
syncOrchestrator.deleteEventSyncInfo()
authManager.signOut()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.flowOf
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -444,8 +443,7 @@ internal class SyncViewModelTest {
configRepository = configRepository,
timeHelper = timeHelper,
authStore = authStore,
logoutUseCase = logoutUseCase,
logout = logoutUseCase,
recentUserActivityManager = recentUserActivityManager,
externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Rule
Expand Down Expand Up @@ -66,8 +65,7 @@ class AboutViewModelTest {
configRepository = configRepository,
eventSyncManager = eventSyncManager,
recentUserActivityManager = recentUserActivityManager,
logoutUseCase = logoutUseCase,
externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher),
logout = logoutUseCase,
)

assertThat(viewModel.modalities.value).isEqualTo(MODALITIES)
Expand Down Expand Up @@ -186,8 +184,7 @@ class AboutViewModelTest {
configRepository = configRepository,
eventSyncManager = eventSyncManager,
recentUserActivityManager = recentUserActivityManager,
externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher),
logoutUseCase = logoutUseCase,
logout = logoutUseCase,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,20 @@ internal class OrchestratorFragment : Fragment(R.layout.fragment_orchestrator) {
private val clientApiVm by viewModels<ClientApiViewModel>()
private val orchestratorVm by viewModels<OrchestratorViewModel>()


override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
orchestratorVm.requestProcessed = savedInstanceState.getBoolean(KEY_REQUEST_PROCESSED)
savedInstanceState.getString(KEY_ACTION_REQUEST)
?.run(orchestratorVm::setActionRequestFromJson)
orchestratorVm.restoreStepsIfNeeded()
orchestratorVm.restoreModalitiesIfNeeded()
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

observeLoginCheckVm()
observeClientApiVm()
observeOrchestratorVm()
Expand Down Expand Up @@ -180,6 +188,10 @@ internal class OrchestratorFragment : Fragment(R.layout.fragment_orchestrator) {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(KEY_REQUEST_PROCESSED, orchestratorVm.requestProcessed)
// [MS-405] Saving the action request in the bundle, since ViewModels don't survive the
// process death. ActionRequest is important in mapping the correct SID response, hence it
// is important for it to be able to survive both configuration changes and process death.
outState.putString(KEY_ACTION_REQUEST, orchestratorVm.getActionRequestJson())
}

override fun onResume() {
Expand All @@ -201,5 +213,6 @@ internal class OrchestratorFragment : Fragment(R.layout.fragment_orchestrator) {

companion object {
private const val KEY_REQUEST_PROCESSED = "requestProcessed"
private const val KEY_ACTION_REQUEST = "actionRequest"
}
}
Loading