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.ui; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SuppressLint; 23 import android.annotation.TestApi; 24 import android.app.slice.Slice; 25 import android.content.Intent; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 29 import com.android.internal.util.AnnotationValidations; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 34 /** 35 * An authentication entry. 36 * 37 * @hide 38 */ 39 @TestApi 40 public final class AuthenticationEntry implements Parcelable { 41 @NonNull private final String mKey; 42 @NonNull private final String mSubkey; 43 @NonNull private final @Status int mStatus; 44 @Nullable private Intent mFrameworkExtrasIntent; 45 @NonNull private final Slice mSlice; 46 47 /** @hide **/ 48 @IntDef(prefix = {"STATUS_"}, value = { 49 STATUS_LOCKED, 50 STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT, 51 STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT, 52 }) 53 @Retention(RetentionPolicy.SOURCE) 54 public @interface Status {} 55 56 /** This entry is still locked, as initially supplied by the provider. */ 57 public static final int STATUS_LOCKED = 0; 58 /** This entry was unlocked but didn't contain any credential. Meanwhile, "less recent" means 59 * there is another such entry that was unlocked more recently. */ 60 public static final int STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT = 1; 61 /** This is the most recent entry that was unlocked but didn't contain any credential. 62 * There should be at most one authentication entry with this status. */ 63 public static final int STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT = 2; 64 AuthenticationEntry(@onNull Parcel in)65 private AuthenticationEntry(@NonNull Parcel in) { 66 mKey = in.readString8(); 67 mSubkey = in.readString8(); 68 mStatus = in.readInt(); 69 mSlice = in.readTypedObject(Slice.CREATOR); 70 mFrameworkExtrasIntent = in.readTypedObject(Intent.CREATOR); 71 72 AnnotationValidations.validate(NonNull.class, null, mKey); 73 AnnotationValidations.validate(NonNull.class, null, mSubkey); 74 AnnotationValidations.validate(NonNull.class, null, mSlice); 75 } 76 77 /** Constructor to be used for an entry that does not require further activities 78 * to be invoked when selected. 79 */ AuthenticationEntry(@onNull String key, @NonNull String subkey, @NonNull Slice slice, @Status int status)80 public AuthenticationEntry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice, 81 @Status int status) { 82 mKey = key; 83 mSubkey = subkey; 84 mSlice = slice; 85 mStatus = status; 86 } 87 88 /** Constructor to be used for an entry that requires a pending intent to be invoked 89 * when clicked. 90 */ AuthenticationEntry(@onNull String key, @NonNull String subkey, @NonNull Slice slice, @Status int status, @NonNull Intent intent)91 public AuthenticationEntry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice, 92 @Status int status, @NonNull Intent intent) { 93 this(key, subkey, slice, status); 94 mFrameworkExtrasIntent = intent; 95 } 96 97 /** 98 * Returns the identifier of this entry that's unique within the context of the CredentialManager 99 * request. 100 */ 101 @NonNull getKey()102 public String getKey() { 103 return mKey; 104 } 105 106 /** 107 * Returns the sub-identifier of this entry that's unique within the context of the {@code key}. 108 */ 109 @NonNull getSubkey()110 public String getSubkey() { 111 return mSubkey; 112 } 113 114 /** 115 * Returns the Slice to be rendered. 116 */ 117 @NonNull getSlice()118 public Slice getSlice() { 119 return mSlice; 120 } 121 122 /** 123 * Returns the entry status. 124 */ 125 @NonNull 126 @Status getStatus()127 public int getStatus() { 128 return mStatus; 129 } 130 131 @Nullable 132 @SuppressLint("IntentBuilderName") // Not building a new intent. getFrameworkExtrasIntent()133 public Intent getFrameworkExtrasIntent() { 134 return mFrameworkExtrasIntent; 135 } 136 137 @Override writeToParcel(@onNull Parcel dest, int flags)138 public void writeToParcel(@NonNull Parcel dest, int flags) { 139 dest.writeString8(mKey); 140 dest.writeString8(mSubkey); 141 dest.writeInt(mStatus); 142 dest.writeTypedObject(mSlice, flags); 143 dest.writeTypedObject(mFrameworkExtrasIntent, flags); 144 } 145 146 @Override describeContents()147 public int describeContents() { 148 return 0; 149 } 150 151 public static final @NonNull Creator<AuthenticationEntry> CREATOR = new Creator<>() { 152 @Override 153 public AuthenticationEntry createFromParcel(@NonNull Parcel in) { 154 return new AuthenticationEntry(in); 155 } 156 157 @Override 158 public AuthenticationEntry[] newArray(int size) { 159 return new AuthenticationEntry[size]; 160 } 161 }; 162 } 163