Loading packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +22 −17 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ class CredentialManagerRepo( requestInfo = intent.extras?.getParcelable( RequestInfo.EXTRA_REQUEST_INFO, RequestInfo::class.java ) ?: testGetRequestInfo() ) ?: testCreatePasskeyRequestInfo() providerEnabledList = when (requestInfo.type) { RequestInfo.TYPE_CREATE -> Loading Loading @@ -115,8 +115,10 @@ class CredentialManagerRepo( providerDisableListUiState, defaultProviderId, requestDisplayInfoUiState, /** isOnPasskeyIntroStateAlready = */ false, isPasskeyFirstUse)!!, /** isOnPasskeyIntroStateAlready = */ false, isPasskeyFirstUse )!!, getCredentialUiState = null, ) } Loading Loading @@ -224,12 +226,14 @@ class CredentialManagerRepo( .Builder("io.enpass.app") .setSaveEntries( listOf<Entry>( CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-1", "elisa.beckett@gmail.com", 20, 7, 27, Instant.ofEpochSecond(10L), "Legal note" ), CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-2", "elisa.work@google.com", 20, 7, 27, Instant.ofEpochSecond(12L), null Loading @@ -244,12 +248,14 @@ class CredentialManagerRepo( .Builder("com.dashlane") .setSaveEntries( listOf<Entry>( CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-3", "elisa.beckett@dashlane.com", 20, 7, 27, Instant.ofEpochSecond(11L), null ), CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-4", "elisa.work@dashlane.com", 20, 7, 27, Instant.ofEpochSecond(14L), null Loading Loading @@ -343,7 +349,6 @@ class CredentialManagerRepo( } private fun newRemoteEntry( key: String, subkey: String, Loading Loading @@ -427,7 +432,8 @@ class CredentialManagerRepo( val displayInfo = DisplayInfo("my-username00", "Joe") data.putBundle( "androidx.credentials.BUNDLE_KEY_REQUEST_DISPLAY_INFO", displayInfo.toBundle()) displayInfo.toBundle() ) return RequestInfo.newCreateRequestInfo( Binder(), CreateCredentialRequest( Loading @@ -445,8 +451,7 @@ class CredentialManagerRepo( Binder(), GetCredentialRequest.Builder( Bundle() ) .addCredentialOption( ).addCredentialOption( CredentialOption( "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL", Bundle(), Loading packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +5 −3 Original line number Diff line number Diff line Loading @@ -36,7 +36,9 @@ import com.android.credentialmanager.common.DialogState import com.android.credentialmanager.common.ProviderActivityResult import com.android.credentialmanager.common.StartBalIntentSenderForResultContract import com.android.credentialmanager.createflow.CreateCredentialScreen import com.android.credentialmanager.createflow.hasContentToDisplay import com.android.credentialmanager.getflow.GetCredentialScreen import com.android.credentialmanager.getflow.hasContentToDisplay import com.android.credentialmanager.ui.theme.CredentialSelectorTheme @ExperimentalMaterialApi Loading Loading @@ -94,13 +96,13 @@ class CredentialSelectorActivity : ComponentActivity() { val createCredentialUiState = viewModel.uiState.createCredentialUiState val getCredentialUiState = viewModel.uiState.getCredentialUiState if (createCredentialUiState != null) { if (createCredentialUiState != null && hasContentToDisplay(createCredentialUiState)) { CreateCredentialScreen( viewModel = viewModel, createCredentialUiState = createCredentialUiState, providerActivityLauncher = launcher ) } else if (getCredentialUiState != null) { } else if (getCredentialUiState != null && hasContentToDisplay(getCredentialUiState)) { GetCredentialScreen( viewModel = viewModel, getCredentialUiState = getCredentialUiState, Loading Loading @@ -130,7 +132,7 @@ class CredentialSelectorActivity : ComponentActivity() { } private fun onInitializationError(e: Exception, intent: Intent) { Log.e(Constants.LOG_TAG, "Failed to show the credential selector", e) Log.e(Constants.LOG_TAG, "Failed to show the credential selector; closing the activity", e) val resultReceiver = intent.getParcelableExtra( android.credentials.ui.Constants.EXTRA_RESULT_RECEIVER, ResultReceiver::class.java Loading packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +9 −2 Original line number Diff line number Diff line Loading @@ -473,8 +473,14 @@ class CreateFlowUtils { createOptionsPairs.add(Pair(it, enabledProvider)) } } if (enabledProvider.remoteEntry != null) { remoteEntry = enabledProvider.remoteEntry!! val currRemoteEntry = enabledProvider.remoteEntry if (currRemoteEntry != null) { if (remoteEntry != null) { // There can only be at most one remote entry Log.d(Constants.LOG_TAG, "Found more than one remote entry.") return null } remoteEntry = currRemoteEntry } } val initialScreenState = toCreateScreenState( Loading @@ -500,6 +506,7 @@ class CreateFlowUtils { lastSeenProviderWithNonEmptyCreateOptions, /*remoteEntry=*/remoteEntry ), remoteEntry = remoteEntry, ) } Loading packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +41 −37 Original line number Diff line number Diff line Loading @@ -59,7 +59,6 @@ import com.android.credentialmanager.common.ui.ContainerCard import com.android.credentialmanager.common.ui.ToggleVisibilityButton import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme @OptIn(ExperimentalMaterial3Api::class) @Composable fun CreateCredentialScreen( viewModel: CredentialSelectorViewModel, Loading @@ -80,10 +79,10 @@ fun CreateCredentialScreen( ) CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard( requestDisplayInfo = createCredentialUiState.requestDisplayInfo, enabledProviderList = createCredentialUiState.enabledProviders, disabledProviderList = createCredentialUiState.disabledProviders, sortedCreateOptionsPairs = createCredentialUiState.sortedCreateOptionsPairs, hasRemoteEntry = createCredentialUiState.remoteEntry != null, onOptionSelected = viewModel::createFlowOnEntrySelectedFromFirstUseScreen, onDisabledProvidersSelected = Loading Loading @@ -277,9 +276,9 @@ fun ConfirmationCard( @Composable fun ProviderSelectionCard( requestDisplayInfo: RequestDisplayInfo, enabledProviderList: List<EnabledProviderInfo>, disabledProviderList: List<DisabledProviderInfo>?, sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>, hasRemoteEntry: Boolean, onOptionSelected: (ActiveEntry) -> Unit, onDisabledProvidersSelected: () -> Unit, onMoreOptionsSelected: () -> Unit, Loading @@ -302,7 +301,8 @@ fun ProviderSelectionCard( CredentialType.PASSWORD -> stringResource(R.string.passwords) CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info) }), } ), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(horizontal = 24.dp) .align(alignment = Alignment.CenterHorizontally), Loading @@ -317,15 +317,14 @@ fun ProviderSelectionCard( style = MaterialTheme.typography.bodyLarge, modifier = Modifier.padding(horizontal = 28.dp), ) Divider( thickness = 18.dp, color = Color.Transparent ) ContainerCard( shape = MaterialTheme.shapes.medium, modifier = Modifier .padding(horizontal = 24.dp) .align(alignment = Alignment.CenterHorizontally), modifier = Modifier.padding( start = 24.dp, end = 24.dp, top = 24.dp, bottom = if (hasRemoteEntry) 24.dp else 16.dp ).align(alignment = Alignment.CenterHorizontally), ) { LazyColumn( verticalArrangement = Arrangement.spacedBy(2.dp) Loading Loading @@ -356,12 +355,11 @@ fun ProviderSelectionCard( } } } if (hasRemoteEntry) { Divider( thickness = 24.dp, color = Color.Transparent ) enabledProviderList.forEach { enabledProvider -> if (enabledProvider.remoteEntry != null) { Row( horizontalArrangement = Arrangement.Start, modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp) Loading @@ -371,13 +369,10 @@ fun ProviderSelectionCard( onMoreOptionsSelected ) } return@forEach } } Divider( thickness = 18.dp, thickness = 24.dp, color = Color.Transparent, modifier = Modifier.padding(bottom = 16.dp) ) } } Loading Loading @@ -412,7 +407,8 @@ fun MoreOptionsSelectionCard( CredentialType.PASSWORD -> stringResource(R.string.password) CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info) }), } ), style = MaterialTheme.typography.titleMedium, ) }, Loading Loading @@ -653,7 +649,8 @@ fun CreationSelectionCard( text = createOptionInfo.footerDescription, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.padding( start = 29.dp, top = 8.dp, bottom = 18.dp, end = 28.dp) start = 29.dp, top = 8.dp, bottom = 18.dp, end = 28.dp ) ) } Divider( Loading Loading @@ -739,7 +736,8 @@ fun MoreAboutPasskeysIntroCard( TextOnSurface( text = stringResource( R.string.more_about_passkeys_title), R.string.more_about_passkeys_title ), style = MaterialTheme.typography.titleMedium, ) }, Loading Loading @@ -865,9 +863,13 @@ fun PrimaryCreateOptionRow( style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(top = 16.dp, start = 5.dp), ) Row(modifier = Modifier.fillMaxWidth().padding(top = 4.dp, bottom = 16.dp, start = 5.dp), verticalAlignment = Alignment.CenterVertically) { Row( modifier = Modifier.fillMaxWidth().padding( top = 4.dp, bottom = 16.dp, start = 5.dp ), verticalAlignment = Alignment.CenterVertically ) { val visualTransformation = remember { PasswordVisualTransformation() } // This subtitle would never be null for create password val originalPassword by remember { Loading Loading @@ -915,7 +917,8 @@ fun PrimaryCreateOptionRow( text = requestDisplayInfo.title, style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding( top = 16.dp, bottom = 16.dp, start = 5.dp), top = 16.dp, bottom = 16.dp, start = 5.dp ), ) } } Loading Loading @@ -957,7 +960,8 @@ fun MoreOptionsInfoRow( ) } if (requestDisplayInfo.type == CredentialType.PASSKEY || requestDisplayInfo.type == CredentialType.PASSWORD) { requestDisplayInfo.type == CredentialType.PASSWORD ) { if (createOptionInfo.passwordCount != null && createOptionInfo.passkeyCount != null ) { Loading packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +5 −0 Original line number Diff line number Diff line Loading @@ -33,9 +33,14 @@ data class CreateCredentialUiState( // we're showing provider selection page at the beginning val hasDefaultProvider: Boolean, val activeEntry: ActiveEntry? = null, val remoteEntry: RemoteInfo? = null, val isFromProviderSelection: Boolean? = null, ) internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean { return state.sortedCreateOptionsPairs.isNotEmpty() } open class ProviderInfo( val icon: Drawable, val id: String, Loading Loading
packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +22 −17 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ class CredentialManagerRepo( requestInfo = intent.extras?.getParcelable( RequestInfo.EXTRA_REQUEST_INFO, RequestInfo::class.java ) ?: testGetRequestInfo() ) ?: testCreatePasskeyRequestInfo() providerEnabledList = when (requestInfo.type) { RequestInfo.TYPE_CREATE -> Loading Loading @@ -115,8 +115,10 @@ class CredentialManagerRepo( providerDisableListUiState, defaultProviderId, requestDisplayInfoUiState, /** isOnPasskeyIntroStateAlready = */ false, isPasskeyFirstUse)!!, /** isOnPasskeyIntroStateAlready = */ false, isPasskeyFirstUse )!!, getCredentialUiState = null, ) } Loading Loading @@ -224,12 +226,14 @@ class CredentialManagerRepo( .Builder("io.enpass.app") .setSaveEntries( listOf<Entry>( CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-1", "elisa.beckett@gmail.com", 20, 7, 27, Instant.ofEpochSecond(10L), "Legal note" ), CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-2", "elisa.work@google.com", 20, 7, 27, Instant.ofEpochSecond(12L), null Loading @@ -244,12 +248,14 @@ class CredentialManagerRepo( .Builder("com.dashlane") .setSaveEntries( listOf<Entry>( CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-3", "elisa.beckett@dashlane.com", 20, 7, 27, Instant.ofEpochSecond(11L), null ), CreateTestUtils.newCreateEntry(context, CreateTestUtils.newCreateEntry( context, "key1", "subkey-4", "elisa.work@dashlane.com", 20, 7, 27, Instant.ofEpochSecond(14L), null Loading Loading @@ -343,7 +349,6 @@ class CredentialManagerRepo( } private fun newRemoteEntry( key: String, subkey: String, Loading Loading @@ -427,7 +432,8 @@ class CredentialManagerRepo( val displayInfo = DisplayInfo("my-username00", "Joe") data.putBundle( "androidx.credentials.BUNDLE_KEY_REQUEST_DISPLAY_INFO", displayInfo.toBundle()) displayInfo.toBundle() ) return RequestInfo.newCreateRequestInfo( Binder(), CreateCredentialRequest( Loading @@ -445,8 +451,7 @@ class CredentialManagerRepo( Binder(), GetCredentialRequest.Builder( Bundle() ) .addCredentialOption( ).addCredentialOption( CredentialOption( "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL", Bundle(), Loading
packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +5 −3 Original line number Diff line number Diff line Loading @@ -36,7 +36,9 @@ import com.android.credentialmanager.common.DialogState import com.android.credentialmanager.common.ProviderActivityResult import com.android.credentialmanager.common.StartBalIntentSenderForResultContract import com.android.credentialmanager.createflow.CreateCredentialScreen import com.android.credentialmanager.createflow.hasContentToDisplay import com.android.credentialmanager.getflow.GetCredentialScreen import com.android.credentialmanager.getflow.hasContentToDisplay import com.android.credentialmanager.ui.theme.CredentialSelectorTheme @ExperimentalMaterialApi Loading Loading @@ -94,13 +96,13 @@ class CredentialSelectorActivity : ComponentActivity() { val createCredentialUiState = viewModel.uiState.createCredentialUiState val getCredentialUiState = viewModel.uiState.getCredentialUiState if (createCredentialUiState != null) { if (createCredentialUiState != null && hasContentToDisplay(createCredentialUiState)) { CreateCredentialScreen( viewModel = viewModel, createCredentialUiState = createCredentialUiState, providerActivityLauncher = launcher ) } else if (getCredentialUiState != null) { } else if (getCredentialUiState != null && hasContentToDisplay(getCredentialUiState)) { GetCredentialScreen( viewModel = viewModel, getCredentialUiState = getCredentialUiState, Loading Loading @@ -130,7 +132,7 @@ class CredentialSelectorActivity : ComponentActivity() { } private fun onInitializationError(e: Exception, intent: Intent) { Log.e(Constants.LOG_TAG, "Failed to show the credential selector", e) Log.e(Constants.LOG_TAG, "Failed to show the credential selector; closing the activity", e) val resultReceiver = intent.getParcelableExtra( android.credentials.ui.Constants.EXTRA_RESULT_RECEIVER, ResultReceiver::class.java Loading
packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +9 −2 Original line number Diff line number Diff line Loading @@ -473,8 +473,14 @@ class CreateFlowUtils { createOptionsPairs.add(Pair(it, enabledProvider)) } } if (enabledProvider.remoteEntry != null) { remoteEntry = enabledProvider.remoteEntry!! val currRemoteEntry = enabledProvider.remoteEntry if (currRemoteEntry != null) { if (remoteEntry != null) { // There can only be at most one remote entry Log.d(Constants.LOG_TAG, "Found more than one remote entry.") return null } remoteEntry = currRemoteEntry } } val initialScreenState = toCreateScreenState( Loading @@ -500,6 +506,7 @@ class CreateFlowUtils { lastSeenProviderWithNonEmptyCreateOptions, /*remoteEntry=*/remoteEntry ), remoteEntry = remoteEntry, ) } Loading
packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +41 −37 Original line number Diff line number Diff line Loading @@ -59,7 +59,6 @@ import com.android.credentialmanager.common.ui.ContainerCard import com.android.credentialmanager.common.ui.ToggleVisibilityButton import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme @OptIn(ExperimentalMaterial3Api::class) @Composable fun CreateCredentialScreen( viewModel: CredentialSelectorViewModel, Loading @@ -80,10 +79,10 @@ fun CreateCredentialScreen( ) CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard( requestDisplayInfo = createCredentialUiState.requestDisplayInfo, enabledProviderList = createCredentialUiState.enabledProviders, disabledProviderList = createCredentialUiState.disabledProviders, sortedCreateOptionsPairs = createCredentialUiState.sortedCreateOptionsPairs, hasRemoteEntry = createCredentialUiState.remoteEntry != null, onOptionSelected = viewModel::createFlowOnEntrySelectedFromFirstUseScreen, onDisabledProvidersSelected = Loading Loading @@ -277,9 +276,9 @@ fun ConfirmationCard( @Composable fun ProviderSelectionCard( requestDisplayInfo: RequestDisplayInfo, enabledProviderList: List<EnabledProviderInfo>, disabledProviderList: List<DisabledProviderInfo>?, sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>, hasRemoteEntry: Boolean, onOptionSelected: (ActiveEntry) -> Unit, onDisabledProvidersSelected: () -> Unit, onMoreOptionsSelected: () -> Unit, Loading @@ -302,7 +301,8 @@ fun ProviderSelectionCard( CredentialType.PASSWORD -> stringResource(R.string.passwords) CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info) }), } ), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(horizontal = 24.dp) .align(alignment = Alignment.CenterHorizontally), Loading @@ -317,15 +317,14 @@ fun ProviderSelectionCard( style = MaterialTheme.typography.bodyLarge, modifier = Modifier.padding(horizontal = 28.dp), ) Divider( thickness = 18.dp, color = Color.Transparent ) ContainerCard( shape = MaterialTheme.shapes.medium, modifier = Modifier .padding(horizontal = 24.dp) .align(alignment = Alignment.CenterHorizontally), modifier = Modifier.padding( start = 24.dp, end = 24.dp, top = 24.dp, bottom = if (hasRemoteEntry) 24.dp else 16.dp ).align(alignment = Alignment.CenterHorizontally), ) { LazyColumn( verticalArrangement = Arrangement.spacedBy(2.dp) Loading Loading @@ -356,12 +355,11 @@ fun ProviderSelectionCard( } } } if (hasRemoteEntry) { Divider( thickness = 24.dp, color = Color.Transparent ) enabledProviderList.forEach { enabledProvider -> if (enabledProvider.remoteEntry != null) { Row( horizontalArrangement = Arrangement.Start, modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp) Loading @@ -371,13 +369,10 @@ fun ProviderSelectionCard( onMoreOptionsSelected ) } return@forEach } } Divider( thickness = 18.dp, thickness = 24.dp, color = Color.Transparent, modifier = Modifier.padding(bottom = 16.dp) ) } } Loading Loading @@ -412,7 +407,8 @@ fun MoreOptionsSelectionCard( CredentialType.PASSWORD -> stringResource(R.string.password) CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info) }), } ), style = MaterialTheme.typography.titleMedium, ) }, Loading Loading @@ -653,7 +649,8 @@ fun CreationSelectionCard( text = createOptionInfo.footerDescription, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.padding( start = 29.dp, top = 8.dp, bottom = 18.dp, end = 28.dp) start = 29.dp, top = 8.dp, bottom = 18.dp, end = 28.dp ) ) } Divider( Loading Loading @@ -739,7 +736,8 @@ fun MoreAboutPasskeysIntroCard( TextOnSurface( text = stringResource( R.string.more_about_passkeys_title), R.string.more_about_passkeys_title ), style = MaterialTheme.typography.titleMedium, ) }, Loading Loading @@ -865,9 +863,13 @@ fun PrimaryCreateOptionRow( style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(top = 16.dp, start = 5.dp), ) Row(modifier = Modifier.fillMaxWidth().padding(top = 4.dp, bottom = 16.dp, start = 5.dp), verticalAlignment = Alignment.CenterVertically) { Row( modifier = Modifier.fillMaxWidth().padding( top = 4.dp, bottom = 16.dp, start = 5.dp ), verticalAlignment = Alignment.CenterVertically ) { val visualTransformation = remember { PasswordVisualTransformation() } // This subtitle would never be null for create password val originalPassword by remember { Loading Loading @@ -915,7 +917,8 @@ fun PrimaryCreateOptionRow( text = requestDisplayInfo.title, style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding( top = 16.dp, bottom = 16.dp, start = 5.dp), top = 16.dp, bottom = 16.dp, start = 5.dp ), ) } } Loading Loading @@ -957,7 +960,8 @@ fun MoreOptionsInfoRow( ) } if (requestDisplayInfo.type == CredentialType.PASSKEY || requestDisplayInfo.type == CredentialType.PASSWORD) { requestDisplayInfo.type == CredentialType.PASSWORD ) { if (createOptionInfo.passwordCount != null && createOptionInfo.passkeyCount != null ) { Loading
packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +5 −0 Original line number Diff line number Diff line Loading @@ -33,9 +33,14 @@ data class CreateCredentialUiState( // we're showing provider selection page at the beginning val hasDefaultProvider: Boolean, val activeEntry: ActiveEntry? = null, val remoteEntry: RemoteInfo? = null, val isFromProviderSelection: Boolean? = null, ) internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean { return state.sortedCreateOptionsPairs.isNotEmpty() } open class ProviderInfo( val icon: Drawable, val id: String, Loading