1 /*
2  * Copyright (C) 2023 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 android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.TestApi;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.pm.ServiceInfo;
26 import android.credentials.flags.Flags;
27 import android.graphics.drawable.Drawable;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.text.TextUtils;
31 
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.List;
35 
36 /**
37  * {@link ServiceInfo} and meta-data about a credential provider.
38  *
39  * @hide
40  */
41 @TestApi
42 public final class CredentialProviderInfo implements Parcelable {
43     @NonNull private final ServiceInfo mServiceInfo;
44     @NonNull private final List<String> mCapabilities = new ArrayList<>();
45     @Nullable private final CharSequence mOverrideLabel;
46     @Nullable private CharSequence mSettingsSubtitle = null;
47     @Nullable private CharSequence mSettingsActivity = null;
48     private final boolean mIsSystemProvider;
49     private final boolean mIsEnabled;
50     private final boolean mIsPrimary;
51 
52     /**
53      * Constructs an information instance of the credential provider.
54      *
55      * @param builder the builder object.
56      */
CredentialProviderInfo(@onNull Builder builder)57     private CredentialProviderInfo(@NonNull Builder builder) {
58         mServiceInfo = builder.mServiceInfo;
59         mCapabilities.addAll(builder.mCapabilities);
60         mIsSystemProvider = builder.mIsSystemProvider;
61         mSettingsSubtitle = builder.mSettingsSubtitle;
62         mIsEnabled = builder.mIsEnabled;
63         mIsPrimary = builder.mIsPrimary;
64         mOverrideLabel = builder.mOverrideLabel;
65         mSettingsActivity = builder.mSettingsActivity;
66     }
67 
68     /** Returns true if the service supports the given {@code credentialType}, false otherwise. */
69     @NonNull
hasCapability(@onNull String credentialType)70     public boolean hasCapability(@NonNull String credentialType) {
71         return mCapabilities.contains(credentialType);
72     }
73 
74     /** Returns the service info. */
75     @NonNull
getServiceInfo()76     public ServiceInfo getServiceInfo() {
77         return mServiceInfo;
78     }
79 
80     /** Returns whether it is a system provider. */
isSystemProvider()81     public boolean isSystemProvider() {
82         return mIsSystemProvider;
83     }
84 
85     /** Returns the service icon. */
86     @Nullable
getServiceIcon(@onNull Context context)87     public Drawable getServiceIcon(@NonNull Context context) {
88         return mServiceInfo.loadIcon(context.getPackageManager());
89     }
90 
91     /** Returns the service label. */
92     @Nullable
getLabel(@onNull Context context)93     public CharSequence getLabel(@NonNull Context context) {
94         if (mOverrideLabel != null) {
95             return mOverrideLabel;
96         }
97         return mServiceInfo.loadSafeLabel(context.getPackageManager());
98     }
99 
100     /** Returns a list of capabilities this provider service can support. */
101     @NonNull
getCapabilities()102     public List<String> getCapabilities() {
103         return Collections.unmodifiableList(mCapabilities);
104     }
105 
106     /** Returns whether the provider is enabled by the user. */
isEnabled()107     public boolean isEnabled() {
108         return mIsEnabled;
109     }
110 
111     /** Returns whether the provider is set as primary by the user. */
isPrimary()112     public boolean isPrimary() {
113         return mIsPrimary;
114     }
115 
116     /** Returns the settings subtitle. */
117     @Nullable
getSettingsSubtitle()118     public CharSequence getSettingsSubtitle() {
119         return mSettingsSubtitle;
120     }
121 
122     /**
123      * Returns the settings activity.
124      *
125      * @hide
126      */
127     @Nullable
128     @TestApi
129     @FlaggedApi(Flags.FLAG_SETTINGS_ACTIVITY_ENABLED)
getSettingsActivity()130     public CharSequence getSettingsActivity() {
131         // Add a manual check to make sure this returns null if
132         // the flag is not enabled.
133         if (!Flags.settingsActivityEnabled()) {
134             return null;
135         }
136         return mSettingsActivity;
137     }
138 
139     /** Returns the component name for the service. */
140     @NonNull
getComponentName()141     public ComponentName getComponentName() {
142         return mServiceInfo.getComponentName();
143     }
144 
145     @Override
writeToParcel(@onNull Parcel dest, int flags)146     public void writeToParcel(@NonNull Parcel dest, int flags) {
147         dest.writeTypedObject(mServiceInfo, flags);
148         dest.writeBoolean(mIsSystemProvider);
149         dest.writeStringList(mCapabilities);
150         dest.writeBoolean(mIsEnabled);
151         dest.writeBoolean(mIsPrimary);
152         TextUtils.writeToParcel(mOverrideLabel, dest, flags);
153         TextUtils.writeToParcel(mSettingsSubtitle, dest, flags);
154         TextUtils.writeToParcel(mSettingsActivity, dest, flags);
155     }
156 
157     @Override
describeContents()158     public int describeContents() {
159         return 0;
160     }
161 
162     @Override
toString()163     public String toString() {
164         return "CredentialProviderInfo {"
165                 + "serviceInfo="
166                 + mServiceInfo
167                 + ", "
168                 + "isSystemProvider="
169                 + mIsSystemProvider
170                 + ", "
171                 + "isEnabled="
172                 + mIsEnabled
173                 + ", "
174                 + "isPrimary="
175                 + mIsPrimary
176                 + ", "
177                 + "overrideLabel="
178                 + mOverrideLabel
179                 + ", "
180                 + "settingsSubtitle="
181                 + mSettingsSubtitle
182                 + ", "
183                 + "settingsActivity="
184                 + mSettingsActivity
185                 + ", "
186                 + "capabilities="
187                 + String.join(",", mCapabilities)
188                 + "}";
189     }
190 
CredentialProviderInfo(@onNull Parcel in)191     private CredentialProviderInfo(@NonNull Parcel in) {
192         mServiceInfo = in.readTypedObject(ServiceInfo.CREATOR);
193         mIsSystemProvider = in.readBoolean();
194         in.readStringList(mCapabilities);
195         mIsEnabled = in.readBoolean();
196         mIsPrimary = in.readBoolean();
197         mOverrideLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
198         mSettingsSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
199         mSettingsActivity = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
200     }
201 
202     public static final @NonNull Parcelable.Creator<CredentialProviderInfo> CREATOR =
203             new Parcelable.Creator<CredentialProviderInfo>() {
204                 @Override
205                 public CredentialProviderInfo[] newArray(int size) {
206                     return new CredentialProviderInfo[size];
207                 }
208 
209                 @Override
210                 public CredentialProviderInfo createFromParcel(@NonNull Parcel in) {
211                     return new CredentialProviderInfo(in);
212                 }
213             };
214 
215     /** A builder for {@link CredentialProviderInfo} objects. */
216     public static final class Builder {
217 
218         @NonNull private ServiceInfo mServiceInfo;
219         @NonNull private List<String> mCapabilities = new ArrayList<>();
220         private boolean mIsSystemProvider = false;
221         @Nullable private CharSequence mSettingsSubtitle = null;
222         @Nullable private CharSequence mSettingsActivity = null;
223         private boolean mIsEnabled = false;
224         private boolean mIsPrimary = false;
225         @Nullable private CharSequence mOverrideLabel = null;
226 
227         /**
228          * Creates a new builder.
229          *
230          * @param serviceInfo the service info of the credential provider service.
231          */
Builder(@onNull ServiceInfo serviceInfo)232         public Builder(@NonNull ServiceInfo serviceInfo) {
233             mServiceInfo = serviceInfo;
234         }
235 
236         /** Sets whether it is a system provider. */
setSystemProvider(boolean isSystemProvider)237         public @NonNull Builder setSystemProvider(boolean isSystemProvider) {
238             mIsSystemProvider = isSystemProvider;
239             return this;
240         }
241 
242         /**
243          * Sets the label to be used instead of getting from the system (for unit tests).
244          *
245          * @hide
246          */
setOverrideLabel(@onNull CharSequence overrideLabel)247         public @NonNull Builder setOverrideLabel(@NonNull CharSequence overrideLabel) {
248             mOverrideLabel = overrideLabel;
249             return this;
250         }
251 
252         /** Sets the settings subtitle. */
setSettingsSubtitle(@ullable CharSequence settingsSubtitle)253         public @NonNull Builder setSettingsSubtitle(@Nullable CharSequence settingsSubtitle) {
254             mSettingsSubtitle = settingsSubtitle;
255             return this;
256         }
257 
258         /**
259          * Sets the settings activity.
260          *
261          * @hide
262          */
setSettingsActivity(@ullable CharSequence settingsActivity)263         public @NonNull Builder setSettingsActivity(@Nullable CharSequence settingsActivity) {
264             mSettingsActivity = settingsActivity;
265             return this;
266         }
267 
268         /** Sets a list of capabilities this provider service can support. */
addCapabilities(@onNull List<String> capabilities)269         public @NonNull Builder addCapabilities(@NonNull List<String> capabilities) {
270             mCapabilities.addAll(capabilities);
271             return this;
272         }
273 
274         /** Sets whether it is enabled by the user. */
setEnabled(boolean isEnabled)275         public @NonNull Builder setEnabled(boolean isEnabled) {
276             mIsEnabled = isEnabled;
277             return this;
278         }
279 
280         /**
281          * Sets whether it is set as primary by the user.
282          *
283          * <p>Primary provider will be used for saving credentials by default. In most cases, there
284          * should only one primary provider exist. However, if there are multiple credential
285          * providers exist in the same package, all of them will be marked as primary.
286          *
287          * @hide
288          */
setPrimary(boolean isPrimary)289         public @NonNull Builder setPrimary(boolean isPrimary) {
290             mIsPrimary = isPrimary;
291             return this;
292         }
293 
294         /** Builds a new {@link CredentialProviderInfo} instance. */
build()295         public @NonNull CredentialProviderInfo build() {
296             return new CredentialProviderInfo(this);
297         }
298     }
299 }
300