Merge "Add go/aster logging to CreateCredentialComponents" into udc-dev

This commit is contained in:
Harsh Lal
2023-03-07 17:47:10 +00:00
committed by Android (Google) Code Review
4 changed files with 248 additions and 82 deletions

View File

@@ -22,6 +22,7 @@ import android.util.Log
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
import androidx.activity.result.IntentSenderRequest
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
@@ -36,6 +37,8 @@ import com.android.credentialmanager.createflow.CreateCredentialUiState
import com.android.credentialmanager.createflow.CreateScreenState
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.getflow.GetScreenState
import com.android.credentialmanager.logging.UIMetrics
import com.android.internal.logging.UiEventLogger.UiEventEnum
/** One and only one of create or get state can be active at any given time. */
data class UiState(
@@ -56,6 +59,8 @@ class CredentialSelectorViewModel(
var uiState by mutableStateOf(credManRepo.initState())
private set
var uiMetrics: UIMetrics = UIMetrics()
/**************************************************************************/
/***** Shared Callbacks *****/
/**************************************************************************/
@@ -76,6 +81,10 @@ class CredentialSelectorViewModel(
fun onNewCredentialManagerRepo(credManRepo: CredentialManagerRepo) {
this.credManRepo = credManRepo
uiState = credManRepo.initState()
if (this.credManRepo.requestInfo.token != credManRepo.requestInfo.token) {
this.uiMetrics.resetInstanceId()
}
}
fun launchProviderUi(
@@ -374,4 +383,9 @@ class CredentialSelectorViewModel(
onInternalError()
}
}
@Composable
fun logUiEvent(uiEventEnum: UiEventEnum) {
this.uiMetrics.log(uiEventEnum, credManRepo.requestInfo.appPackageName)
}
}

View File

@@ -67,6 +67,8 @@ import com.android.credentialmanager.common.ui.SheetContainerCard
import com.android.credentialmanager.common.ui.PasskeyBenefitRow
import com.android.credentialmanager.common.ui.HeadlineText
import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
import com.android.credentialmanager.logging.CreateCredentialEvent
import com.android.internal.logging.UiEventLogger.UiEventEnum
@Composable
fun CreateCredentialScreen(
@@ -85,81 +87,93 @@ fun CreateCredentialScreen(
ProviderActivityState.NOT_APPLICABLE -> {
when (createCredentialUiState.currentScreenState) {
CreateScreenState.PASSKEY_INTRO -> PasskeyIntroCard(
onConfirm = viewModel::createFlowOnConfirmIntro,
onLearnMore = viewModel::createFlowOnLearnMore,
onConfirm = viewModel::createFlowOnConfirmIntro,
onLearnMore = viewModel::createFlowOnLearnMore,
onLog = { viewModel.logUiEvent(it) },
)
CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
disabledProviderList = createCredentialUiState.disabledProviders,
sortedCreateOptionsPairs =
createCredentialUiState.sortedCreateOptionsPairs,
hasRemoteEntry = createCredentialUiState.remoteEntry != null,
onOptionSelected =
viewModel::createFlowOnEntrySelectedFromFirstUseScreen,
onDisabledProvidersSelected =
viewModel::createFlowOnDisabledProvidersSelected,
onMoreOptionsSelected =
viewModel::createFlowOnMoreOptionsSelectedOnProviderSelection,
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
disabledProviderList = createCredentialUiState
.disabledProviders,
sortedCreateOptionsPairs =
createCredentialUiState.sortedCreateOptionsPairs,
hasRemoteEntry = createCredentialUiState.remoteEntry != null,
onOptionSelected =
viewModel::createFlowOnEntrySelectedFromFirstUseScreen,
onDisabledProvidersSelected =
viewModel::createFlowOnDisabledProvidersSelected,
onMoreOptionsSelected =
viewModel::createFlowOnMoreOptionsSelectedOnProviderSelection,
onLog = { viewModel.logUiEvent(it) },
)
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
providerInfo = createCredentialUiState.activeEntry?.activeProvider!!,
hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
createOptionInfo =
createCredentialUiState.activeEntry.activeEntryInfo
as CreateOptionInfo,
onOptionSelected = viewModel::createFlowOnEntrySelected,
onConfirm = viewModel::createFlowOnConfirmEntrySelected,
onMoreOptionsSelected =
viewModel::createFlowOnMoreOptionsSelectedOnCreationSelection,
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
providerInfo = createCredentialUiState
.activeEntry?.activeProvider!!,
hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
createOptionInfo =
createCredentialUiState.activeEntry.activeEntryInfo
as CreateOptionInfo,
onOptionSelected = viewModel::createFlowOnEntrySelected,
onConfirm = viewModel::createFlowOnConfirmEntrySelected,
onMoreOptionsSelected =
viewModel::createFlowOnMoreOptionsSelectedOnCreationSelection,
onLog = { viewModel.logUiEvent(it) },
)
CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
disabledProviderList = createCredentialUiState.disabledProviders,
sortedCreateOptionsPairs =
createCredentialUiState.sortedCreateOptionsPairs,
hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
isFromProviderSelection =
createCredentialUiState.isFromProviderSelection!!,
onBackProviderSelectionButtonSelected =
viewModel::createFlowOnBackProviderSelectionButtonSelected,
onBackCreationSelectionButtonSelected =
viewModel::createFlowOnBackCreationSelectionButtonSelected,
onOptionSelected =
viewModel::createFlowOnEntrySelectedFromMoreOptionScreen,
onDisabledProvidersSelected =
viewModel::createFlowOnDisabledProvidersSelected,
onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
disabledProviderList = createCredentialUiState
.disabledProviders,
sortedCreateOptionsPairs =
createCredentialUiState.sortedCreateOptionsPairs,
hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
isFromProviderSelection =
createCredentialUiState.isFromProviderSelection!!,
onBackProviderSelectionButtonSelected =
viewModel::createFlowOnBackProviderSelectionButtonSelected,
onBackCreationSelectionButtonSelected =
viewModel::createFlowOnBackCreationSelectionButtonSelected,
onOptionSelected =
viewModel::createFlowOnEntrySelectedFromMoreOptionScreen,
onDisabledProvidersSelected =
viewModel::createFlowOnDisabledProvidersSelected,
onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
onLog = { viewModel.logUiEvent(it) },
)
CreateScreenState.MORE_OPTIONS_ROW_INTRO -> {
if (createCredentialUiState.activeEntry == null) {
viewModel.onIllegalUiState("Expect active entry to be non-null" +
" upon default provider dialog.")
" upon default provider dialog.")
} else {
MoreOptionsRowIntroCard(
selectedEntry = createCredentialUiState.activeEntry,
onIllegalScreenState = viewModel::onIllegalUiState,
onChangeDefaultSelected =
viewModel::createFlowOnChangeDefaultSelected,
onUseOnceSelected = viewModel::createFlowOnUseOnceSelected,
selectedEntry = createCredentialUiState.activeEntry,
onIllegalScreenState = viewModel::onIllegalUiState,
onChangeDefaultSelected =
viewModel::createFlowOnChangeDefaultSelected,
onUseOnceSelected = viewModel::createFlowOnUseOnceSelected,
onLog = { viewModel.logUiEvent(it) },
)
}
}
CreateScreenState.EXTERNAL_ONLY_SELECTION -> ExternalOnlySelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
activeRemoteEntry =
createCredentialUiState.activeEntry?.activeEntryInfo!!,
onOptionSelected = viewModel::createFlowOnEntrySelected,
onConfirm = viewModel::createFlowOnConfirmEntrySelected,
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
activeRemoteEntry =
createCredentialUiState.activeEntry?.activeEntryInfo!!,
onOptionSelected = viewModel::createFlowOnEntrySelected,
onConfirm = viewModel::createFlowOnConfirmEntrySelected,
onLog = { viewModel.logUiEvent(it) },
)
CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO ->
MoreAboutPasskeysIntroCard(
CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO -> MoreAboutPasskeysIntroCard(
onBackPasskeyIntroButtonSelected =
viewModel::createFlowOnBackPasskeyIntroButtonSelected,
)
onLog = { viewModel.logUiEvent(it) },
)
}
viewModel.uiMetrics.log(
CreateCredentialEvent
.CREDMAN_CREATE_CRED_PROVIDER_ACTIVITY_NOT_APPLICABLE)
}
ProviderActivityState.READY_TO_LAUNCH -> {
// Launch only once per providerActivityState change so that the provider
@@ -167,9 +181,14 @@ fun CreateCredentialScreen(
LaunchedEffect(viewModel.uiState.providerActivityState) {
viewModel.launchProviderUi(providerActivityLauncher)
}
viewModel.uiMetrics.log(
CreateCredentialEvent
.CREDMAN_CREATE_CRED_PROVIDER_ACTIVITY_READY_TO_LAUNCH)
}
ProviderActivityState.PENDING -> {
// Hide our content when the provider activity is active.
viewModel.uiMetrics.log(
CreateCredentialEvent.CREDMAN_CREATE_CRED_PROVIDER_ACTIVITY_PENDING)
}
}
},
@@ -181,6 +200,7 @@ fun CreateCredentialScreen(
fun PasskeyIntroCard(
onConfirm: () -> Unit,
onLearnMore: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
item {
@@ -245,6 +265,7 @@ fun PasskeyIntroCard(
)
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_PASSKEY_INTRO)
}
@Composable
@@ -256,6 +277,7 @@ fun ProviderSelectionCard(
onOptionSelected: (ActiveEntry) -> Unit,
onDisabledProvidersSelected: () -> Unit,
onMoreOptionsSelected: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
item { HeadlineIcon(bitmap = requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()) }
@@ -319,21 +341,23 @@ fun ProviderSelectionCard(
}
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_PROVIDER_SELECTION)
}
@Composable
fun MoreOptionsSelectionCard(
requestDisplayInfo: RequestDisplayInfo,
enabledProviderList: List<EnabledProviderInfo>,
disabledProviderList: List<DisabledProviderInfo>?,
sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
hasDefaultProvider: Boolean,
isFromProviderSelection: Boolean,
onBackProviderSelectionButtonSelected: () -> Unit,
onBackCreationSelectionButtonSelected: () -> Unit,
onOptionSelected: (ActiveEntry) -> Unit,
onDisabledProvidersSelected: () -> Unit,
onRemoteEntrySelected: (BaseEntry) -> Unit,
requestDisplayInfo: RequestDisplayInfo,
enabledProviderList: List<EnabledProviderInfo>,
disabledProviderList: List<DisabledProviderInfo>?,
sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
hasDefaultProvider: Boolean,
isFromProviderSelection: Boolean,
onBackProviderSelectionButtonSelected: () -> Unit,
onBackCreationSelectionButtonSelected: () -> Unit,
onOptionSelected: (ActiveEntry) -> Unit,
onDisabledProvidersSelected: () -> Unit,
onRemoteEntrySelected: (BaseEntry) -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard(topAppBar = {
MoreOptionTopAppBar(
@@ -394,14 +418,16 @@ fun MoreOptionsSelectionCard(
}
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_MORE_OPTIONS_SELECTION)
}
@Composable
fun MoreOptionsRowIntroCard(
selectedEntry: ActiveEntry,
onIllegalScreenState: (String) -> Unit,
onChangeDefaultSelected: () -> Unit,
onUseOnceSelected: () -> Unit,
selectedEntry: ActiveEntry,
onIllegalScreenState: (String) -> Unit,
onChangeDefaultSelected: () -> Unit,
onUseOnceSelected: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
val entryInfo = selectedEntry.activeEntryInfo
if (entryInfo !is CreateOptionInfo) {
@@ -440,18 +466,20 @@ fun MoreOptionsRowIntroCard(
)
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_MORE_OPTIONS_ROW_INTRO)
}
@Composable
fun CreationSelectionCard(
requestDisplayInfo: RequestDisplayInfo,
enabledProviderList: List<EnabledProviderInfo>,
providerInfo: EnabledProviderInfo,
createOptionInfo: CreateOptionInfo,
onOptionSelected: (BaseEntry) -> Unit,
onConfirm: () -> Unit,
onMoreOptionsSelected: () -> Unit,
hasDefaultProvider: Boolean,
requestDisplayInfo: RequestDisplayInfo,
enabledProviderList: List<EnabledProviderInfo>,
providerInfo: EnabledProviderInfo,
createOptionInfo: CreateOptionInfo,
onOptionSelected: (BaseEntry) -> Unit,
onConfirm: () -> Unit,
onMoreOptionsSelected: () -> Unit,
hasDefaultProvider: Boolean,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
item {
@@ -537,14 +565,16 @@ fun CreationSelectionCard(
item { BodySmallText(text = createOptionInfo.footerDescription) }
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_CREATION_OPTION_SELECTION)
}
@Composable
fun ExternalOnlySelectionCard(
requestDisplayInfo: RequestDisplayInfo,
activeRemoteEntry: BaseEntry,
onOptionSelected: (BaseEntry) -> Unit,
onConfirm: () -> Unit,
requestDisplayInfo: RequestDisplayInfo,
activeRemoteEntry: BaseEntry,
onOptionSelected: (BaseEntry) -> Unit,
onConfirm: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
item { HeadlineIcon(imageVector = Icons.Outlined.QrCodeScanner) }
@@ -572,11 +602,13 @@ fun ExternalOnlySelectionCard(
)
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_EXTERNAL_ONLY_SELECTION)
}
@Composable
fun MoreAboutPasskeysIntroCard(
onBackPasskeyIntroButtonSelected: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard(
topAppBar = {
@@ -612,6 +644,7 @@ fun MoreAboutPasskeysIntroCard(
BodyMediumText(text = stringResource(R.string.seamless_transition_detail))
}
}
onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_MORE_ABOUT_PASSKEYS_INTRO)
}
@Composable

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2023 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.logging
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
enum class CreateCredentialEvent(private val id: Int) : UiEventLogger.UiEventEnum {
@UiEvent(doc = "The create credential bottomsheet became visible on the screen.")
CREDMAN_CREATE_CRED_BOTTOMSHEET(1318),
@UiEvent(doc = "The provider activity is launched on the screen.")
CREDMAN_CREATE_CRED_PROVIDER_ACTIVITY_READY_TO_LAUNCH(1319),
@UiEvent(doc = "The provider activity is launched and we are waiting for its result. " +
"Contents Hidden.")
CREDMAN_CREATE_CRED_PROVIDER_ACTIVITY_PENDING(1320),
@UiEvent(doc = "The provider activity is not active or ready launched on the screen.")
CREDMAN_CREATE_CRED_PROVIDER_ACTIVITY_NOT_APPLICABLE(1321),
@UiEvent(doc = "The passkey introduction card is visible on screen.")
CREDMAN_CREATE_CRED_PASSKEY_INTRO(1322),
@UiEvent(doc = "The provider selection card is visible on screen.")
CREDMAN_CREATE_CRED_PROVIDER_SELECTION(1323),
@UiEvent(doc = "The creation option selection card is visible on screen.")
CREDMAN_CREATE_CRED_CREATION_OPTION_SELECTION(1324),
@UiEvent(doc = "The more option selection card is visible on screen.")
CREDMAN_CREATE_CRED_MORE_OPTIONS_SELECTION(1325),
@UiEvent(doc = "The more options row intro card is visible on screen.")
CREDMAN_CREATE_CRED_MORE_OPTIONS_ROW_INTRO(1326),
@UiEvent(doc = "The external only selection card is visible on screen.")
CREDMAN_CREATE_CRED_EXTERNAL_ONLY_SELECTION(1327),
@UiEvent(doc = "The more about passkeys intro card is visible on screen.")
CREDMAN_CREATE_CRED_MORE_ABOUT_PASSKEYS_INTRO(1328);
override fun getId(): Int {
return this.id
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2023 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.logging
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.UiEventLoggerImpl
class UIMetrics() {
private val INSTANCE_ID_MAX = 1 shl 20
private val mUiEventLogger: UiEventLogger = UiEventLoggerImpl()
val mInstanceIdSequence: InstanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
var mInstanceId: InstanceId = mInstanceIdSequence.newInstanceId()
fun resetInstanceId() {
this.mInstanceId = mInstanceIdSequence.newInstanceId()
}
@Composable
fun log(event: UiEventLogger.UiEventEnum) {
val instanceId: InstanceId = mInstanceId
LaunchedEffect(true) {
mUiEventLogger.log(event, instanceId)
}
}
@Composable
fun log(event: UiEventLogger.UiEventEnum, packageName: String) {
val instanceId: InstanceId = mInstanceId
LaunchedEffect(true) {
mUiEventLogger.logWithInstanceId(event, /*uid=*/0, packageName, instanceId)
}
}
@Composable
fun log(event: UiEventLogger.UiEventEnum, instanceId: InstanceId, packageName: String) {
LaunchedEffect(true) {
mUiEventLogger.logWithInstanceId(event, /*uid=*/0, packageName, instanceId)
}
}
}