1 /* 2 * Copyright 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.credentials; 18 19 import static android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.app.Activity; 25 import android.app.PendingIntent; 26 import android.os.CancellationSignal; 27 import android.os.OutcomeReceiver; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 import android.util.ArraySet; 31 32 import java.util.Set; 33 import java.util.concurrent.Executor; 34 35 36 /** 37 * An internal response object that prefetches user app credentials and provides metadata about 38 * them. 39 * 40 * @hide 41 */ 42 public final class PrepareGetCredentialResponseInternal implements Parcelable { 43 private static final String TAG = "CredentialManager"; 44 45 private final boolean mHasQueryApiPermission; 46 @Nullable 47 private final ArraySet<String> mCredentialResultTypes; 48 private final boolean mHasAuthenticationResults; 49 private final boolean mHasRemoteResults; 50 /** 51 * The pending intent to be launched to finalize the user credential. If null, the callback 52 * will fail with {@link GetCredentialException#TYPE_NO_CREDENTIAL}. 53 */ 54 @Nullable 55 private final PendingIntent mPendingIntent; 56 57 @Nullable getPendingIntent()58 public PendingIntent getPendingIntent() { 59 return mPendingIntent; 60 } 61 62 /** 63 * Returns true if the user has any candidate credentials for the given {@code credentialType}, 64 * and false otherwise. 65 */ 66 @RequiresPermission(CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) hasCredentialResults(@onNull String credentialType)67 public boolean hasCredentialResults(@NonNull String credentialType) { 68 if (!mHasQueryApiPermission) { 69 throw new SecurityException( 70 "caller doesn't have the permission to query credential results"); 71 } 72 if (mCredentialResultTypes == null) { 73 return false; 74 } 75 return mCredentialResultTypes.contains(credentialType); 76 } 77 78 /** 79 * Returns true if the user has any candidate authentication actions (locked credential 80 * supplier), and false otherwise. 81 */ 82 @RequiresPermission(CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) hasAuthenticationResults()83 public boolean hasAuthenticationResults() { 84 if (!mHasQueryApiPermission) { 85 throw new SecurityException( 86 "caller doesn't have the permission to query authentication results"); 87 } 88 return mHasAuthenticationResults; 89 } 90 91 /** 92 * Returns true if the user has any candidate remote credential results, and false otherwise. 93 */ 94 @RequiresPermission(CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) hasRemoteResults()95 public boolean hasRemoteResults() { 96 if (!mHasQueryApiPermission) { 97 throw new SecurityException( 98 "caller doesn't have the permission to query remote results"); 99 } 100 return mHasRemoteResults; 101 } 102 103 @Override writeToParcel(@onNull Parcel dest, int flags)104 public void writeToParcel(@NonNull Parcel dest, int flags) { 105 dest.writeBoolean(mHasQueryApiPermission); 106 dest.writeArraySet(mCredentialResultTypes); 107 dest.writeBoolean(mHasAuthenticationResults); 108 dest.writeBoolean(mHasRemoteResults); 109 dest.writeTypedObject(mPendingIntent, flags); 110 } 111 112 @Override describeContents()113 public int describeContents() { 114 return 0; 115 } 116 117 /** 118 * Constructs a {@link PrepareGetCredentialResponseInternal}. 119 * 120 * @param hasQueryApiPermission whether caller has the permission to query the credential 121 * result metadata 122 * @param credentialResultTypes a set of credential types that each has candidate credentials 123 * found, or null if the caller doesn't have the permission to 124 * this information 125 * @param hasAuthenticationResults whether the user has any candidate authentication actions, or 126 * false if the caller doesn't have the permission to this 127 * information 128 * @param hasRemoteResults whether the user has any candidate remote options, or false 129 * if the caller doesn't have the permission to this information 130 * @param pendingIntent the pending intent to be launched during 131 * {@link #show(Activity, CancellationSignal, Executor, 132 * OutcomeReceiver)}} to 133 * finalize the user credential 134 * @hide 135 */ PrepareGetCredentialResponseInternal(boolean hasQueryApiPermission, @Nullable Set<String> credentialResultTypes, boolean hasAuthenticationResults, boolean hasRemoteResults, @Nullable PendingIntent pendingIntent)136 public PrepareGetCredentialResponseInternal(boolean hasQueryApiPermission, 137 @Nullable Set<String> credentialResultTypes, 138 boolean hasAuthenticationResults, boolean hasRemoteResults, 139 @Nullable PendingIntent pendingIntent) { 140 mHasQueryApiPermission = hasQueryApiPermission; 141 mCredentialResultTypes = new ArraySet<>(credentialResultTypes); 142 mHasAuthenticationResults = hasAuthenticationResults; 143 mHasRemoteResults = hasRemoteResults; 144 mPendingIntent = pendingIntent; 145 } 146 PrepareGetCredentialResponseInternal(@onNull Parcel in)147 private PrepareGetCredentialResponseInternal(@NonNull Parcel in) { 148 mHasQueryApiPermission = in.readBoolean(); 149 mCredentialResultTypes = (ArraySet<String>) in.readArraySet(null); 150 mHasAuthenticationResults = in.readBoolean(); 151 mHasRemoteResults = in.readBoolean(); 152 mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); 153 } 154 155 public static final @NonNull Creator<PrepareGetCredentialResponseInternal> CREATOR = 156 new Creator<>() { 157 @Override 158 public PrepareGetCredentialResponseInternal[] newArray(int size) { 159 return new PrepareGetCredentialResponseInternal[size]; 160 } 161 162 @Override 163 public PrepareGetCredentialResponseInternal createFromParcel(@NonNull Parcel in) { 164 return new PrepareGetCredentialResponseInternal(in); 165 } 166 }; 167 } 168