Define the UI result code and corresponding data structures.

Test: deployed locally
Bug: 247855226
Bug: 253156958
Change-Id: I489e4f44b09030bba20075eb3c174e9f5275e5ac
This commit is contained in:
Helen Qin
2022-10-21 07:06:17 +00:00
parent 43b4aab511
commit 2b2e8343c3
4 changed files with 266 additions and 40 deletions

View File

@@ -0,0 +1,123 @@
/*
* Copyright 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 android.credentials.ui;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.AnnotationValidations;
/**
* Base dialog result data.
*
* Returned for simple use cases like cancellation. Can also be subclassed when more information
* is needed, e.g. {@link UserSelectionDialogResult}.
*
* @hide
*/
public class BaseDialogResult implements Parcelable {
/** Parses and returns a BaseDialogResult from the given resultData. */
@Nullable
public static BaseDialogResult fromResultData(@NonNull Bundle resultData) {
return resultData.getParcelable(EXTRA_BASE_RESULT, BaseDialogResult.class);
}
/**
* Used for the UX to construct the {@code resultData Bundle} to send via the {@code
* ResultReceiver}.
*/
public static void addToBundle(@NonNull BaseDialogResult result, @NonNull Bundle bundle) {
bundle.putParcelable(EXTRA_BASE_RESULT, result);
}
/**
* The intent extra key for the {@code BaseDialogResult} object when the credential
* selector activity finishes.
*/
private static final String EXTRA_BASE_RESULT =
"android.credentials.ui.extra.BASE_RESULT";
/** User intentionally canceled the dialog. */
public static final int RESULT_CODE_DIALOG_CANCELED = 0;
/**
* User made a selection and the dialog finished. The user selection result is in the
* {@code resultData}.
*/
public static final int RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION = 1;
/**
* The user has acknowledged the consent page rendered for when they first used Credential
* Manager on this device.
*/
public static final int RESULT_CODE_CREDENTIAL_MANAGER_CONSENT_ACKNOWLEDGED = 2;
/**
* The user has acknowledged the consent page rendered for enabling a new provider.
* This should only happen during the first time use. The provider info is in the
* {@code resultData}.
*/
public static final int RESULT_CODE_PROVIDER_ENABLED = 3;
/**
* The user has consented to switching to a new default provider. The provider info is in the
* {@code resultData}.
*/
public static final int RESULT_CODE_DEFAULT_PROVIDER_CHANGED = 4;
@NonNull
private final IBinder mRequestToken;
public BaseDialogResult(@NonNull IBinder requestToken) {
mRequestToken = requestToken;
}
/** Returns the unique identifier for the request that launched the operation. */
@NonNull
public IBinder getRequestToken() {
return mRequestToken;
}
protected BaseDialogResult(@NonNull Parcel in) {
IBinder requestToken = in.readStrongBinder();
mRequestToken = requestToken;
AnnotationValidations.validate(NonNull.class, null, mRequestToken);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeStrongBinder(mRequestToken);
}
@Override
public int describeContents() {
return 0;
}
public static final @NonNull Creator<BaseDialogResult> CREATOR =
new Creator<BaseDialogResult>() {
@Override
public BaseDialogResult createFromParcel(@NonNull Parcel in) {
return new BaseDialogResult(in);
}
@Override
public BaseDialogResult[] newArray(int size) {
return new BaseDialogResult[size];
}
};
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 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 android.credentials.ui;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.AnnotationValidations;
/**
* Result data matching {@link BaseDialogResult#RESULT_CODE_PROVIDER_ENABLED}, or {@link
* BaseDialogResult#RESULT_CODE_DEFAULT_PROVIDER_CHANGED}.
*
* @hide
*/
public class ProviderDialogResult extends BaseDialogResult implements Parcelable {
/** Parses and returns a ProviderDialogResult from the given resultData. */
@Nullable
public static ProviderDialogResult fromResultData(@NonNull Bundle resultData) {
return resultData.getParcelable(EXTRA_PROVIDER_RESULT, ProviderDialogResult.class);
}
/**
* Used for the UX to construct the {@code resultData Bundle} to send via the {@code
* ResultReceiver}.
*/
public static void addToBundle(
@NonNull ProviderDialogResult result, @NonNull Bundle bundle) {
bundle.putParcelable(EXTRA_PROVIDER_RESULT, result);
}
/**
* The intent extra key for the {@code ProviderDialogResult} object when the credential
* selector activity finishes.
*/
private static final String EXTRA_PROVIDER_RESULT =
"android.credentials.ui.extra.PROVIDER_RESULT";
@NonNull
private final String mProviderId;
public ProviderDialogResult(@NonNull IBinder requestToken, @NonNull String providerId) {
super(requestToken);
mProviderId = providerId;
}
@NonNull
public String getProviderId() {
return mProviderId;
}
protected ProviderDialogResult(@NonNull Parcel in) {
super(in);
String providerId = in.readString8();
mProviderId = providerId;
AnnotationValidations.validate(NonNull.class, null, mProviderId);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString8(mProviderId);
}
@Override
public int describeContents() {
return 0;
}
public static final @NonNull Creator<ProviderDialogResult> CREATOR =
new Creator<ProviderDialogResult>() {
@Override
public ProviderDialogResult createFromParcel(@NonNull Parcel in) {
return new ProviderDialogResult(in);
}
@Override
public ProviderDialogResult[] newArray(int size) {
return new ProviderDialogResult[size];
}
};
}

View File

@@ -17,6 +17,8 @@
package android.credentials.ui;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,24 +26,33 @@ import android.os.Parcelable;
import com.android.internal.util.AnnotationValidations;
/**
* User selection result information of a UX flow.
*
* Returned as part of the activity result intent data when the user dialog completes
* successfully.
* Result data matching {@link BaseDialogResult#RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION}.
*
* @hide
*/
public class UserSelectionResult implements Parcelable {
public class UserSelectionDialogResult extends BaseDialogResult implements Parcelable {
/** Parses and returns a UserSelectionDialogResult from the given resultData. */
@Nullable
public static UserSelectionDialogResult fromResultData(@NonNull Bundle resultData) {
return resultData.getParcelable(
EXTRA_USER_SELECTION_RESULT, UserSelectionDialogResult.class);
}
/**
* The intent extra key for the {@code UserSelectionResult} object when the credential selector
* activity finishes.
*/
public static final String EXTRA_USER_SELECTION_RESULT =
"android.credentials.ui.extra.USER_SELECTION_RESULT";
* Used for the UX to construct the {@code resultData Bundle} to send via the {@code
* ResultReceiver}.
*/
public static void addToBundle(
@NonNull UserSelectionDialogResult result, @NonNull Bundle bundle) {
bundle.putParcelable(EXTRA_USER_SELECTION_RESULT, result);
}
@NonNull
private final IBinder mRequestToken;
/**
* The intent extra key for the {@code UserSelectionDialogResult} object when the credential
* selector activity finishes.
*/
private static final String EXTRA_USER_SELECTION_RESULT =
"android.credentials.ui.extra.USER_SELECTION_RESULT";
@NonNull
private final String mProviderId;
@@ -49,19 +60,14 @@ public class UserSelectionResult implements Parcelable {
// TODO: consider switching to string or other types, depending on the service implementation.
private final int mEntryId;
public UserSelectionResult(@NonNull IBinder requestToken, @NonNull String providerId,
public UserSelectionDialogResult(
@NonNull IBinder requestToken, @NonNull String providerId,
int entryId) {
mRequestToken = requestToken;
super(requestToken);
mProviderId = providerId;
mEntryId = entryId;
}
/** Returns token of the app request that initiated this user dialog. */
@NonNull
public IBinder getRequestToken() {
return mRequestToken;
}
/** Returns provider package name whose entry was selected by the user. */
@NonNull
public String getProviderId() {
@@ -73,13 +79,11 @@ public class UserSelectionResult implements Parcelable {
return mEntryId;
}
protected UserSelectionResult(@NonNull Parcel in) {
IBinder requestToken = in.readStrongBinder();
protected UserSelectionDialogResult(@NonNull Parcel in) {
super(in);
String providerId = in.readString8();
int entryId = in.readInt();
mRequestToken = requestToken;
AnnotationValidations.validate(NonNull.class, null, mRequestToken);
mProviderId = providerId;
AnnotationValidations.validate(NonNull.class, null, mProviderId);
mEntryId = entryId;
@@ -87,7 +91,7 @@ public class UserSelectionResult implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeStrongBinder(mRequestToken);
super.writeToParcel(dest, flags);
dest.writeString8(mProviderId);
dest.writeInt(mEntryId);
}
@@ -97,16 +101,16 @@ public class UserSelectionResult implements Parcelable {
return 0;
}
public static final @NonNull Creator<UserSelectionResult> CREATOR =
new Creator<UserSelectionResult>() {
public static final @NonNull Creator<UserSelectionDialogResult> CREATOR =
new Creator<UserSelectionDialogResult>() {
@Override
public UserSelectionResult createFromParcel(@NonNull Parcel in) {
return new UserSelectionResult(in);
public UserSelectionDialogResult createFromParcel(@NonNull Parcel in) {
return new UserSelectionDialogResult(in);
}
@Override
public UserSelectionResult[] newArray(int size) {
return new UserSelectionResult[size];
public UserSelectionDialogResult[] newArray(int size) {
return new UserSelectionDialogResult[size];
}
};
}

View File

@@ -16,7 +16,6 @@
package com.android.credentialmanager
import android.app.Activity
import android.app.slice.Slice
import android.app.slice.SliceSpec
import android.content.Context
@@ -25,7 +24,8 @@ import android.credentials.ui.Constants
import android.credentials.ui.Entry
import android.credentials.ui.ProviderData
import android.credentials.ui.RequestInfo
import android.credentials.ui.UserSelectionResult
import android.credentials.ui.BaseDialogResult
import android.credentials.ui.UserSelectionDialogResult
import android.graphics.drawable.Icon
import android.os.Binder
import android.os.Bundle
@@ -67,21 +67,20 @@ class CredentialManagerRepo(
}
fun onCancel() {
resultReceiver?.send(Activity.RESULT_CANCELED, null)
val resultData = Bundle()
BaseDialogResult.addToBundle(BaseDialogResult(requestInfo.token), resultData)
resultReceiver?.send(BaseDialogResult.RESULT_CODE_DIALOG_CANCELED, resultData)
}
fun onOptionSelected(providerPackageName: String, entryId: Int) {
val userSelectionResult = UserSelectionResult(
val userSelectionDialogResult = UserSelectionDialogResult(
requestInfo.token,
providerPackageName,
entryId
)
val resultData = Bundle()
resultData.putParcelable(
UserSelectionResult.EXTRA_USER_SELECTION_RESULT,
userSelectionResult
)
resultReceiver?.send(Activity.RESULT_OK, resultData)
UserSelectionDialogResult.addToBundle(userSelectionDialogResult, resultData)
resultReceiver?.send(BaseDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION, resultData)
}
fun getCredentialInitialUiState(): GetCredentialUiState {