Define all the entry-level display info in Entry.

Note that the UI has not started using the
new jetpack entry classes (defined under
packages/CredentialManager/src/com/android/credentialmanager/jetpack).
Next, the existing *UI.kt files under
packages/CredentialManager/src/com/android/credentialmanager needs to be
removed and the UI begin adopting these new structures.

Test: deployed locally
Bug: 247855226
Bug: 253156958
Change-Id: I35c48a4a224fad019efc10b841a1910ae940185c
This commit is contained in:
Helen Qin
2022-10-21 01:54:36 +00:00
parent 937e6ea632
commit ab4b22a3b5
5 changed files with 282 additions and 5 deletions

View File

@@ -30,12 +30,39 @@ import com.android.internal.util.AnnotationValidations;
* @hide
*/
public class Entry implements Parcelable {
// TODO: move to jetpack.
// TODO: these constants should go to jetpack.
public static final String VERSION = "v1";
public static final Uri CREDENTIAL_MANAGER_ENTRY_URI = Uri.parse("credentialmanager.slice");
public static final String HINT_TITLE = "hint_title";
public static final String HINT_SUBTITLE = "hint_subtitle";
public static final String HINT_ICON = "hint_icon";
// TODO: remove these hint constants and use the credential entry & action ones defined below.
public static final String HINT_TITLE = "HINT_TITLE";
public static final String HINT_SUBTITLE = "HINT_SUBTITLE";
public static final String HINT_ICON = "HINT_ICON";
/**
* 1. CREDENTIAL ENTRY CONSTANTS
*/
// User profile picture associated with this credential entry.
public static final String HINT_PROFILE_ICON = "HINT_PROFILE_ICON";
public static final String HINT_CREDENTIAL_TYPE_ICON = "HINT_CREDENTIAL_TYPE_ICON";
// The user account name of this provider app associated with this entry.
// Note: this is independent from the request app.
public static final String HINT_USER_PROVIDER_ACCOUNT_NAME = "HINT_USER_PROVIDER_ACCOUNT_NAME";
public static final String HINT_PASSWORD_COUNT = "HINT_PASSWORD_COUNT";
public static final String HINT_PASSKEY_COUNT = "HINT_PASSKEY_COUNT";
public static final String HINT_TOTAL_CREDENTIAL_COUNT = "HINT_TOTAL_CREDENTIAL_COUNT";
public static final String HINT_LAST_USED_TIME_MILLIS = "HINT_LAST_USED_TIME_MILLIS";
/** Below are only available for get flows. */
public static final String HINT_NOTE = "HINT_NOTE";
public static final String HINT_USER_NAME = "HINT_USER_NAME";
public static final String HINT_CREDENTIAL_TYPE = "HINT_CREDENTIAL_TYPE";
public static final String HINT_PASSKEY_USER_DISPLAY_NAME = "HINT_PASSKEY_USER_DISPLAY_NAME";
public static final String HINT_PASSWORD_VALUE = "HINT_PASSWORD_VALUE";
/**
* 2. ACTION CONSTANTS
*/
public static final String HINT_ACTION_TITLE = "HINT_ACTION_TITLE";
public static final String HINT_ACTION_SUBTEXT = "HINT_ACTION_SUBTEXT";
public static final String HINT_ACTION_ICON = "HINT_ACTION_ICON";
/**
* The intent extra key for the action chip {@code Entry} list when launching the UX activities.
@@ -55,7 +82,7 @@ public class Entry implements Parcelable {
public static final String EXTRA_ENTRY_AUTHENTICATION_ACTION =
"android.credentials.ui.extra.ENTRY_AUTHENTICATION_ACTION";
// TODO: may be changed to other type depending on the service implementation.
// TODO: change to string key + string subkey.
private final int mId;
@NonNull

View File

@@ -0,0 +1,46 @@
/*
* 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.jetpack
import android.app.slice.Slice
import android.graphics.drawable.Icon
/**
* UI representation for a credential entry used during the get credential flow.
*
* TODO: move to jetpack.
*/
abstract class CredentialEntryUi(
val credentialTypeIcon: Icon,
val profileIcon: Icon?,
val lastUsedTimeMillis: Long?,
val note: CharSequence?,
) {
companion object {
fun fromSlice(slice: Slice): CredentialEntryUi {
return when (slice.spec?.type) {
TYPE_PUBLIC_KEY_CREDENTIAL -> PasskeyCredentialEntryUi.fromSlice(slice)
TYPE_PASSWORD_CREDENTIAL -> PasswordCredentialEntryUi.fromSlice(slice)
else -> throw IllegalArgumentException("Unexpected type: ${slice.spec?.type}")
}
}
const val TYPE_PUBLIC_KEY_CREDENTIAL: String =
"androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL"
const val TYPE_PASSWORD_CREDENTIAL: String = "androidx.credentials.TYPE_PASSWORD"
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.jetpack
import android.app.slice.Slice
import android.credentials.ui.Entry
import android.graphics.drawable.Icon
class PasskeyCredentialEntryUi(
val userName: CharSequence,
val userDisplayName: CharSequence?,
credentialTypeIcon: Icon,
profileIcon: Icon?,
lastUsedTimeMillis: Long?,
note: CharSequence?,
) : CredentialEntryUi(credentialTypeIcon, profileIcon, lastUsedTimeMillis, note) {
companion object {
fun fromSlice(slice: Slice): CredentialEntryUi {
var userName: CharSequence? = null
var userDisplayName: CharSequence? = null
var credentialTypeIcon: Icon? = null
var profileIcon: Icon? = null
var lastUsedTimeMillis: Long? = null
var note: CharSequence? = null
val items = slice.items
items.forEach {
if (it.hasHint(Entry.HINT_USER_NAME)) {
userName = it.text
} else if (it.hasHint(Entry.HINT_PASSKEY_USER_DISPLAY_NAME)) {
userDisplayName = it.text
} else if (it.hasHint(Entry.HINT_CREDENTIAL_TYPE_ICON)) {
credentialTypeIcon = it.icon
} else if (it.hasHint(Entry.HINT_PROFILE_ICON)) {
profileIcon = it.icon
} else if (it.hasHint(Entry.HINT_LAST_USED_TIME_MILLIS)) {
lastUsedTimeMillis = it.long
} else if (it.hasHint(Entry.HINT_NOTE)) {
note = it.text
}
}
// TODO: fail NPE more elegantly.
return PasskeyCredentialEntryUi(
userName!!, userDisplayName, credentialTypeIcon!!,
profileIcon, lastUsedTimeMillis, note,
)
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.jetpack
import android.app.slice.Slice
import android.credentials.ui.Entry
import android.graphics.drawable.Icon
/**
* UI representation for a password credential entry used during the get credential flow.
*
* TODO: move to jetpack.
*/
class PasswordCredentialEntryUi(
val userName: CharSequence,
val password: CharSequence,
credentialTypeIcon: Icon,
profileIcon: Icon?,
lastUsedTimeMillis: Long?,
note: CharSequence?,
) : CredentialEntryUi(credentialTypeIcon, profileIcon, lastUsedTimeMillis, note) {
companion object {
fun fromSlice(slice: Slice): CredentialEntryUi {
var userName: CharSequence? = null
var password: CharSequence? = null
var credentialTypeIcon: Icon? = null
var profileIcon: Icon? = null
var lastUsedTimeMillis: Long? = null
var note: CharSequence? = null
val items = slice.items
items.forEach {
if (it.hasHint(Entry.HINT_USER_NAME)) {
userName = it.text
} else if (it.hasHint(Entry.HINT_PASSWORD_VALUE)) {
password = it.text
} else if (it.hasHint(Entry.HINT_CREDENTIAL_TYPE_ICON)) {
credentialTypeIcon = it.icon
} else if (it.hasHint(Entry.HINT_PROFILE_ICON)) {
profileIcon = it.icon
} else if (it.hasHint(Entry.HINT_LAST_USED_TIME_MILLIS)) {
lastUsedTimeMillis = it.long
} else if (it.hasHint(Entry.HINT_NOTE)) {
note = it.text
}
}
// TODO: fail NPE more elegantly.
return PasswordCredentialEntryUi(
userName!!, password!!, credentialTypeIcon!!,
profileIcon, lastUsedTimeMillis, note,
)
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.jetpack
import android.app.slice.Slice
import android.credentials.ui.Entry
import android.graphics.drawable.Icon
/**
* UI representation for a save entry used during the create credential flow.
*
* TODO: move to jetpack.
*/
class SaveEntryUi(
val userProviderAccountName: CharSequence,
val credentialTypeIcon: Icon?,
val profileIcon: Icon?,
val passwordCount: Int?,
val passkeyCount: Int?,
val totalCredentialCount: Int?,
val lastUsedTimeMillis: Long?,
) {
companion object {
fun fromSlice(slice: Slice): SaveEntryUi {
var userProviderAccountName: CharSequence? = null
var credentialTypeIcon: Icon? = null
var profileIcon: Icon? = null
var passwordCount: Int? = null
var passkeyCount: Int? = null
var totalCredentialCount: Int? = null
var lastUsedTimeMillis: Long? = null
val items = slice.items
items.forEach {
if (it.hasHint(Entry.HINT_USER_PROVIDER_ACCOUNT_NAME)) {
userProviderAccountName = it.text
} else if (it.hasHint(Entry.HINT_CREDENTIAL_TYPE_ICON)) {
credentialTypeIcon = it.icon
} else if (it.hasHint(Entry.HINT_PROFILE_ICON)) {
profileIcon = it.icon
} else if (it.hasHint(Entry.HINT_PASSWORD_COUNT)) {
passwordCount = it.int
} else if (it.hasHint(Entry.HINT_PASSKEY_COUNT)) {
passkeyCount = it.int
} else if (it.hasHint(Entry.HINT_TOTAL_CREDENTIAL_COUNT)) {
totalCredentialCount = it.int
} else if (it.hasHint(Entry.HINT_LAST_USED_TIME_MILLIS)) {
lastUsedTimeMillis = it.long
}
}
// TODO: fail NPE more elegantly.
return SaveEntryUi(
userProviderAccountName!!, credentialTypeIcon, profileIcon,
passwordCount, passkeyCount, totalCredentialCount, lastUsedTimeMillis,
)
}
}
}