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
isFlowAutoSelectablenull37 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
hasContentToDisplaynull51 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