| /* |
| * Copyright 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.credentials |
| |
| import android.content.ComponentName |
| import android.os.Bundle |
| import androidx.annotation.RestrictTo |
| import androidx.credentials.internal.FrameworkClassParsingException |
| |
| /** |
| * Encapsulates a request to get a user credential. |
| * |
| * An application can construct such a request by adding one or more types of [CredentialOption], |
| * and then call [CredentialManager.getCredential] to launch framework UI flows to allow the user to |
| * consent to using a previously saved credential for the given application. |
| * |
| * @param credentialOptions the list of [CredentialOption] from which the user can choose one to |
| * authenticate to the app |
| * @param origin the origin of a different application if the request is being made on behalf of |
| * that application (Note: for API level >=34, setting a non-null value for this parameter, will |
| * throw a SecurityException if android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present) |
| * @param preferIdentityDocUi the value which signals if the UI should be tailored to display an |
| * identity document like driver license etc |
| * @param preferUiBrandingComponentName a service [ComponentName] from which the Credential Selector |
| * UI will pull its label and icon to render top level branding (Note: your app must have the |
| * permission android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS to specify this, or it |
| * would not take effect; also this bit may not take effect for Android API level 33 and below, |
| * depending on the pre-34 provider(s) you have chosen |
| * @param preferImmediatelyAvailableCredentials true if you prefer the operation to return |
| * immediately when there is no available credentials instead of falling back to discovering |
| * remote options, and false (default) otherwise |
| * @property credentialOptions the list of [CredentialOption] from which the user can choose one to |
| * authenticate to the app |
| * @property origin the origin of a different application if the request is being made on behalf of |
| * that application. For API level >=34, setting a non-null value for this parameter, will throw a |
| * SecurityException if android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not present. |
| * @property preferIdentityDocUi the value which signals if the UI should be tailored to display an |
| * identity document like driver license etc. |
| * @property preferUiBrandingComponentName a service [ComponentName] from which the Credential |
| * Selector UI will pull its label and icon to render top level branding. Your app must have the |
| * permission android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS to specify this, or it |
| * would not take effect. Notice that this bit may not take effect for Android API level 33 and |
| * below, depending on the pre-34 provider(s) you have chosen. |
| * @property preferImmediatelyAvailableCredentials true if you prefer the operation to return |
| * immediately when there is no available credentials instead of falling back to discovering |
| * remote options, and false (default) otherwise |
| * @throws IllegalArgumentException If [credentialOptions] is empty or contains |
| * [GetRestoreCredentialOption] with another option (i.e. [GetPasswordOption] or |
| * [GetPublicKeyCredentialOption]). |
| */ |
| class GetCredentialRequest |
| @JvmOverloads |
| constructor( |
| val credentialOptions: List<CredentialOption>, |
| val origin: String? = null, |
| val preferIdentityDocUi: Boolean = false, |
| val preferUiBrandingComponentName: ComponentName? = null, |
| @get:JvmName("preferImmediatelyAvailableCredentials") |
| val preferImmediatelyAvailableCredentials: Boolean = false, |
| ) { |
| |
| init { |
| require(credentialOptions.isNotEmpty()) { "credentialOptions should not be empty" } |
| if (credentialOptions.size > 1) { |
| for (option in credentialOptions) { |
| if (option is GetRestoreCredentialOption) { |
| throw IllegalArgumentException( |
| "Only a single GetRestoreCredentialOption should be provided." |
| ) |
| } |
| } |
| } |
| } |
| |
| /** A builder for [GetCredentialRequest]. */ |
| class Builder { |
| private var credentialOptions: MutableList<CredentialOption> = mutableListOf() |
| private var origin: String? = null |
| private var preferIdentityDocUi: Boolean = false |
| private var preferImmediatelyAvailableCredentials: Boolean = false |
| private var preferUiBrandingComponentName: ComponentName? = null |
| |
| /** Adds a specific type of [CredentialOption]. */ |
| fun addCredentialOption(credentialOption: CredentialOption): Builder { |
| credentialOptions.add(credentialOption) |
| return this |
| } |
| |
| /** Sets the list of [CredentialOption]. */ |
| fun setCredentialOptions(credentialOptions: List<CredentialOption>): Builder { |
| this.credentialOptions = credentialOptions.toMutableList() |
| return this |
| } |
| |
| /** |
| * Sets the [origin] of a different application if the request is being made on behalf of |
| * that application. For API level >=34, setting a non-null value for this parameter, will |
| * throw a SecurityException if android.permission.CREDENTIAL_MANAGER_SET_ORIGIN is not |
| * present. |
| */ |
| fun setOrigin(origin: String): Builder { |
| this.origin = origin |
| return this |
| } |
| |
| /** |
| * Sets whether you prefer the operation to return immediately when there is no available |
| * credentials instead of falling back to discovering remote options. The default value is |
| * false. |
| */ |
| @Suppress("MissingGetterMatchingBuilder") |
| fun setPreferImmediatelyAvailableCredentials( |
| preferImmediatelyAvailableCredentials: Boolean |
| ): Builder { |
| this.preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials |
| return this |
| } |
| |
| /** |
| * Sets service [ComponentName] from which the Credential Selector UI will pull its label |
| * and icon to render top level branding. Your app must have the permission |
| * android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS to specify this, or it would |
| * not take effect. Notice that this bit may not take effect for Android API level 33 and |
| * below, depending on the pre-34 provider(s) you have chosen. |
| */ |
| fun setPreferUiBrandingComponentName(component: ComponentName?): Builder { |
| this.preferUiBrandingComponentName = component |
| return this |
| } |
| |
| /** |
| * Sets the [Boolean] preferIdentityDocUi to true if the requester wants to prefer using a |
| * UI suited for Identity Documents like mDocs, Driving License etc. |
| */ |
| @Suppress("MissingGetterMatchingBuilder") |
| fun setPreferIdentityDocUi(preferIdentityDocUi: Boolean): Builder { |
| this.preferIdentityDocUi = preferIdentityDocUi |
| return this |
| } |
| |
| /** |
| * Builds a [GetCredentialRequest]. |
| * |
| * @throws IllegalArgumentException If [credentialOptions] is empty |
| */ |
| fun build(): GetCredentialRequest { |
| return GetCredentialRequest( |
| credentialOptions.toList(), |
| origin, |
| preferIdentityDocUi, |
| preferUiBrandingComponentName, |
| preferImmediatelyAvailableCredentials |
| ) |
| } |
| } |
| |
| internal companion object { |
| internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS = |
| "androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS" |
| private const val BUNDLE_KEY_PREFER_IDENTITY_DOC_UI = |
| "androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI" |
| private const val BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME = |
| "androidx.credentials.BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME" |
| |
| @RestrictTo(RestrictTo.Scope.LIBRARY) |
| @JvmStatic |
| fun toRequestDataBundle(request: GetCredentialRequest): Bundle { |
| val bundle = Bundle() |
| bundle.putBoolean(BUNDLE_KEY_PREFER_IDENTITY_DOC_UI, request.preferIdentityDocUi) |
| bundle.putBoolean( |
| BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS, |
| request.preferImmediatelyAvailableCredentials |
| ) |
| bundle.putParcelable( |
| BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME, |
| request.preferUiBrandingComponentName |
| ) |
| return bundle |
| } |
| |
| @RestrictTo(RestrictTo.Scope.LIBRARY) |
| @JvmStatic |
| fun createFrom( |
| credentialOptions: List<CredentialOption>, |
| origin: String?, |
| data: Bundle |
| ): GetCredentialRequest { |
| try { |
| val preferIdentityDocUi = data.getBoolean(BUNDLE_KEY_PREFER_IDENTITY_DOC_UI) |
| val preferImmediatelyAvailableCredentials = |
| data.getBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS) |
| @Suppress("DEPRECATION") |
| val preferUiBrandingComponentName = |
| data.getParcelable<ComponentName>(BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME) |
| val getCredentialBuilder = |
| Builder() |
| .setCredentialOptions(credentialOptions) |
| .setPreferIdentityDocUi(preferIdentityDocUi) |
| .setPreferUiBrandingComponentName(preferUiBrandingComponentName) |
| .setPreferImmediatelyAvailableCredentials( |
| preferImmediatelyAvailableCredentials |
| ) |
| if (origin != null) { |
| getCredentialBuilder.setOrigin(origin) |
| } |
| return getCredentialBuilder.build() |
| } catch (e: Exception) { |
| throw FrameworkClassParsingException() |
| } |
| } |
| } |
| } |