1 /* <lambda>null2 * Copyright 2024 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 androidx.credentials.playservices.controllers.identitycredentials.createpublickeycredential 18 19 import android.content.Context 20 import android.os.CancellationSignal 21 import androidx.credentials.CreatePublicKeyCredentialRequest 22 import androidx.credentials.CreatePublicKeyCredentialResponse 23 import androidx.credentials.CredentialManagerCallback 24 import androidx.credentials.PublicKeyCredential 25 import androidx.credentials.exceptions.CreateCredentialException 26 import androidx.credentials.exceptions.CreateCredentialUnknownException 27 import androidx.credentials.internal.toJetpackCreateException 28 import androidx.credentials.playservices.CredentialProviderPlayServicesImpl 29 import androidx.credentials.playservices.controllers.CredentialProviderController 30 import com.google.android.gms.identitycredentials.CreateCredentialRequest 31 import com.google.android.gms.identitycredentials.CreateCredentialResponse 32 import com.google.android.gms.identitycredentials.IdentityCredentialManager 33 import java.util.concurrent.Executor 34 35 /** A controller to handle the CreateCredential flow with play services. */ 36 internal class CreatePublicKeyCredentialController(private val context: Context) : 37 CredentialProviderController< 38 CreatePublicKeyCredentialRequest, 39 CreateCredentialRequest, 40 CreateCredentialResponse, 41 androidx.credentials.CreateCredentialResponse, 42 CreateCredentialException 43 >(context) { 44 45 override fun invokePlayServices( 46 request: CreatePublicKeyCredentialRequest, 47 callback: 48 CredentialManagerCallback< 49 androidx.credentials.CreateCredentialResponse, 50 CreateCredentialException 51 >, 52 executor: Executor, 53 cancellationSignal: CancellationSignal? 54 ) { 55 if (CredentialProviderPlayServicesImpl.Companion.cancellationReviewer(cancellationSignal)) { 56 return 57 } 58 59 val convertedRequest = this.convertRequestToPlayServices(request) 60 IdentityCredentialManager.Companion.getClient(context) 61 .createCredential(convertedRequest) 62 .addOnSuccessListener { 63 val createCredentialResponse: CreateCredentialResponse? = 64 it.createCredentialResponse 65 if (createCredentialResponse == null) { 66 cancelOrCallbackExceptionOrResult(cancellationSignal) { 67 executor.execute { callback.onError(CreateCredentialUnknownException()) } 68 } 69 } 70 if (createCredentialResponse != null) { 71 try { 72 val response = 73 this.convertResponseToCredentialManager(createCredentialResponse) 74 cancelOrCallbackExceptionOrResult(cancellationSignal) { 75 executor.execute { callback.onResult(response) } 76 } 77 } catch (e: Exception) { 78 cancelOrCallbackExceptionOrResult(cancellationSignal) { 79 executor.execute { 80 callback.onError(toJetpackCreateException(e.message.toString())) 81 } 82 } 83 } 84 } 85 } 86 .addOnFailureListener { e -> 87 cancelOrCallbackExceptionOrResult(cancellationSignal) { 88 executor.execute { 89 callback.onError(CreateCredentialUnknownException(e.message)) 90 } 91 } 92 } 93 } 94 95 public override fun convertRequestToPlayServices( 96 request: CreatePublicKeyCredentialRequest 97 ): CreateCredentialRequest { 98 return CreateCredentialRequest( 99 type = request.type, 100 credentialData = request.credentialData, 101 candidateQueryData = request.candidateQueryData, 102 origin = request.origin, 103 requestJson = request.requestJson, 104 resultReceiver = null 105 ) 106 } 107 108 override fun convertResponseToCredentialManager( 109 response: CreateCredentialResponse 110 ): androidx.credentials.CreateCredentialResponse { 111 when (response.type) { 112 PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> { 113 // TODO(359049355): Replace with 114 // CreatePublicKeyCredentialResponse.createFrom(response.data) after 115 // making this API public 116 try { 117 val registrationResponseJson = 118 response.data.getString( 119 "androidx.credentials.BUNDLE_KEY_REGISTRATION_RESPONSE_JSON" 120 ) 121 return CreatePublicKeyCredentialResponse(registrationResponseJson!!) 122 } catch (_: NullPointerException) { 123 throw CreateCredentialUnknownException() 124 } 125 } 126 else -> throw CreateCredentialUnknownException() 127 } 128 } 129 130 companion object { 131 /** 132 * Factory method for 133 * [androidx.credentials.playservices.controllers.identityauth.createpublickeycredential.CredentialProviderCreatePublicKeyCredentialController]. 134 * 135 * @param context the calling context for this controller 136 * @return a credential provider controller for IdentityCredentialsCreatePublicKeyCredential 137 */ 138 @JvmStatic 139 fun getInstance(context: Context): CreatePublicKeyCredentialController { 140 return CreatePublicKeyCredentialController(context) 141 } 142 } 143 } 144