@@ -30,6 +30,7 @@ import com.firebase.ui.auth.util.data.PhoneNumberUtils
3030import com.firebase.ui.auth.util.data.ProviderAvailability
3131import com.google.firebase.FirebaseException
3232import com.google.firebase.auth.ActionCodeSettings
33+ import com.google.firebase.auth.AuthCredential
3334import com.google.firebase.auth.EmailAuthProvider
3435import com.google.firebase.auth.FacebookAuthProvider
3536import com.google.firebase.auth.FirebaseAuth
@@ -271,6 +272,24 @@ abstract class AuthProvider(open val providerId: String) {
271272
272273 private fun continueUrl (continueUrl : String , block : ContinueUrlBuilder .() -> Unit ) =
273274 ContinueUrlBuilder (continueUrl).apply (block).build()
275+
276+ /* *
277+ * An interface to wrap the static `EmailAuthProvider.getCredential` method to make it testable.
278+ * @suppress
279+ */
280+ internal interface CredentialProvider {
281+ fun getCredential (email : String , password : String ): AuthCredential
282+ }
283+
284+ /* *
285+ * The default implementation of [CredentialProvider] that calls the static method.
286+ * @suppress
287+ */
288+ internal class DefaultCredentialProvider : CredentialProvider {
289+ override fun getCredential (email : String , password : String ): AuthCredential {
290+ return EmailAuthProvider .getCredential(email, password)
291+ }
292+ }
274293 }
275294
276295 /* *
@@ -388,40 +407,99 @@ abstract class AuthProvider(open val providerId: String) {
388407 phoneNumber : String ,
389408 multiFactorSession : MultiFactorSession ? = null,
390409 forceResendingToken : PhoneAuthProvider .ForceResendingToken ? ,
391- ): VerifyPhoneNumberResult = suspendCoroutine { continuation ->
392- val options = PhoneAuthOptions .newBuilder(auth)
393- .setPhoneNumber(phoneNumber)
394- .requireSmsValidation(! isInstantVerificationEnabled)
395- .setTimeout(timeout, TimeUnit .SECONDS )
396- .setCallbacks(object : PhoneAuthProvider .OnVerificationStateChangedCallbacks () {
397- override fun onVerificationCompleted (credential : PhoneAuthCredential ) {
398- continuation.resume(VerifyPhoneNumberResult .AutoVerified (credential))
399- }
410+ verifier : Verifier = DefaultVerifier (),
411+ ): VerifyPhoneNumberResult {
412+ return verifier.verifyPhoneNumber(
413+ auth,
414+ phoneNumber,
415+ timeout,
416+ forceResendingToken,
417+ multiFactorSession,
418+ isInstantVerificationEnabled
419+ )
420+ }
400421
401- override fun onVerificationFailed (e : FirebaseException ) {
402- continuation.resumeWithException(e)
403- }
422+ /* *
423+ * @suppress
424+ */
425+ internal interface Verifier {
426+ suspend fun verifyPhoneNumber (
427+ auth : FirebaseAuth ,
428+ phoneNumber : String ,
429+ timeout : Long ,
430+ forceResendingToken : PhoneAuthProvider .ForceResendingToken ? ,
431+ multiFactorSession : MultiFactorSession ? ,
432+ isInstantVerificationEnabled : Boolean
433+ ): VerifyPhoneNumberResult
434+ }
404435
405- override fun onCodeSent (
406- verificationId : String ,
407- token : PhoneAuthProvider .ForceResendingToken ,
408- ) {
409- continuation.resume(
410- VerifyPhoneNumberResult .NeedsManualVerification (
411- verificationId,
412- token
413- )
414- )
436+ /* *
437+ * @suppress
438+ */
439+ internal class DefaultVerifier : Verifier {
440+ override suspend fun verifyPhoneNumber (
441+ auth : FirebaseAuth ,
442+ phoneNumber : String ,
443+ timeout : Long ,
444+ forceResendingToken : PhoneAuthProvider .ForceResendingToken ? ,
445+ multiFactorSession : MultiFactorSession ? ,
446+ isInstantVerificationEnabled : Boolean
447+ ): VerifyPhoneNumberResult {
448+ return suspendCoroutine { continuation ->
449+ val options = PhoneAuthOptions .newBuilder(auth)
450+ .setPhoneNumber(phoneNumber)
451+ .requireSmsValidation(! isInstantVerificationEnabled)
452+ .setTimeout(timeout, TimeUnit .SECONDS )
453+ .setCallbacks(object : PhoneAuthProvider .OnVerificationStateChangedCallbacks () {
454+ override fun onVerificationCompleted (credential : PhoneAuthCredential ) {
455+ continuation.resume(VerifyPhoneNumberResult .AutoVerified (credential))
456+ }
457+
458+ override fun onVerificationFailed (e : FirebaseException ) {
459+ continuation.resumeWithException(e)
460+ }
461+
462+ override fun onCodeSent (
463+ verificationId : String ,
464+ token : PhoneAuthProvider .ForceResendingToken ,
465+ ) {
466+ continuation.resume(
467+ VerifyPhoneNumberResult .NeedsManualVerification (
468+ verificationId,
469+ token
470+ )
471+ )
472+ }
473+ })
474+ if (forceResendingToken != null ) {
475+ options.setForceResendingToken(forceResendingToken)
415476 }
416- })
417- if (forceResendingToken != null ) {
418- options.setForceResendingToken(forceResendingToken)
477+ if (multiFactorSession != null ) {
478+ options.setMultiFactorSession(multiFactorSession)
479+ }
480+ PhoneAuthProvider .verifyPhoneNumber(options.build())
481+ }
419482 }
420- if (multiFactorSession != null ) {
421- options.setMultiFactorSession(multiFactorSession)
483+ }
484+
485+ /* *
486+ * An interface to wrap the static `PhoneAuthProvider.getCredential` method to make it testable.
487+ * @suppress
488+ */
489+ internal interface CredentialProvider {
490+ fun getCredential (verificationId : String , smsCode : String ): PhoneAuthCredential
491+ }
492+
493+ /* *
494+ * The default implementation of [CredentialProvider] that calls the static method.
495+ * @suppress
496+ */
497+ internal class DefaultCredentialProvider : CredentialProvider {
498+ override fun getCredential (verificationId : String , smsCode : String ): PhoneAuthCredential {
499+ return PhoneAuthProvider .getCredential(verificationId, smsCode)
422500 }
423- PhoneAuthProvider .verifyPhoneNumber(options.build())
424501 }
502+
425503 }
426504
427505 /* *
@@ -704,4 +782,4 @@ abstract class AuthProvider(open val providerId: String) {
704782 }
705783 }
706784 }
707- }
785+ }
0 commit comments