Loading packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +21 −10 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ import com.android.credentialmanager.getflow.GetCredentialUiState import androidx.credentials.CreateCredentialRequest.DisplayInfo import androidx.credentials.CreatePublicKeyCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.GetPasswordOption import androidx.credentials.GetPublicKeyCredentialOption import java.time.Instant Loading @@ -71,7 +73,7 @@ class CredentialManagerRepo( requestInfo = intent.extras?.getParcelable( RequestInfo.EXTRA_REQUEST_INFO, RequestInfo::class.java ) ?: testCreatePasswordRequestInfo() ) ?: testCreatePasskeyRequestInfo() val originName: String? = when (requestInfo.type) { RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin Loading Loading @@ -120,8 +122,7 @@ class CredentialManagerRepo( providerDisableListUiState, defaultProviderId, requestDisplayInfoUiState, /** isOnPasskeyIntroStateAlready */ false, isOnPasskeyIntroStateAlready = false, isPasskeyFirstUse )!!, getCredentialUiState = null, Loading Loading @@ -400,7 +401,8 @@ class CredentialManagerRepo( " \"authenticatorSelection\": {\n" + " \"residentKey\": \"required\",\n" + " \"requireResidentKey\": true\n" + " }}" " }}", preferImmediatelyAvailableCredentials = true, ) val credentialData = request.credentialData return RequestInfo.newCreateRequestInfo( Loading Loading @@ -446,19 +448,28 @@ class CredentialManagerRepo( } private fun testGetRequestInfo(): RequestInfo { val passwordOption = GetPasswordOption() val passkeyOption = GetPublicKeyCredentialOption( "json", preferImmediatelyAvailableCredentials = false) return RequestInfo.newGetRequestInfo( Binder(), GetCredentialRequest.Builder( Bundle() ).addCredentialOption( CredentialOption( "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL", Bundle(), Bundle(), /*isSystemProviderRequired=*/ false passwordOption.type, passwordOption.requestData, passwordOption.candidateQueryData, passwordOption.isSystemProviderRequired ) ).addCredentialOption( CredentialOption( passkeyOption.type, passkeyOption.requestData, passkeyOption.candidateQueryData, passkeyOption.isSystemProviderRequired ) .build(), ).build(), "com.google.android.youtube" ) } Loading packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +65 −18 Original line number Diff line number Diff line Loading @@ -50,7 +50,11 @@ import com.android.credentialmanager.getflow.RemoteEntryInfo import androidx.credentials.CreateCredentialRequest import androidx.credentials.CreateCustomCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.CredentialOption import androidx.credentials.CreatePublicKeyCredentialRequest import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged import androidx.credentials.GetPublicKeyCredentialOption import androidx.credentials.GetPublicKeyCredentialOptionPrivileged import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL import androidx.credentials.provider.Action import androidx.credentials.provider.AuthenticationAction Loading Loading @@ -172,10 +176,27 @@ class GetFlowUtils { context: Context, originName: String?, ): com.android.credentialmanager.getflow.RequestDisplayInfo? { val getCredentialRequest = requestInfo.getCredentialRequest ?: return null val preferImmediatelyAvailableCredentials = getCredentialRequest.credentialOptions.any { val credentialOptionJetpack = CredentialOption.createFrom( it.type, it.credentialRetrievalData, it.credentialRetrievalData, it.isSystemProviderRequired ) if (credentialOptionJetpack is GetPublicKeyCredentialOption) { credentialOptionJetpack.preferImmediatelyAvailableCredentials } else if (credentialOptionJetpack is GetPublicKeyCredentialOptionPrivileged) { credentialOptionJetpack.preferImmediatelyAvailableCredentials } else { false } } return com.android.credentialmanager.getflow.RequestDisplayInfo( appName = originName ?: getAppLabel(context.packageManager, requestInfo.appPackageName) ?: return null ?: return null, preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials ) } Loading Loading @@ -415,24 +436,25 @@ class CreateFlowUtils { createCredentialRequestJetpack.password, CredentialType.PASSWORD, appLabel, context.getDrawable(R.drawable.ic_password)!! context.getDrawable(R.drawable.ic_password) ?: return null, preferImmediatelyAvailableCredentials = false, ) is CreatePublicKeyCredentialRequest -> { val requestJson = createCredentialRequestJetpack.requestJson val json = JSONObject(requestJson) var name = "" var displayName = "" if (json.has("user")) { val user: JSONObject = json.getJSONObject("user") name = user.getString("name") displayName = user.getString("displayName") newRequestDisplayInfoFromPasskeyJson( requestJson = createCredentialRequestJetpack.requestJson, appLabel = appLabel, context = context, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, ) } RequestDisplayInfo( name, displayName, CredentialType.PASSKEY, appLabel, context.getDrawable(R.drawable.ic_passkey)!! is CreatePublicKeyCredentialRequestPrivileged -> { newRequestDisplayInfoFromPasskeyJson( requestJson = createCredentialRequestJetpack.requestJson, appLabel = appLabel, context = context, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, ) } is CreateCustomCredentialRequest -> { Loading @@ -446,7 +468,8 @@ class CreateFlowUtils { type = CredentialType.UNKNOWN, appName = appLabel, typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_other_sign_in)!! ?: context.getDrawable(R.drawable.ic_other_sign_in) ?: return null, preferImmediatelyAvailableCredentials = false, ) } else -> null Loading Loading @@ -613,5 +636,29 @@ class CreateFlowUtils { ) } else null } private fun newRequestDisplayInfoFromPasskeyJson( requestJson: String, appLabel: String, context: Context, preferImmediatelyAvailableCredentials: Boolean, ): RequestDisplayInfo? { val json = JSONObject(requestJson) var name = "" var displayName = "" if (json.has("user")) { val user: JSONObject = json.getJSONObject("user") name = user.getString("name") displayName = user.getString("displayName") } return RequestDisplayInfo( name, displayName, CredentialType.PASSKEY, appLabel, context.getDrawable(R.drawable.ic_passkey) ?: return null, preferImmediatelyAvailableCredentials, ) } } } packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +4 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ data class CreateCredentialUiState( ) internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean { return state.sortedCreateOptionsPairs.isNotEmpty() return state.sortedCreateOptionsPairs.isNotEmpty() || (!state.requestDisplayInfo.preferImmediatelyAvailableCredentials && state.remoteEntry != null) } open class ProviderInfo( Loading Loading @@ -104,6 +106,7 @@ data class RequestDisplayInfo( val type: CredentialType, val appName: String, val typeIcon: Drawable, val preferImmediatelyAvailableCredentials: Boolean, ) /** Loading packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +3 −2 Original line number Diff line number Diff line Loading @@ -37,7 +37,8 @@ data class GetCredentialUiState( internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean { return state.providerDisplayInfo.sortedUserNameToCredentialEntryList.isNotEmpty() || state.providerDisplayInfo.authenticationEntryList.isNotEmpty() || state.providerDisplayInfo.remoteEntry != null (state.providerDisplayInfo.remoteEntry != null && !state.requestDisplayInfo.preferImmediatelyAvailableCredentials) } data class ProviderInfo( Loading Loading @@ -146,6 +147,7 @@ class ActionEntryInfo( data class RequestDisplayInfo( val appName: String, val preferImmediatelyAvailableCredentials: Boolean, ) /** Loading Loading @@ -246,7 +248,6 @@ private fun toActiveEntry( private fun toGetScreenState( providerDisplayInfo: ProviderDisplayInfo ): GetScreenState { return if (providerDisplayInfo.sortedUserNameToCredentialEntryList.isEmpty() && providerDisplayInfo.remoteEntry == null && providerDisplayInfo.authenticationEntryList.all { it.isUnlockedAndEmpty }) Loading Loading
packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +21 −10 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ import com.android.credentialmanager.getflow.GetCredentialUiState import androidx.credentials.CreateCredentialRequest.DisplayInfo import androidx.credentials.CreatePublicKeyCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.GetPasswordOption import androidx.credentials.GetPublicKeyCredentialOption import java.time.Instant Loading @@ -71,7 +73,7 @@ class CredentialManagerRepo( requestInfo = intent.extras?.getParcelable( RequestInfo.EXTRA_REQUEST_INFO, RequestInfo::class.java ) ?: testCreatePasswordRequestInfo() ) ?: testCreatePasskeyRequestInfo() val originName: String? = when (requestInfo.type) { RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin Loading Loading @@ -120,8 +122,7 @@ class CredentialManagerRepo( providerDisableListUiState, defaultProviderId, requestDisplayInfoUiState, /** isOnPasskeyIntroStateAlready */ false, isOnPasskeyIntroStateAlready = false, isPasskeyFirstUse )!!, getCredentialUiState = null, Loading Loading @@ -400,7 +401,8 @@ class CredentialManagerRepo( " \"authenticatorSelection\": {\n" + " \"residentKey\": \"required\",\n" + " \"requireResidentKey\": true\n" + " }}" " }}", preferImmediatelyAvailableCredentials = true, ) val credentialData = request.credentialData return RequestInfo.newCreateRequestInfo( Loading Loading @@ -446,19 +448,28 @@ class CredentialManagerRepo( } private fun testGetRequestInfo(): RequestInfo { val passwordOption = GetPasswordOption() val passkeyOption = GetPublicKeyCredentialOption( "json", preferImmediatelyAvailableCredentials = false) return RequestInfo.newGetRequestInfo( Binder(), GetCredentialRequest.Builder( Bundle() ).addCredentialOption( CredentialOption( "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL", Bundle(), Bundle(), /*isSystemProviderRequired=*/ false passwordOption.type, passwordOption.requestData, passwordOption.candidateQueryData, passwordOption.isSystemProviderRequired ) ).addCredentialOption( CredentialOption( passkeyOption.type, passkeyOption.requestData, passkeyOption.candidateQueryData, passkeyOption.isSystemProviderRequired ) .build(), ).build(), "com.google.android.youtube" ) } Loading
packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +65 −18 Original line number Diff line number Diff line Loading @@ -50,7 +50,11 @@ import com.android.credentialmanager.getflow.RemoteEntryInfo import androidx.credentials.CreateCredentialRequest import androidx.credentials.CreateCustomCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.CredentialOption import androidx.credentials.CreatePublicKeyCredentialRequest import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged import androidx.credentials.GetPublicKeyCredentialOption import androidx.credentials.GetPublicKeyCredentialOptionPrivileged import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL import androidx.credentials.provider.Action import androidx.credentials.provider.AuthenticationAction Loading Loading @@ -172,10 +176,27 @@ class GetFlowUtils { context: Context, originName: String?, ): com.android.credentialmanager.getflow.RequestDisplayInfo? { val getCredentialRequest = requestInfo.getCredentialRequest ?: return null val preferImmediatelyAvailableCredentials = getCredentialRequest.credentialOptions.any { val credentialOptionJetpack = CredentialOption.createFrom( it.type, it.credentialRetrievalData, it.credentialRetrievalData, it.isSystemProviderRequired ) if (credentialOptionJetpack is GetPublicKeyCredentialOption) { credentialOptionJetpack.preferImmediatelyAvailableCredentials } else if (credentialOptionJetpack is GetPublicKeyCredentialOptionPrivileged) { credentialOptionJetpack.preferImmediatelyAvailableCredentials } else { false } } return com.android.credentialmanager.getflow.RequestDisplayInfo( appName = originName ?: getAppLabel(context.packageManager, requestInfo.appPackageName) ?: return null ?: return null, preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials ) } Loading Loading @@ -415,24 +436,25 @@ class CreateFlowUtils { createCredentialRequestJetpack.password, CredentialType.PASSWORD, appLabel, context.getDrawable(R.drawable.ic_password)!! context.getDrawable(R.drawable.ic_password) ?: return null, preferImmediatelyAvailableCredentials = false, ) is CreatePublicKeyCredentialRequest -> { val requestJson = createCredentialRequestJetpack.requestJson val json = JSONObject(requestJson) var name = "" var displayName = "" if (json.has("user")) { val user: JSONObject = json.getJSONObject("user") name = user.getString("name") displayName = user.getString("displayName") newRequestDisplayInfoFromPasskeyJson( requestJson = createCredentialRequestJetpack.requestJson, appLabel = appLabel, context = context, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, ) } RequestDisplayInfo( name, displayName, CredentialType.PASSKEY, appLabel, context.getDrawable(R.drawable.ic_passkey)!! is CreatePublicKeyCredentialRequestPrivileged -> { newRequestDisplayInfoFromPasskeyJson( requestJson = createCredentialRequestJetpack.requestJson, appLabel = appLabel, context = context, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, ) } is CreateCustomCredentialRequest -> { Loading @@ -446,7 +468,8 @@ class CreateFlowUtils { type = CredentialType.UNKNOWN, appName = appLabel, typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_other_sign_in)!! ?: context.getDrawable(R.drawable.ic_other_sign_in) ?: return null, preferImmediatelyAvailableCredentials = false, ) } else -> null Loading Loading @@ -613,5 +636,29 @@ class CreateFlowUtils { ) } else null } private fun newRequestDisplayInfoFromPasskeyJson( requestJson: String, appLabel: String, context: Context, preferImmediatelyAvailableCredentials: Boolean, ): RequestDisplayInfo? { val json = JSONObject(requestJson) var name = "" var displayName = "" if (json.has("user")) { val user: JSONObject = json.getJSONObject("user") name = user.getString("name") displayName = user.getString("displayName") } return RequestDisplayInfo( name, displayName, CredentialType.PASSKEY, appLabel, context.getDrawable(R.drawable.ic_passkey) ?: return null, preferImmediatelyAvailableCredentials, ) } } }
packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +4 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ data class CreateCredentialUiState( ) internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean { return state.sortedCreateOptionsPairs.isNotEmpty() return state.sortedCreateOptionsPairs.isNotEmpty() || (!state.requestDisplayInfo.preferImmediatelyAvailableCredentials && state.remoteEntry != null) } open class ProviderInfo( Loading Loading @@ -104,6 +106,7 @@ data class RequestDisplayInfo( val type: CredentialType, val appName: String, val typeIcon: Drawable, val preferImmediatelyAvailableCredentials: Boolean, ) /** Loading
packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +3 −2 Original line number Diff line number Diff line Loading @@ -37,7 +37,8 @@ data class GetCredentialUiState( internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean { return state.providerDisplayInfo.sortedUserNameToCredentialEntryList.isNotEmpty() || state.providerDisplayInfo.authenticationEntryList.isNotEmpty() || state.providerDisplayInfo.remoteEntry != null (state.providerDisplayInfo.remoteEntry != null && !state.requestDisplayInfo.preferImmediatelyAvailableCredentials) } data class ProviderInfo( Loading Loading @@ -146,6 +147,7 @@ class ActionEntryInfo( data class RequestDisplayInfo( val appName: String, val preferImmediatelyAvailableCredentials: Boolean, ) /** Loading Loading @@ -246,7 +248,6 @@ private fun toActiveEntry( private fun toGetScreenState( providerDisplayInfo: ProviderDisplayInfo ): GetScreenState { return if (providerDisplayInfo.sortedUserNameToCredentialEntryList.isEmpty() && providerDisplayInfo.remoteEntry == null && providerDisplayInfo.authenticationEntryList.all { it.isUnlockedAndEmpty }) Loading