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 androidx.credentials.exceptions
18 
19 import android.os.Bundle
20 import androidx.annotation.RestrictTo
21 import androidx.credentials.CredentialManager
22 import androidx.credentials.internal.toJetpackGetException
23 
24 /**
25  * Represents an error thrown during a get flow with Credential Manager. See [CredentialManager] for
26  * more details on how Exceptions work for Credential Manager flows.
27  *
28  * @see CredentialManager
29  * @see GetCredentialUnknownException
30  * @see GetCredentialCancellationException
31  * @see GetCredentialInterruptedException
32  */
33 abstract class GetCredentialException
34 @JvmOverloads
35 internal constructor(
36     @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) open val type: String,
37     @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) open val errorMessage: CharSequence? = null
38 ) : Exception(errorMessage?.toString()) {
39     companion object {
40         private const val EXTRA_GET_CREDENTIAL_EXCEPTION_TYPE =
41             "androidx.credentials.provider.extra.CREATE_CREDENTIAL_EXCEPTION_TYPE"
42         private const val EXTRA_GET_CREDENTIAL_EXCEPTION_MESSAGE =
43             "androidx.credentials.provider.extra.CREATE_CREDENTIAL_EXCEPTION_MESSAGE"
44 
45         /**
46          * Helper method to convert the given [ex] to a parcelable [Bundle], in case the instance
47          * needs to be sent across a process. Consumers of this method should use [fromBundle] to
48          * reconstruct the class instance back from the bundle returned here.
49          */
50         @JvmStatic
asBundlenull51         fun asBundle(ex: GetCredentialException): Bundle {
52             val bundle = Bundle()
53             bundle.putString(EXTRA_GET_CREDENTIAL_EXCEPTION_TYPE, ex.type)
54             ex.errorMessage?.let {
55                 bundle.putCharSequence(EXTRA_GET_CREDENTIAL_EXCEPTION_MESSAGE, it)
56             }
57             return bundle
58         }
59 
60         /**
61          * Helper method to convert a [Bundle] retrieved through [asBundle], back to an instance of
62          * [GetCredentialException].
63          *
64          * Throws [IllegalArgumentException] if the conversion fails. This means that the given
65          * [bundle] does not contain a `GetCredentialException`. The bundle should be constructed
66          * and retrieved from [asBundle] itself and never be created from scratch to avoid the
67          * failure.
68          */
69         @JvmStatic
fromBundlenull70         fun fromBundle(bundle: Bundle): GetCredentialException {
71             val type =
72                 bundle.getString(EXTRA_GET_CREDENTIAL_EXCEPTION_TYPE)
73                     ?: throw IllegalArgumentException("Bundle was missing exception type.")
74             val msg = bundle.getCharSequence(EXTRA_GET_CREDENTIAL_EXCEPTION_MESSAGE)
75             return toJetpackGetException(type, msg)
76         }
77     }
78 }
79