1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.credentialmanager.createflow 18 19 import android.app.PendingIntent 20 import android.content.Intent 21 import android.graphics.drawable.Drawable 22 import com.android.credentialmanager.common.BaseEntry 23 import com.android.credentialmanager.common.CredentialType 24 import java.time.Instant 25 26 data class CreateCredentialUiState( 27 val enabledProviders: List<EnabledProviderInfo>, 28 val disabledProviders: List<DisabledProviderInfo>? = null, 29 val currentScreenState: CreateScreenState, 30 val requestDisplayInfo: RequestDisplayInfo, 31 val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>, 32 val activeEntry: ActiveEntry? = null, 33 val remoteEntry: RemoteInfo? = null, 34 val foundCandidateFromUserDefaultProvider: Boolean, 35 ) 36 37 internal fun isFlowAutoSelectable( 38 uiState: CreateCredentialUiState 39 ): Boolean { 40 return uiState.requestDisplayInfo.isAutoSelectRequest && 41 // Even if the flow is auto selectable, still allow passkey intro screen to show once if 42 // applicable. 43 uiState.currentScreenState != CreateScreenState.PASSKEY_INTRO && 44 uiState.currentScreenState != CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO && 45 uiState.sortedCreateOptionsPairs.size == 1 && 46 uiState.activeEntry?.activeEntryInfo?.let { 47 it is CreateOptionInfo && it.allowAutoSelect 48 } ?: false 49 } 50 51 internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean { 52 return state.sortedCreateOptionsPairs.isNotEmpty() || 53 (!state.requestDisplayInfo.preferImmediatelyAvailableCredentials && 54 state.remoteEntry != null) 55 } 56 57 open class ProviderInfo( 58 val icon: Drawable, 59 val id: String, 60 val displayName: String, 61 ) 62 63 class EnabledProviderInfo( 64 icon: Drawable, 65 id: String, 66 displayName: String, 67 // Sorted by last used time 68 var sortedCreateOptions: List<CreateOptionInfo>, 69 var remoteEntry: RemoteInfo?, 70 ) : ProviderInfo(icon, id, displayName) 71 72 class DisabledProviderInfo( 73 icon: Drawable, 74 id: String, 75 displayName: String, 76 ) : ProviderInfo(icon, id, displayName) 77 78 class CreateOptionInfo( 79 providerId: String, 80 entryKey: String, 81 entrySubkey: String, 82 pendingIntent: PendingIntent?, 83 fillInIntent: Intent?, 84 val userProviderDisplayName: String, 85 val profileIcon: Drawable?, 86 val passwordCount: Int?, 87 val passkeyCount: Int?, 88 val totalCredentialCount: Int?, 89 val lastUsedTime: Instant, 90 val footerDescription: String?, 91 val allowAutoSelect: Boolean, 92 ) : BaseEntry( 93 providerId, 94 entryKey, 95 entrySubkey, 96 pendingIntent, 97 fillInIntent, 98 shouldTerminateUiUponSuccessfulProviderResult = true, 99 ) 100 101 class RemoteInfo( 102 providerId: String, 103 entryKey: String, 104 entrySubkey: String, 105 pendingIntent: PendingIntent?, 106 fillInIntent: Intent?, 107 ) : BaseEntry( 108 providerId, 109 entryKey, 110 entrySubkey, 111 pendingIntent, 112 fillInIntent, 113 shouldTerminateUiUponSuccessfulProviderResult = true, 114 ) 115 116 data class RequestDisplayInfo( 117 val title: String, 118 val subtitle: String?, 119 val type: CredentialType, 120 val appName: String, 121 val typeIcon: Drawable, 122 val preferImmediatelyAvailableCredentials: Boolean, 123 val appPreferredDefaultProviderId: String?, 124 val userSetDefaultProviderIds: Set<String>, 125 // Whether the given CreateCredentialRequest allows auto select. 126 val isAutoSelectRequest: Boolean, 127 ) 128 129 /** 130 * This is initialized to be the most recent used. Can then be changed if 131 * user selects a different entry on the more option page. 132 */ 133 data class ActiveEntry ( 134 val activeProvider: EnabledProviderInfo, 135 val activeEntryInfo: BaseEntry, 136 ) 137 138 /** The name of the current screen. */ 139 enum class CreateScreenState { 140 PASSKEY_INTRO, 141 MORE_ABOUT_PASSKEYS_INTRO, 142 CREATION_OPTION_SELECTION, 143 MORE_OPTIONS_SELECTION, 144 DEFAULT_PROVIDER_CONFIRMATION, 145 EXTERNAL_ONLY_SELECTION, 146 } 147