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