Loading core/java/android/credentials/ui/RequestInfo.java +6 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,12 @@ public class RequestInfo implements Parcelable { */ public static final @NonNull String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO"; /** * The intent extra key for the {@code ResultReceiver} object when launching the UX * activities. */ public static final @NonNull String EXTRA_RESULT_RECEIVER = "android.credentials.ui.extra.RESULT_RECEIVER"; /** Type value for an executeGetCredential request. */ public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET"; Loading packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.app.slice.Slice import android.credentials.ui.Entry import android.graphics.drawable.Icon /** * UI representation for a credential entry used during the get credential flow. * * TODO: move to jetpack. */ class CredentialEntryUi( val userName: CharSequence, val displayName: CharSequence?, val icon: Icon?, // TODO: add last used. ) { companion object { fun fromSlice(slice: Slice): CredentialEntryUi { val items = slice.items var title: String? = null var subTitle: String? = null var icon: Icon? = null items.forEach { if (it.hasHint(Entry.HINT_ICON)) { icon = it.icon } else if (it.hasHint(Entry.HINT_SUBTITLE)) { subTitle = it.text.toString() } else if (it.hasHint(Entry.HINT_TITLE)) { title = it.text.toString() } } // TODO: fail NPE more elegantly. return CredentialEntryUi(title!!, subTitle, icon) } } } packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +49 −142 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.app.slice.Slice Loading @@ -9,11 +25,8 @@ import android.credentials.ui.ProviderData import android.credentials.ui.RequestInfo import android.graphics.drawable.Icon import android.os.Binder import com.android.credentialmanager.createflow.CreateOptionInfo import com.android.credentialmanager.createflow.CreatePasskeyUiState import com.android.credentialmanager.createflow.CreateScreenState import com.android.credentialmanager.createflow.ProviderInfo import com.android.credentialmanager.getflow.CredentialOptionInfo import com.android.credentialmanager.getflow.GetCredentialUiState import com.android.credentialmanager.getflow.GetScreenState Loading Loading @@ -41,6 +54,39 @@ class CredentialManagerRepo( ) ?: testProviderList() } fun getCredentialInitialUiState(): GetCredentialUiState { val providerList = GetFlowUtils.toProviderList(providerList, context) return GetCredentialUiState( providerList, GetScreenState.CREDENTIAL_SELECTION, providerList.first() ) } fun createPasskeyInitialUiState(): CreatePasskeyUiState { val providerList = CreateFlowUtils.toProviderList(providerList, context) return CreatePasskeyUiState( providers = providerList, currentScreenState = CreateScreenState.PASSKEY_INTRO, ) } companion object { lateinit var repo: CredentialManagerRepo fun setup( context: Context, intent: Intent, ) { repo = CredentialManagerRepo(context, intent) } fun getInstance(): CredentialManagerRepo { return repo } } // TODO: below are prototype functionalities. To be removed for productionization. private fun testProviderList(): List<ProviderData> { return listOf( ProviderData( Loading Loading @@ -94,143 +140,4 @@ class CredentialManagerRepo( slice ) } private fun getCredentialProviderList(): List<com.android.credentialmanager.getflow.ProviderInfo> { return listOf( com.android.credentialmanager.getflow.ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Google Password Manager", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = listOf( CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@gmail.com", id = "id-1", ), CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett Work", subtitle = "elisa.beckett.work@google.com", id = "id-2", ), ) ), com.android.credentialmanager.getflow.ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Lastpass", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = listOf( CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@lastpass.com", id = "id-1", ), ) ), com.android.credentialmanager.getflow.ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Dashlane", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = listOf( CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@dashlane.com", id = "id-1", ), ) ), ) } private fun createCredentialProviderList(): List<ProviderInfo> { return listOf( ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Google Password Manager", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = listOf( CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@gmail.com", id = "id-1", ), CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett Work", subtitle = "elisa.beckett.work@google.com", id = "id-2", ), ) ), ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Lastpass", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = listOf( CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@lastpass.com", id = "id-1", ), ) ), ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Dashlane", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = listOf( CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@dashlane.com", id = "id-1", ), ) ), ) } fun getCredentialInitialUiState(): GetCredentialUiState { val providerList = getCredentialProviderList() return GetCredentialUiState( providerList, GetScreenState.CREDENTIAL_SELECTION, providerList.first() ) } fun createPasskeyInitialUiState(): CreatePasskeyUiState { val providerList = createCredentialProviderList() return CreatePasskeyUiState( providers = providerList, currentScreenState = CreateScreenState.PASSKEY_INTRO, ) } companion object { lateinit var repo: CredentialManagerRepo fun setup( context: Context, intent: Intent, ) { repo = CredentialManagerRepo(context, intent) } fun getInstance(): CredentialManagerRepo { return repo } } } packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +31 −8 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.credentials.ui.RequestInfo import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity Loading @@ -16,14 +33,20 @@ class CredentialSelectorActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) CredentialManagerRepo.setup(this, intent) val startDestination = intent.extras?.getString( "start_destination", "CREATE_PASSKEY" ) ?: "CREATE_PASSKEY" val requestInfo = intent.extras?.getParcelable<RequestInfo>(RequestInfo.EXTRA_REQUEST_INFO) if (requestInfo != null) { val requestType = requestInfo.type setContent { CredentialSelectorTheme { CredentialManagerBottomSheet(startDestination) CredentialManagerBottomSheet(requestType) } } } else { // TODO: prototype only code to be removed. In production should exit. setContent { CredentialSelectorTheme { CredentialManagerBottomSheet(RequestInfo.TYPE_CREATE) } } } } Loading packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt 0 → 100644 +106 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.content.Context import android.credentials.ui.Entry import android.credentials.ui.ProviderData import com.android.credentialmanager.createflow.CreateOptionInfo import com.android.credentialmanager.getflow.CredentialOptionInfo import com.android.credentialmanager.getflow.ProviderInfo /** Utility functions for converting CredentialManager data structures to or from UI formats. */ class GetFlowUtils { companion object { fun toProviderList( providerDataList: List<ProviderData>, context: Context, ): List<ProviderInfo> { return providerDataList.map { ProviderInfo( // TODO: replace to extract from the service data structure when available icon = context.getDrawable(R.drawable.ic_passkey)!!, name = it.packageName, appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context) ) } } /* From service data structure to UI credential entry list representation. */ private fun toCredentialOptionInfoList( credentialEntries: List<Entry>, context: Context, ): List<CredentialOptionInfo> { return credentialEntries.map { val credentialEntryUi = CredentialEntryUi.fromSlice(it.slice) // Consider directly move the UI object into the class. return@map CredentialOptionInfo( // TODO: remove fallbacks icon = credentialEntryUi.icon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_passkey)!!, title = credentialEntryUi.userName.toString(), subtitle = credentialEntryUi.displayName?.toString() ?: "Unknown display name", id = it.entryId, ) } } } } class CreateFlowUtils { companion object { fun toProviderList( providerDataList: List<ProviderData>, context: Context, ): List<com.android.credentialmanager.createflow.ProviderInfo> { return providerDataList.map { com.android.credentialmanager.createflow.ProviderInfo( // TODO: replace to extract from the service data structure when available icon = context.getDrawable(R.drawable.ic_passkey)!!, name = it.packageName, appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = toCreationOptionInfoList(it.credentialEntries, context), ) } } private fun toCreationOptionInfoList( creationEntries: List<Entry>, context: Context, ): List<CreateOptionInfo> { return creationEntries.map { val saveEntryUi = SaveEntryUi.fromSlice(it.slice) return@map CreateOptionInfo( // TODO: remove fallbacks icon = saveEntryUi.icon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_passkey)!!, title = saveEntryUi.title.toString(), subtitle = saveEntryUi.subTitle?.toString() ?: "Unknown subtitle", id = it.entryId, ) } } } } Loading
core/java/android/credentials/ui/RequestInfo.java +6 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,12 @@ public class RequestInfo implements Parcelable { */ public static final @NonNull String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO"; /** * The intent extra key for the {@code ResultReceiver} object when launching the UX * activities. */ public static final @NonNull String EXTRA_RESULT_RECEIVER = "android.credentials.ui.extra.RESULT_RECEIVER"; /** Type value for an executeGetCredential request. */ public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET"; Loading
packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.app.slice.Slice import android.credentials.ui.Entry import android.graphics.drawable.Icon /** * UI representation for a credential entry used during the get credential flow. * * TODO: move to jetpack. */ class CredentialEntryUi( val userName: CharSequence, val displayName: CharSequence?, val icon: Icon?, // TODO: add last used. ) { companion object { fun fromSlice(slice: Slice): CredentialEntryUi { val items = slice.items var title: String? = null var subTitle: String? = null var icon: Icon? = null items.forEach { if (it.hasHint(Entry.HINT_ICON)) { icon = it.icon } else if (it.hasHint(Entry.HINT_SUBTITLE)) { subTitle = it.text.toString() } else if (it.hasHint(Entry.HINT_TITLE)) { title = it.text.toString() } } // TODO: fail NPE more elegantly. return CredentialEntryUi(title!!, subTitle, icon) } } }
packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +49 −142 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.app.slice.Slice Loading @@ -9,11 +25,8 @@ import android.credentials.ui.ProviderData import android.credentials.ui.RequestInfo import android.graphics.drawable.Icon import android.os.Binder import com.android.credentialmanager.createflow.CreateOptionInfo import com.android.credentialmanager.createflow.CreatePasskeyUiState import com.android.credentialmanager.createflow.CreateScreenState import com.android.credentialmanager.createflow.ProviderInfo import com.android.credentialmanager.getflow.CredentialOptionInfo import com.android.credentialmanager.getflow.GetCredentialUiState import com.android.credentialmanager.getflow.GetScreenState Loading Loading @@ -41,6 +54,39 @@ class CredentialManagerRepo( ) ?: testProviderList() } fun getCredentialInitialUiState(): GetCredentialUiState { val providerList = GetFlowUtils.toProviderList(providerList, context) return GetCredentialUiState( providerList, GetScreenState.CREDENTIAL_SELECTION, providerList.first() ) } fun createPasskeyInitialUiState(): CreatePasskeyUiState { val providerList = CreateFlowUtils.toProviderList(providerList, context) return CreatePasskeyUiState( providers = providerList, currentScreenState = CreateScreenState.PASSKEY_INTRO, ) } companion object { lateinit var repo: CredentialManagerRepo fun setup( context: Context, intent: Intent, ) { repo = CredentialManagerRepo(context, intent) } fun getInstance(): CredentialManagerRepo { return repo } } // TODO: below are prototype functionalities. To be removed for productionization. private fun testProviderList(): List<ProviderData> { return listOf( ProviderData( Loading Loading @@ -94,143 +140,4 @@ class CredentialManagerRepo( slice ) } private fun getCredentialProviderList(): List<com.android.credentialmanager.getflow.ProviderInfo> { return listOf( com.android.credentialmanager.getflow.ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Google Password Manager", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = listOf( CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@gmail.com", id = "id-1", ), CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett Work", subtitle = "elisa.beckett.work@google.com", id = "id-2", ), ) ), com.android.credentialmanager.getflow.ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Lastpass", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = listOf( CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@lastpass.com", id = "id-1", ), ) ), com.android.credentialmanager.getflow.ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Dashlane", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = listOf( CredentialOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@dashlane.com", id = "id-1", ), ) ), ) } private fun createCredentialProviderList(): List<ProviderInfo> { return listOf( ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Google Password Manager", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = listOf( CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@gmail.com", id = "id-1", ), CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett Work", subtitle = "elisa.beckett.work@google.com", id = "id-2", ), ) ), ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Lastpass", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = listOf( CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@lastpass.com", id = "id-1", ), ) ), ProviderInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, name = "Dashlane", appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = listOf( CreateOptionInfo( icon = context.getDrawable(R.drawable.ic_passkey)!!, title = "Elisa Backett", subtitle = "elisa.beckett@dashlane.com", id = "id-1", ), ) ), ) } fun getCredentialInitialUiState(): GetCredentialUiState { val providerList = getCredentialProviderList() return GetCredentialUiState( providerList, GetScreenState.CREDENTIAL_SELECTION, providerList.first() ) } fun createPasskeyInitialUiState(): CreatePasskeyUiState { val providerList = createCredentialProviderList() return CreatePasskeyUiState( providers = providerList, currentScreenState = CreateScreenState.PASSKEY_INTRO, ) } companion object { lateinit var repo: CredentialManagerRepo fun setup( context: Context, intent: Intent, ) { repo = CredentialManagerRepo(context, intent) } fun getInstance(): CredentialManagerRepo { return repo } } }
packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +31 −8 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.credentials.ui.RequestInfo import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity Loading @@ -16,14 +33,20 @@ class CredentialSelectorActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) CredentialManagerRepo.setup(this, intent) val startDestination = intent.extras?.getString( "start_destination", "CREATE_PASSKEY" ) ?: "CREATE_PASSKEY" val requestInfo = intent.extras?.getParcelable<RequestInfo>(RequestInfo.EXTRA_REQUEST_INFO) if (requestInfo != null) { val requestType = requestInfo.type setContent { CredentialSelectorTheme { CredentialManagerBottomSheet(startDestination) CredentialManagerBottomSheet(requestType) } } } else { // TODO: prototype only code to be removed. In production should exit. setContent { CredentialSelectorTheme { CredentialManagerBottomSheet(RequestInfo.TYPE_CREATE) } } } } Loading
packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt 0 → 100644 +106 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.credentialmanager import android.content.Context import android.credentials.ui.Entry import android.credentials.ui.ProviderData import com.android.credentialmanager.createflow.CreateOptionInfo import com.android.credentialmanager.getflow.CredentialOptionInfo import com.android.credentialmanager.getflow.ProviderInfo /** Utility functions for converting CredentialManager data structures to or from UI formats. */ class GetFlowUtils { companion object { fun toProviderList( providerDataList: List<ProviderData>, context: Context, ): List<ProviderInfo> { return providerDataList.map { ProviderInfo( // TODO: replace to extract from the service data structure when available icon = context.getDrawable(R.drawable.ic_passkey)!!, name = it.packageName, appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context) ) } } /* From service data structure to UI credential entry list representation. */ private fun toCredentialOptionInfoList( credentialEntries: List<Entry>, context: Context, ): List<CredentialOptionInfo> { return credentialEntries.map { val credentialEntryUi = CredentialEntryUi.fromSlice(it.slice) // Consider directly move the UI object into the class. return@map CredentialOptionInfo( // TODO: remove fallbacks icon = credentialEntryUi.icon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_passkey)!!, title = credentialEntryUi.userName.toString(), subtitle = credentialEntryUi.displayName?.toString() ?: "Unknown display name", id = it.entryId, ) } } } } class CreateFlowUtils { companion object { fun toProviderList( providerDataList: List<ProviderData>, context: Context, ): List<com.android.credentialmanager.createflow.ProviderInfo> { return providerDataList.map { com.android.credentialmanager.createflow.ProviderInfo( // TODO: replace to extract from the service data structure when available icon = context.getDrawable(R.drawable.ic_passkey)!!, name = it.packageName, appDomainName = "tribank.us", credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, createOptions = toCreationOptionInfoList(it.credentialEntries, context), ) } } private fun toCreationOptionInfoList( creationEntries: List<Entry>, context: Context, ): List<CreateOptionInfo> { return creationEntries.map { val saveEntryUi = SaveEntryUi.fromSlice(it.slice) return@map CreateOptionInfo( // TODO: remove fallbacks icon = saveEntryUi.icon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_passkey)!!, title = saveEntryUi.title.toString(), subtitle = saveEntryUi.subTitle?.toString() ?: "Unknown subtitle", id = it.entryId, ) } } } }