1+ /*
2+ * Copyright 2016 Google Inc. All Rights Reserved.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+ * in compliance with the License. You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software distributed under the
10+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+ * express or implied. See the License for the specific language governing permissions and
12+ * limitations under the License.
13+ */
14+ package com.firebase.ui.auth.ui.email
15+
16+ import android.app.AlertDialog
17+ import android.content.Context
18+ import android.content.Intent
19+ import android.os.Bundle
20+ import androidx.annotation.NonNull
21+ import androidx.annotation.Nullable
22+ import androidx.annotation.RestrictTo
23+ import androidx.lifecycle.ViewModelProvider
24+ import com.firebase.ui.auth.ErrorCodes
25+ import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException
26+ import com.firebase.ui.auth.FirebaseUiException
27+ import com.firebase.ui.auth.IdpResponse
28+ import com.firebase.ui.auth.R
29+ import com.firebase.ui.auth.data.model.FlowParameters
30+ import com.firebase.ui.auth.data.model.UserCancellationException
31+ import com.firebase.ui.auth.ui.InvisibleActivityBase
32+ import com.firebase.ui.auth.util.ExtraConstants
33+ import com.firebase.ui.auth.viewmodel.RequestCodes
34+ import com.firebase.ui.auth.viewmodel.ResourceObserver
35+ import com.firebase.ui.auth.viewmodel.email.EmailLinkSignInHandler
36+ import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException
37+
38+ // Assuming EmailLinkErrorRecoveryActivity exists in your project.
39+ import com.firebase.ui.auth.ui.email.EmailLinkErrorRecoveryActivity
40+
41+ @RestrictTo(RestrictTo .Scope .LIBRARY_GROUP )
42+ class EmailLinkCatcherActivity : InvisibleActivityBase () {
43+
44+ private lateinit var mHandler: EmailLinkSignInHandler
45+
46+ companion object {
47+ @JvmStatic
48+ fun createIntent (context : Context , flowParams : FlowParameters ): Intent {
49+ return createBaseIntent(context, EmailLinkCatcherActivity ::class .java, flowParams)
50+ }
51+ }
52+
53+ override fun onCreate (@Nullable savedInstanceState : Bundle ? ) {
54+ super .onCreate(savedInstanceState)
55+
56+ initHandler()
57+
58+ if (getFlowParams().emailLink != null ) {
59+ mHandler.startSignIn()
60+ }
61+ }
62+
63+ private fun initHandler () {
64+ mHandler = ViewModelProvider (this ).get(EmailLinkSignInHandler ::class .java)
65+ mHandler.init (getFlowParams())
66+ mHandler.operation.observe(this , object : ResourceObserver <IdpResponse >(this ) {
67+ override fun onSuccess (@NonNull response : IdpResponse ) {
68+ finish(RESULT_OK , response.toIntent())
69+ }
70+
71+ override fun onFailure (@NonNull e : Exception ) {
72+ when {
73+ e is UserCancellationException -> finish(RESULT_CANCELED , null )
74+ e is FirebaseAuthAnonymousUpgradeException -> {
75+ val res = e.response
76+ finish(RESULT_CANCELED , Intent ().putExtra(ExtraConstants .IDP_RESPONSE , res))
77+ }
78+ e is FirebaseUiException -> {
79+ val errorCode = e.errorCode
80+ when (errorCode) {
81+ ErrorCodes .EMAIL_LINK_WRONG_DEVICE_ERROR ,
82+ ErrorCodes .INVALID_EMAIL_LINK_ERROR ,
83+ ErrorCodes .EMAIL_LINK_DIFFERENT_ANONYMOUS_USER_ERROR ->
84+ buildAlertDialog(errorCode).show()
85+ ErrorCodes .EMAIL_LINK_PROMPT_FOR_EMAIL_ERROR ,
86+ ErrorCodes .EMAIL_MISMATCH_ERROR ->
87+ startErrorRecoveryFlow(RequestCodes .EMAIL_LINK_PROMPT_FOR_EMAIL_FLOW )
88+ ErrorCodes .EMAIL_LINK_CROSS_DEVICE_LINKING_ERROR ->
89+ startErrorRecoveryFlow(RequestCodes .EMAIL_LINK_CROSS_DEVICE_LINKING_FLOW )
90+ else -> finish(RESULT_CANCELED , IdpResponse .getErrorIntent(e))
91+ }
92+ }
93+ e is FirebaseAuthInvalidCredentialsException ->
94+ startErrorRecoveryFlow(RequestCodes .EMAIL_LINK_PROMPT_FOR_EMAIL_FLOW )
95+ else -> finish(RESULT_CANCELED , IdpResponse .getErrorIntent(e))
96+ }
97+ }
98+ })
99+ }
100+
101+ /* *
102+ * @param flow must be one of RequestCodes.EMAIL_LINK_PROMPT_FOR_EMAIL_FLOW or
103+ * RequestCodes.EMAIL_LINK_CROSS_DEVICE_LINKING_FLOW
104+ */
105+ private fun startErrorRecoveryFlow (flow : Int ) {
106+ if (flow != RequestCodes .EMAIL_LINK_CROSS_DEVICE_LINKING_FLOW &&
107+ flow != RequestCodes .EMAIL_LINK_PROMPT_FOR_EMAIL_FLOW
108+ ) {
109+ throw IllegalStateException (
110+ " Invalid flow param. It must be either " +
111+ " RequestCodes.EMAIL_LINK_CROSS_DEVICE_LINKING_FLOW or " +
112+ " RequestCodes.EMAIL_LINK_PROMPT_FOR_EMAIL_FLOW"
113+ )
114+ }
115+ val intent = EmailLinkErrorRecoveryActivity .createIntent(applicationContext, getFlowParams(), flow)
116+ startActivityForResult(intent, flow)
117+ }
118+
119+ private fun buildAlertDialog (errorCode : Int ): AlertDialog {
120+ val builder = AlertDialog .Builder (this )
121+ val (titleText, messageText) = when (errorCode) {
122+ ErrorCodes .EMAIL_LINK_DIFFERENT_ANONYMOUS_USER_ERROR -> Pair (
123+ getString(R .string.fui_email_link_different_anonymous_user_header),
124+ getString(R .string.fui_email_link_different_anonymous_user_message)
125+ )
126+ ErrorCodes .INVALID_EMAIL_LINK_ERROR -> Pair (
127+ getString(R .string.fui_email_link_invalid_link_header),
128+ getString(R .string.fui_email_link_invalid_link_message)
129+ )
130+ else -> Pair (
131+ getString(R .string.fui_email_link_wrong_device_header),
132+ getString(R .string.fui_email_link_wrong_device_message)
133+ )
134+ }
135+ return builder.setTitle(titleText)
136+ .setMessage(messageText)
137+ .setPositiveButton(R .string.fui_email_link_dismiss_button) { _, _ ->
138+ finish(errorCode, null )
139+ }
140+ .create()
141+ }
142+
143+ override fun onActivityResult (requestCode : Int , resultCode : Int , @Nullable data : Intent ? ) {
144+ super .onActivityResult(requestCode, resultCode, data)
145+ if (requestCode == RequestCodes .EMAIL_LINK_PROMPT_FOR_EMAIL_FLOW ||
146+ requestCode == RequestCodes .EMAIL_LINK_CROSS_DEVICE_LINKING_FLOW
147+ ) {
148+ val response = IdpResponse .fromResultIntent(data)
149+ // CheckActionCode is called before starting this flow, so we only get here
150+ // if the sign in link is valid – it can only fail by being cancelled.
151+ if (resultCode == RESULT_OK ) {
152+ finish(RESULT_OK , response?.toIntent())
153+ } else {
154+ finish(RESULT_CANCELED , null )
155+ }
156+ }
157+ }
158+ }
0 commit comments