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 android.service.credentials; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.PendingIntent; 24 import android.app.slice.Slice; 25 import android.credentials.GetCredentialResponse; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 29 import com.android.internal.util.Preconditions; 30 31 /** 32 * A credential entry that is to be displayed on the account selector that is presented to the 33 * user. 34 * 35 * <p>If user selects this entry, the corresponding {@link PendingIntent}, 36 * set on the {@code slice} will be invoked to launch activities that require some user engagement 37 * before getting the credential corresponding to this entry, e.g. authentication, 38 * confirmation etc. The extras associated with the resulting {@link android.app.Activity} will 39 * also contain the complete credential request containing all required parameters. This request 40 * can be retrieved against {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_REQUEST}. 41 * 42 * Once the activity fulfills the required user engagement, the {@link android.app.Activity} 43 * result should be set to {@link android.app.Activity#RESULT_OK}, and the 44 * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} must be set with a 45 * {@link GetCredentialResponse} object. 46 */ 47 public final class CredentialEntry implements Parcelable { 48 /** The request option that corresponds to this entry. **/ 49 private final @Nullable String mBeginGetCredentialOptionId; 50 51 /** The type of the credential entry to be shown on the UI. */ 52 private final @NonNull String mType; 53 54 55 /** The object containing display content to be shown along with this credential entry 56 * on the UI. */ 57 private final @NonNull Slice mSlice; 58 59 /** 60 * Creates an entry that is associated with a {@link BeginGetCredentialOption} request. 61 * Providers must use this constructor when they extend from {@link CredentialProviderService} 62 * to respond to query phase {@link CredentialProviderService#onBeginGetCredential} 63 * credential retrieval requests. 64 * 65 * @param beginGetCredentialOptionId the beginGetCredentialOptionId to be retrieved from 66 * {@link BeginGetCredentialOption#getId()} - the request option for which this CredentialEntry 67 * is being constructed This helps maintain an association 68 * such that when the user selects this entry, providers can 69 * receive the complete corresponding 70 * {@link GetCredentialRequest}. 71 * @param type the type of the credential for which this credential entry is being created 72 * @param slice the slice containing the metadata to be shown on the UI, must be constructed 73 * through the {@link androidx.credentials.provider} Jetpack library; 74 * If constructed manually, the {@code slice} object must 75 * contain the non-null properties of the 76 * {@link androidx.credentials.provider.CredentialEntry} class populated as slice 77 * items against specific hints as used in the class's {@code toSlice} method, 78 * since the Android System uses this library to parse the {@code slice} and 79 * extract the required attributes 80 * 81 * @throws IllegalArgumentException If {@code beginGetCredentialOptionId} or {@code type} 82 * is null, or empty 83 */ CredentialEntry(@onNull String beginGetCredentialOptionId, @NonNull String type, @NonNull Slice slice)84 public CredentialEntry(@NonNull String beginGetCredentialOptionId, @NonNull String type, 85 @NonNull Slice slice) { 86 mBeginGetCredentialOptionId = Preconditions.checkStringNotEmpty( 87 beginGetCredentialOptionId, "beginGetCredentialOptionId must not be " 88 + "null, or empty"); 89 mType = Preconditions.checkStringNotEmpty(type, "type must not be null, or " 90 + "empty"); 91 mSlice = requireNonNull(slice, "slice must not be null"); 92 } 93 94 /** 95 * Creates an entry that is associated with a {@link BeginGetCredentialOption} request. 96 * Providers must use this constructor when they extend from {@link CredentialProviderService} 97 * to respond to query phase {@link CredentialProviderService#onBeginGetCredential} 98 * credential retrieval requests. 99 * 100 * @param beginGetCredentialOption the request option for which this credential entry is 101 * being constructed This helps maintain an association, 102 * such that when the user selects this entry, providers 103 * can receive the complete corresponding request. 104 * @param slice the slice containing the metadata to be shown on the UI. Must be 105 * constructed through the androidx.credentials jetpack library. 106 */ CredentialEntry(@onNull BeginGetCredentialOption beginGetCredentialOption, @NonNull Slice slice)107 public CredentialEntry(@NonNull BeginGetCredentialOption beginGetCredentialOption, 108 @NonNull Slice slice) { 109 requireNonNull(beginGetCredentialOption, "beginGetCredentialOption must not" 110 + " be null"); 111 mBeginGetCredentialOptionId = Preconditions.checkStringNotEmpty( 112 beginGetCredentialOption.getId(), "Id in beginGetCredentialOption " 113 + "must not be null"); 114 mType = Preconditions.checkStringNotEmpty(beginGetCredentialOption.getType(), 115 "type in beginGetCredentialOption must not be null"); 116 mSlice = requireNonNull(slice, "slice must not be null"); 117 } 118 119 /** 120 * Creates an entry that is independent of an incoming {@link BeginGetCredentialOption} 121 * request. Providers must use this constructor for constructing entries to be registered 122 * with the framework outside of the span of an API call. 123 * 124 * @param type the type of the credential 125 * @param slice the slice containing the metadata to be shown on the UI. Must be 126 * constructed through the androidx.credentials jetpack library. 127 * 128 */ CredentialEntry(@onNull String type, @NonNull Slice slice)129 public CredentialEntry(@NonNull String type, @NonNull Slice slice) { 130 mBeginGetCredentialOptionId = null; 131 mType = requireNonNull(type, "type must not be null"); 132 mSlice = requireNonNull(slice, "slice must not be null"); 133 } 134 CredentialEntry(@onNull Parcel in)135 private CredentialEntry(@NonNull Parcel in) { 136 requireNonNull(in, "parcel must not be null"); 137 mType = in.readString8(); 138 mSlice = in.readTypedObject(Slice.CREATOR); 139 mBeginGetCredentialOptionId = in.readString8(); 140 } 141 142 @NonNull 143 public static final Creator<CredentialEntry> CREATOR = 144 new Creator<CredentialEntry>() { 145 @Override 146 public CredentialEntry createFromParcel(@NonNull Parcel in) { 147 return new CredentialEntry(in); 148 } 149 150 @Override 151 public CredentialEntry[] newArray(int size) { 152 return new CredentialEntry[size]; 153 } 154 }; 155 156 @Override describeContents()157 public int describeContents() { 158 return 0; 159 } 160 161 @Override writeToParcel(@onNull Parcel dest, int flags)162 public void writeToParcel(@NonNull Parcel dest, int flags) { 163 dest.writeString8(mType); 164 dest.writeTypedObject(mSlice, flags); 165 dest.writeString8(mBeginGetCredentialOptionId); 166 } 167 168 /** 169 * Returns the id of the {@link BeginGetCredentialOption} for which this credential 170 * entry has been constructed. 171 */ 172 @NonNull getBeginGetCredentialOptionId()173 public String getBeginGetCredentialOptionId() { 174 return mBeginGetCredentialOptionId; 175 } 176 177 /** 178 * Returns the specific credential type of the entry. 179 */ 180 @NonNull getType()181 public String getType() { 182 return mType; 183 } 184 185 /** 186 * Returns the {@link Slice} object containing UI display content to be shown for this entry. 187 */ 188 @NonNull getSlice()189 public Slice getSlice() { 190 return mSlice; 191 } 192 } 193