diff options
5 files changed, 66 insertions, 45 deletions
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index 2a7e9e16a10e..59e6142f3687 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -21,11 +21,14 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.android.credentialmanager.model.Request import com.android.credentialmanager.client.CredentialManagerClient +import com.android.credentialmanager.model.get.ActionEntryInfo +import com.android.credentialmanager.model.get.CredentialEntryInfo import com.android.credentialmanager.ui.mappers.toGet import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @@ -33,15 +36,15 @@ import javax.inject.Inject class CredentialSelectorViewModel @Inject constructor( private val credentialManagerClient: CredentialManagerClient, ) : ViewModel() { - + private val isPrimaryScreen = MutableStateFlow(false) val uiState: StateFlow<CredentialSelectorUiState> = credentialManagerClient.requests - .map { request -> + .combine(isPrimaryScreen) { request, isPrimary -> when (request) { null -> CredentialSelectorUiState.Idle is Request.Cancel -> CredentialSelectorUiState.Cancel(request.appName) is Request.Close -> CredentialSelectorUiState.Close is Request.Create -> CredentialSelectorUiState.Create - is Request.Get -> request.toGet() + is Request.Get -> request.toGet(isPrimary) } } .stateIn( @@ -57,9 +60,18 @@ class CredentialSelectorViewModel @Inject constructor( sealed class CredentialSelectorUiState { data object Idle : CredentialSelectorUiState() - sealed class Get : CredentialSelectorUiState() { - data object SingleProviderSinglePasskey : Get() - data object SingleProviderSinglePassword : Get() + sealed class Get() : CredentialSelectorUiState() { + data class SingleEntry(val entry: CredentialEntryInfo) : Get() + data class SingleEntryPerAccount(val sortedEntries: List<CredentialEntryInfo>) : Get() + data class MultipleEntry( + val accounts: List<PerUserNameEntries>, + val actionEntryList: List<ActionEntryInfo>, + ) : Get() { + data class PerUserNameEntries( + val userName: String, + val sortedCredentialEntryList: List<CredentialEntryInfo>, + ) + } // TODO: b/301206470 add the remaining states } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt index 7e0ea3077559..790f5b1f27f3 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt @@ -26,6 +26,7 @@ import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState import androidx.wear.compose.navigation.rememberSwipeDismissableNavController import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState import com.android.credentialmanager.CredentialSelectorUiState +import com.android.credentialmanager.CredentialSelectorUiState.Get.SingleEntry import com.android.credentialmanager.CredentialSelectorViewModel import com.android.credentialmanager.ui.screens.LoadingScreen import com.android.credentialmanager.ui.screens.single.password.SinglePasswordScreen @@ -57,6 +58,7 @@ fun WearApp( scrollable(Screen.SinglePasswordScreen.route) { SinglePasswordScreen( + state = viewModel.uiState.value as SingleEntry, columnState = it.columnState, onCloseApp = onCloseApp, ) @@ -100,7 +102,7 @@ private fun handleGetNavigation( onCloseApp: () -> Unit, ) { when (state) { - is CredentialSelectorUiState.Get.SingleProviderSinglePassword -> { + is SingleEntry -> { navController.navigateToSinglePasswordScreen() } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt index 14b992a0d0e9..44a838d51a04 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt @@ -18,18 +18,45 @@ package com.android.credentialmanager.ui.mappers import com.android.credentialmanager.model.Request import com.android.credentialmanager.CredentialSelectorUiState +import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry.PerUserNameEntries +import com.android.credentialmanager.model.CredentialType +import com.android.credentialmanager.model.get.CredentialEntryInfo -fun Request.Get.toGet(): CredentialSelectorUiState.Get { +fun Request.Get.toGet(isPrimary: Boolean): CredentialSelectorUiState.Get { // TODO: b/301206470 returning a hard coded state for MVP - if (true) return CredentialSelectorUiState.Get.SingleProviderSinglePassword - - return if (providerInfos.size == 1) { - if (providerInfos.first().credentialEntryList.size == 1) { - CredentialSelectorUiState.Get.SingleProviderSinglePassword + if (true) return CredentialSelectorUiState.Get.SingleEntry( + providerInfos + .flatMap { it.credentialEntryList } + .first { it.credentialType == CredentialType.PASSWORD } + ) + val accounts = providerInfos + .flatMap { it.credentialEntryList } + .groupBy { it.userName} + .entries + .toList() + return if (isPrimary) { + if (accounts.size == 1) { + CredentialSelectorUiState.Get.SingleEntry( + accounts[0].value.minWith(comparator) + ) } else { - TODO() // b/301206470 - Implement other get flows + CredentialSelectorUiState.Get.SingleEntryPerAccount( + accounts.map { it.value.minWith(comparator) }.sortedWith(comparator) + ) } } else { - TODO() // b/301206470 - Implement other get flows + CredentialSelectorUiState.Get.MultipleEntry( + accounts = accounts.map { PerUserNameEntries( + it.key, + it.value.sortedWith(comparator) + ) + }, + actionEntryList = providerInfos.flatMap { it.actionEntryList }, + ) } } +val comparator = compareBy<CredentialEntryInfo> { entryInfo -> + // Passkey type always go first + entryInfo.credentialType.let{ if (it == CredentialType.PASSKEY) 0 else 1 } +} + .thenByDescending{ it.lastUsedTimeMillis } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt index b64f58192d23..9f971ae1e327 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.credentialmanager.CredentialSelectorUiState.Get.SingleEntry import com.android.credentialmanager.R import com.android.credentialmanager.TAG import com.android.credentialmanager.activity.StartBalIntentSenderForResultContract @@ -44,12 +45,13 @@ import com.google.android.horologist.compose.tools.WearPreview @Composable fun SinglePasswordScreen( + state: SingleEntry, columnState: ScalingLazyColumnState, onCloseApp: () -> Unit, modifier: Modifier = Modifier, viewModel: SinglePasswordScreenViewModel = hiltViewModel(), ) { - viewModel.initialize() + viewModel.initialize(state.entry) val uiState by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt index 26bee1f8d191..4f9fc46e0fce 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt @@ -19,12 +19,9 @@ package com.android.credentialmanager.ui.screens.single.password import android.content.Intent import android.credentials.ui.ProviderPendingIntentResponse import android.credentials.ui.UserSelectionDialogResult -import android.util.Log import androidx.activity.result.IntentSenderRequest import androidx.annotation.MainThread import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.android.credentialmanager.TAG import com.android.credentialmanager.ktx.getIntentSenderRequest import com.android.credentialmanager.model.Request import com.android.credentialmanager.client.CredentialManagerClient @@ -33,7 +30,6 @@ import com.android.credentialmanager.ui.model.PasswordUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel @@ -51,32 +47,14 @@ class SinglePasswordScreenViewModel @Inject constructor( val uiState: StateFlow<SinglePasswordScreenUiState> = _uiState @MainThread - fun initialize() { + fun initialize(entryInfo: CredentialEntryInfo) { if (initializeCalled) return initializeCalled = true - - viewModelScope.launch { - val request = credentialManagerClient.requests.value - Log.d(TAG, "request: $request, client instance: $credentialManagerClient") - - if (request !is Request.Get) { - _uiState.value = SinglePasswordScreenUiState.Error - } else { - requestGet = request - - if (requestGet.providerInfos.all { it.credentialEntryList.isEmpty() }) { - Log.d(TAG, "Empty passwordEntries") - _uiState.value = SinglePasswordScreenUiState.Error - } else { - entryInfo = requestGet.providerInfos.first().credentialEntryList.first() - _uiState.value = SinglePasswordScreenUiState.Loaded( - PasswordUiModel( - email = entryInfo.userName, - ) - ) - } - } - } + _uiState.value = SinglePasswordScreenUiState.Loaded( + PasswordUiModel( + email = entryInfo.userName, + ) + ) } fun onCancelClick() { |