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