diff --git a/README.md b/README.md index 4844b0ee9..6ef43566a 100644 --- a/README.md +++ b/README.md @@ -48,16 +48,16 @@ libraries. ```groovy dependencies { // FirebaseUI for Firebase Realtime Database - implementation 'com.firebaseui:firebase-ui-database:6.3.0' + implementation 'com.firebaseui:firebase-ui-database:6.4.0' // FirebaseUI for Cloud Firestore - implementation 'com.firebaseui:firebase-ui-firestore:6.3.0' + implementation 'com.firebaseui:firebase-ui-firestore:6.4.0' // FirebaseUI for Firebase Auth - implementation 'com.firebaseui:firebase-ui-auth:6.3.0' + implementation 'com.firebaseui:firebase-ui-auth:6.4.0' // FirebaseUI for Cloud Storage - implementation 'com.firebaseui:firebase-ui-storage:6.3.0' + implementation 'com.firebaseui:firebase-ui-storage:6.4.0' } ``` diff --git a/auth/README.md b/auth/README.md index 8c8973c6c..4c3b0d57d 100644 --- a/auth/README.md +++ b/auth/README.md @@ -65,7 +65,7 @@ Gradle, add the dependency: ```groovy dependencies { // ... - implementation 'com.firebaseui:firebase-ui-auth:6.3.0' + implementation 'com.firebaseui:firebase-ui-auth:6.4.0' // Required only if Facebook login support is required // Find the latest Facebook SDK releases here: https://github.com/facebook/facebook-android-sdk/blob/master/CHANGELOG.md diff --git a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java index 48b592adc..07665f983 100644 --- a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java +++ b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java @@ -1201,14 +1201,17 @@ public GenericOAuthProviderBuilder setCustomParameters( @SuppressWarnings(value = "unchecked") private abstract class AuthIntentBuilder { final List mProviders = new ArrayList<>(); + IdpConfig mDefaultProvider = null; int mLogo = NO_LOGO; int mTheme = getDefaultTheme(); String mTosUrl; String mPrivacyPolicyUrl; boolean mAlwaysShowProviderChoice = false; + boolean mLockOrientation = false; boolean mEnableCredentials = true; boolean mEnableHints = true; AuthMethodPickerLayout mAuthMethodPickerLayout = null; + ActionCodeSettings mPasswordSettings = null; /** * Specifies the theme to use for the application flow. If no theme is specified, a @@ -1270,7 +1273,7 @@ public T setTosAndPrivacyPolicyUrls(@NonNull String tosUrl, } /** - * Specified the set of supported authentication providers. At least one provider must + * Specifies the set of supported authentication providers. At least one provider must * be specified. There may only be one instance of each provider. Anonymous provider cannot * be the only provider specified. *

@@ -1307,6 +1310,29 @@ public T setAvailableProviders(@NonNull List idpConfigs) { return (T) this; } + /** + * Specifies the default authentication provider, bypassing the provider selection screen. + * The provider here must already be included via {@link #setAvailableProviders(List)}, and + * this method is incompatible with {@link #setAlwaysShowSignInMethodScreen(boolean)}. + * + * @param config the default {@link IdpConfig} to use. + */ + @NonNull + public T setDefaultProvider(@Nullable IdpConfig config) { + if (config != null) { + if (!mProviders.contains(config)) { + throw new IllegalStateException( + "Default provider not in available providers list."); + } + if (mAlwaysShowProviderChoice) { + throw new IllegalStateException( + "Can't set default provider and always show provider choice."); + } + } + mDefaultProvider = config; + return (T) this; + } + /** * Enables or disables the use of Smart Lock for Passwords in the sign in flow. To * (en)disable hint selector and credential selector independently use {@link @@ -1359,10 +1385,39 @@ public T setAuthMethodPickerLayout(@NonNull AuthMethodPickerLayout authMethodPic */ @NonNull public T setAlwaysShowSignInMethodScreen(boolean alwaysShow) { + if (alwaysShow && mDefaultProvider != null) { + throw new IllegalStateException( + "Can't show provider choice with a default provider."); + } mAlwaysShowProviderChoice = alwaysShow; return (T) this; } + /** + * Enable or disables the orientation for small devices to be locked in + * Portrait orientation + *

+ *

This is false by default. + * + * @param lockOrientation if true, force the activities to be in Portrait orientation. + */ + @NonNull + public T setLockOrientation(boolean lockOrientation) { + mLockOrientation = lockOrientation; + return (T) this; + } + + /** + * Set custom settings for the RecoverPasswordActivity. + * + * @param passwordSettings to allow additional state via a continue URL. + */ + @NonNull + public T setResetPasswordSettings(ActionCodeSettings passwordSettings) { + mPasswordSettings = passwordSettings; + return (T) this; + } + @CallSuper @NonNull public Intent build() { @@ -1431,6 +1486,7 @@ protected FlowParameters getFlowParams() { return new FlowParameters( mApp.getName(), mProviders, + mDefaultProvider, mTheme, mLogo, mTosUrl, @@ -1439,7 +1495,9 @@ protected FlowParameters getFlowParams() { mEnableHints, mEnableAnonymousUpgrade, mAlwaysShowProviderChoice, + mLockOrientation, mEmailLink, + mPasswordSettings, mAuthMethodPickerLayout); } } diff --git a/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java b/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java index 402a38b12..c59e555f7 100644 --- a/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java +++ b/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java @@ -22,6 +22,7 @@ import com.firebase.ui.auth.AuthUI.IdpConfig; import com.firebase.ui.auth.util.ExtraConstants; import com.firebase.ui.auth.util.Preconditions; +import com.google.firebase.auth.ActionCodeSettings; import java.util.Collections; import java.util.List; @@ -44,6 +45,7 @@ public class FlowParameters implements Parcelable { public FlowParameters createFromParcel(Parcel in) { String appName = in.readString(); List providerInfo = in.createTypedArrayList(IdpConfig.CREATOR); + IdpConfig defaultProvider = in.readParcelable(IdpConfig.class.getClassLoader()); int themeId = in.readInt(); int logoId = in.readInt(); String termsOfServiceUrl = in.readString(); @@ -52,12 +54,15 @@ public FlowParameters createFromParcel(Parcel in) { boolean enableHints = in.readInt() != 0; boolean enableAnonymousUpgrade = in.readInt() != 0; boolean alwaysShowProviderChoice = in.readInt() != 0; + boolean lockOrientation = in.readInt() != 0; String emailLink = in.readString(); + ActionCodeSettings passwordResetSettings = in.readParcelable(ActionCodeSettings.class.getClassLoader()); AuthMethodPickerLayout customLayout = in.readParcelable(AuthMethodPickerLayout.class.getClassLoader()); return new FlowParameters( appName, providerInfo, + defaultProvider, themeId, logoId, termsOfServiceUrl, @@ -66,7 +71,9 @@ public FlowParameters createFromParcel(Parcel in) { enableHints, enableAnonymousUpgrade, alwaysShowProviderChoice, + lockOrientation, emailLink, + passwordResetSettings, customLayout); } @@ -82,6 +89,9 @@ public FlowParameters[] newArray(int size) { @NonNull public final List providers; + @Nullable + public final IdpConfig defaultProvider; + @StyleRes public final int themeId; @@ -97,10 +107,14 @@ public FlowParameters[] newArray(int size) { @Nullable public String emailLink; + @Nullable + public final ActionCodeSettings passwordResetSettings; + public final boolean enableCredentials; public final boolean enableHints; public final boolean enableAnonymousUpgrade; public final boolean alwaysShowProviderChoice; + public final boolean lockOrientation; @Nullable public final AuthMethodPickerLayout authMethodPickerLayout; @@ -108,6 +122,7 @@ public FlowParameters[] newArray(int size) { public FlowParameters( @NonNull String appName, @NonNull List providers, + @Nullable IdpConfig defaultProvider, @StyleRes int themeId, @DrawableRes int logoId, @Nullable String termsOfServiceUrl, @@ -116,11 +131,14 @@ public FlowParameters( boolean enableHints, boolean enableAnonymousUpgrade, boolean alwaysShowProviderChoice, + boolean lockOrientation, @Nullable String emailLink, + @Nullable ActionCodeSettings passwordResetSettings, @Nullable AuthMethodPickerLayout authMethodPickerLayout) { this.appName = Preconditions.checkNotNull(appName, "appName cannot be null"); this.providers = Collections.unmodifiableList( Preconditions.checkNotNull(providers, "providers cannot be null")); + this.defaultProvider = defaultProvider; this.themeId = themeId; this.logoId = logoId; this.termsOfServiceUrl = termsOfServiceUrl; @@ -129,7 +147,9 @@ public FlowParameters( this.enableHints = enableHints; this.enableAnonymousUpgrade = enableAnonymousUpgrade; this.alwaysShowProviderChoice = alwaysShowProviderChoice; + this.lockOrientation = lockOrientation; this.emailLink = emailLink; + this.passwordResetSettings = passwordResetSettings; this.authMethodPickerLayout = authMethodPickerLayout; } @@ -144,6 +164,7 @@ public static FlowParameters fromIntent(Intent intent) { public void writeToParcel(Parcel dest, int flags) { dest.writeString(appName); dest.writeTypedList(providers); + dest.writeParcelable(defaultProvider, flags); dest.writeInt(themeId); dest.writeInt(logoId); dest.writeString(termsOfServiceUrl); @@ -152,7 +173,9 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(enableHints ? 1 : 0); dest.writeInt(enableAnonymousUpgrade ? 1 : 0); dest.writeInt(alwaysShowProviderChoice ? 1 : 0); + dest.writeInt(lockOrientation ? 1 : 0); dest.writeString(emailLink); + dest.writeParcelable(passwordResetSettings, flags); dest.writeParcelable(authMethodPickerLayout, flags); } @@ -178,6 +201,10 @@ public boolean isAnonymousUpgradeEnabled() { } public boolean shouldShowProviderChoice() { - return !isSingleProviderFlow() || alwaysShowProviderChoice; + return defaultProvider == null && (!isSingleProviderFlow() || alwaysShowProviderChoice); + } + + public IdpConfig getDefaultOrFirstProvider() { + return defaultProvider != null ? defaultProvider : providers.get(0); } } diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/GenericIdpSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/GenericIdpSignInHandler.java index 7e7c6ddcb..03748bec2 100644 --- a/auth/src/main/java/com/firebase/ui/auth/data/remote/GenericIdpSignInHandler.java +++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/GenericIdpSignInHandler.java @@ -86,8 +86,9 @@ protected void handleNormalSignInFlow(final FirebaseAuth auth, @Override public void onSuccess(@NonNull AuthResult authResult) { handleSuccess(provider.getProviderId(), - authResult.getUser(), (OAuthCredential) - authResult.getCredential()); + authResult.getUser(), + (OAuthCredential) authResult.getCredential(), + authResult.getAdditionalUserInfo().isNewUser()); } }) .addOnFailureListener( @@ -135,8 +136,9 @@ private void handleAnonymousUpgradeFlow(final FirebaseAuth auth, @Override public void onSuccess(@NonNull AuthResult authResult) { handleSuccess(provider.getProviderId(), - authResult.getUser(), (OAuthCredential) - authResult.getCredential()); + authResult.getUser(), + (OAuthCredential) authResult.getCredential(), + authResult.getAdditionalUserInfo().isNewUser()); } }) .addOnFailureListener( @@ -221,6 +223,7 @@ protected OAuthProvider buildOAuthProvider(String providerId) { protected void handleSuccess(@NonNull String providerId, @NonNull FirebaseUser user, @NonNull OAuthCredential credential, + boolean isNewUser, boolean setPendingCredential) { IdpResponse.Builder response = new IdpResponse.Builder( new User.Builder( @@ -234,14 +237,16 @@ protected void handleSuccess(@NonNull String providerId, if (setPendingCredential) { response.setPendingCredential(credential); } + response.setNewUser(isNewUser); setResult(Resource.forSuccess(response.build())); } protected void handleSuccess(@NonNull String providerId, @NonNull FirebaseUser user, - @NonNull OAuthCredential credential) { - handleSuccess(providerId, user, credential, /* setPendingCredential= */false); + @NonNull OAuthCredential credential, + boolean isNewUser) { + handleSuccess(providerId, user, credential, isNewUser, /* setPendingCredential= */true); } diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java index acfc3e2dd..3f972b0e6 100644 --- a/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java +++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java @@ -135,9 +135,8 @@ public void onComplete(@NonNull Task task) { } private void startAuthMethodChoice() { - // If there is only one provider selected, launch the flow directly if (!getArguments().shouldShowProviderChoice()) { - AuthUI.IdpConfig firstIdpConfig = getArguments().providers.get(0); + AuthUI.IdpConfig firstIdpConfig = getArguments().getDefaultOrFirstProvider(); String firstProvider = firstIdpConfig.getProviderId(); switch (firstProvider) { case EMAIL_LINK_PROVIDER: diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java b/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java index 475106067..934f64563 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java @@ -14,6 +14,8 @@ package com.firebase.ui.auth.ui; +import android.annotation.SuppressLint; +import android.content.pm.ActivityInfo; import android.os.Bundle; import com.firebase.ui.auth.R; @@ -31,6 +33,10 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.FirebaseUI); // Provides default values setTheme(getFlowParams().themeId); + + if (getFlowParams().lockOrientation) { + lockOrientation(); + } } protected void switchFragment(@NonNull Fragment fragment, @@ -53,4 +59,9 @@ protected void switchFragment(@NonNull Fragment fragment, protected void switchFragment(@NonNull Fragment fragment, int fragmentId, @NonNull String tag) { switchFragment(fragment, fragmentId, tag, false, false); } + + @SuppressLint("SourceLockedOrientationActivity") + private void lockOrientation() { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } } diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java index 1405f81de..0f2e2d59a 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java @@ -34,6 +34,7 @@ import com.firebase.ui.auth.viewmodel.ResourceObserver; import com.firebase.ui.auth.viewmodel.email.RecoverPasswordHandler; import com.google.android.material.textfield.TextInputLayout; +import com.google.firebase.auth.ActionCodeSettings; import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException; import com.google.firebase.auth.FirebaseAuthInvalidUserException; @@ -118,10 +119,18 @@ public void onClick(View view) { @Override public void onDonePressed() { if (mEmailFieldValidator.validate(mEmailEditText.getText())) { - mHandler.startReset(mEmailEditText.getText().toString()); + if (getFlowParams().passwordResetSettings != null) { + resetPassword(mEmailEditText.getText().toString(), getFlowParams().passwordResetSettings); + } + else { + resetPassword(mEmailEditText.getText().toString(), null); + } } } + private void resetPassword(String email, @Nullable ActionCodeSettings passwordResetSettings) { + mHandler.startReset(email, passwordResetSettings); + } private void showEmailSentDialog(String email) { new AlertDialog.Builder(this) .setTitle(R.string.fui_title_confirm_recover_password) diff --git a/auth/src/main/java/com/firebase/ui/auth/util/ui/TextHelper.java b/auth/src/main/java/com/firebase/ui/auth/util/ui/TextHelper.java index 8bd33f02b..cc0260c45 100644 --- a/auth/src/main/java/com/firebase/ui/auth/util/ui/TextHelper.java +++ b/auth/src/main/java/com/firebase/ui/auth/util/ui/TextHelper.java @@ -18,7 +18,7 @@ public static void boldAllOccurencesOfText(@NonNull SpannableStringBuilder build while (fromIndex < text.length()) { int start = text.indexOf(textToBold, fromIndex); int end = start + textToBold.length(); - if (start == -1 || end >= text.length()) { + if (start == -1 || end > text.length()) { break; } builder.setSpan(new StyleSpan(Typeface.BOLD), diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/RecoverPasswordHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/RecoverPasswordHandler.java index f322cd0c9..6e004cabc 100644 --- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/RecoverPasswordHandler.java +++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/RecoverPasswordHandler.java @@ -6,8 +6,10 @@ import com.firebase.ui.auth.viewmodel.AuthViewModelBase; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.ActionCodeSettings; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) @@ -16,10 +18,13 @@ public RecoverPasswordHandler(Application application) { super(application); } - public void startReset(@NonNull final String email) { + public void startReset(@NonNull final String email, @Nullable ActionCodeSettings actionCodeSettings) { setResult(Resource.forLoading()); - getAuth().sendPasswordResetEmail(email) - .addOnCompleteListener(new OnCompleteListener() { + Task reset = actionCodeSettings != null + ? getAuth().sendPasswordResetEmail(email, actionCodeSettings) + : getAuth().sendPasswordResetEmail(email); + + reset.addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { Resource resource = task.isSuccessful() diff --git a/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java b/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java index abdafa1e9..47c81b7f5 100644 --- a/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java +++ b/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java @@ -34,6 +34,8 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; @RunWith(RobolectricTestRunner.class) public class AuthUITest { @@ -65,6 +67,35 @@ public void testCreateStartIntent_shouldOnlyAllowOneInstanceOfAnIdp() { new IdpConfig.EmailBuilder().build())); } + @Test(expected = IllegalStateException.class) + public void testCreateStartIntent_defaultProviderMustBeAvailable() { + SignInIntentBuilder startIntent = mAuthUi.createSignInIntentBuilder(); + startIntent.setAvailableProviders(Arrays.asList( + new IdpConfig.EmailBuilder().build(), + new IdpConfig.GoogleBuilder().build())) + .setDefaultProvider(new IdpConfig.FacebookBuilder().build()); + } + + @Test(expected = IllegalStateException.class) + public void testCreateStartIntent_incompatibleOptions() { + SignInIntentBuilder startIntent = mAuthUi.createSignInIntentBuilder(); + startIntent.setAvailableProviders(Arrays.asList( + new IdpConfig.EmailBuilder().build(), + new IdpConfig.GoogleBuilder().build())) + .setDefaultProvider(new IdpConfig.GoogleBuilder().build()) + .setAlwaysShowSignInMethodScreen(true); + } + + @Test(expected = IllegalStateException.class) + public void testCreateStartIntent_incompatibleOptionsReverseOrder() { + SignInIntentBuilder startIntent = mAuthUi.createSignInIntentBuilder(); + startIntent.setAvailableProviders(Arrays.asList( + new IdpConfig.EmailBuilder().build(), + new IdpConfig.GoogleBuilder().build())) + .setAlwaysShowSignInMethodScreen(true) + .setDefaultProvider(new IdpConfig.GoogleBuilder().build()); + } + @Test public void testCreatingStartIntent() { FlowParameters flowParameters = mAuthUi @@ -83,6 +114,26 @@ public void testCreatingStartIntent() { assertEquals(TestConstants.TOS_URL, flowParameters.termsOfServiceUrl); assertEquals(TestConstants.PRIVACY_URL, flowParameters.privacyPolicyUrl); assertEquals(AuthUI.getDefaultTheme(), flowParameters.themeId); + assertTrue(flowParameters.shouldShowProviderChoice()); + assertEquals(new IdpConfig.EmailBuilder().build(), + flowParameters.getDefaultOrFirstProvider()); + } + + @Test + public void testCreatingStartIntentWithDefaultProvider() { + FlowParameters flowParameters = mAuthUi + .createSignInIntentBuilder() + .setAvailableProviders(Arrays.asList( + new IdpConfig.EmailBuilder().build(), + new IdpConfig.GoogleBuilder().build(), + new IdpConfig.FacebookBuilder().build())) + .setDefaultProvider(new IdpConfig.FacebookBuilder().build()) + .build() + .getParcelableExtra(ExtraConstants.FLOW_PARAMS); + assertEquals(new IdpConfig.FacebookBuilder().build(), flowParameters.defaultProvider); + assertFalse(flowParameters.shouldShowProviderChoice()); + assertEquals(new IdpConfig.FacebookBuilder().build(), + flowParameters.getDefaultOrFirstProvider()); } @Test(expected = NullPointerException.class) diff --git a/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java b/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java index f118866e7..44888d720 100644 --- a/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java +++ b/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java @@ -157,6 +157,7 @@ public static FlowParameters getFlowParameters(Collection providerIds, return new FlowParameters( DEFAULT_APP_NAME, idpConfigs, + null, AuthUI.getDefaultTheme(), AuthUI.NO_LOGO, null, @@ -165,6 +166,8 @@ public static FlowParameters getFlowParameters(Collection providerIds, true, enableAnonymousUpgrade, false, + true, + null, null, customLayout); } diff --git a/auth/src/test/java/com/firebase/ui/auth/viewmodel/RecoverPasswordHandlerTest.java b/auth/src/test/java/com/firebase/ui/auth/viewmodel/RecoverPasswordHandlerTest.java index 32a1f6e58..6f7f11256 100644 --- a/auth/src/test/java/com/firebase/ui/auth/viewmodel/RecoverPasswordHandlerTest.java +++ b/auth/src/test/java/com/firebase/ui/auth/viewmodel/RecoverPasswordHandlerTest.java @@ -9,6 +9,7 @@ import com.firebase.ui.auth.testhelpers.TestConstants; import com.firebase.ui.auth.testhelpers.TestHelper; import com.firebase.ui.auth.viewmodel.email.RecoverPasswordHandler; +import com.google.firebase.auth.ActionCodeSettings; import com.google.firebase.auth.EmailAuthProvider; import com.google.firebase.auth.FirebaseAuth; @@ -39,6 +40,8 @@ public class RecoverPasswordHandlerTest { private RecoverPasswordHandler mHandler; + private ActionCodeSettings mPasswordResetSettings; + @Before public void setUp() { TestHelper.initialize(); @@ -49,6 +52,12 @@ public void setUp() { FlowParameters testParams = TestHelper.getFlowParameters(Collections.singletonList( EmailAuthProvider.PROVIDER_ID)); mHandler.initializeForTesting(testParams, mMockAuth, null, null); + + mPasswordResetSettings = ActionCodeSettings.newBuilder() + .setAndroidPackageName("com.firebase.uidemo", true, null) + .setHandleCodeInApp(true) + .setUrl("https://google.com") + .build(); } @Test @@ -59,7 +68,7 @@ public void testReset_sendsRecoverEmail() { // Begin observation, then send the email mHandler.getOperation().observeForever(mObserver); - mHandler.startReset(TestConstants.EMAIL); + mHandler.startReset(TestConstants.EMAIL, null); // Should get in-progress resource verify(mObserver).onChanged(argThat(ResourceMatchers.isLoading())); @@ -79,7 +88,7 @@ public void testReset_propagatesFailure() { // Begin observation, then send the email mHandler.getOperation().observeForever(mObserver); - mHandler.startReset(TestConstants.EMAIL); + mHandler.startReset(TestConstants.EMAIL, null); // Should get in-progress resource verify(mObserver).onChanged(argThat(ResourceMatchers.isLoading())); @@ -91,4 +100,43 @@ public void testReset_propagatesFailure() { verify(mObserver).onChanged(argThat(ResourceMatchers.isFailure())); } + @Test + public void testReset_sendsCustomRecoverEmail() { + // Send password email succeeds + when(mMockAuth.sendPasswordResetEmail(TestConstants.EMAIL, mPasswordResetSettings )) + .thenReturn(AutoCompleteTask.forSuccess(null)); + + // Begin observation, then send the email + mHandler.getOperation().observeForever(mObserver); + mHandler.startReset(TestConstants.EMAIL, mPasswordResetSettings); + + // Should get in-progress resource + verify(mObserver).onChanged(argThat(ResourceMatchers.isLoading())); + + // Firebase auth should be called + verify(mMockAuth).sendPasswordResetEmail(TestConstants.EMAIL, mPasswordResetSettings); + + // Should get the success resource + verify(mObserver).onChanged(argThat(ResourceMatchers.isSuccess())); + } + + @Test + public void testCustomReset_propagatesFailure() { + // Send password email fails + when(mMockAuth.sendPasswordResetEmail(TestConstants.EMAIL, mPasswordResetSettings)) + .thenReturn(AutoCompleteTask.forFailure(new Exception("FAILED"))); + + // Begin observation, then send the email + mHandler.getOperation().observeForever(mObserver); + mHandler.startReset(TestConstants.EMAIL, mPasswordResetSettings); + + // Should get in-progress resource + verify(mObserver).onChanged(argThat(ResourceMatchers.isLoading())); + + // Firebase auth should be called + verify(mMockAuth).sendPasswordResetEmail(TestConstants.EMAIL, mPasswordResetSettings); + + // Should get the success resource + verify(mObserver).onChanged(argThat(ResourceMatchers.isFailure())); + } } diff --git a/buildSrc/src/main/kotlin/Config.kt b/buildSrc/src/main/kotlin/Config.kt index 1ee8d1745..916155ce9 100644 --- a/buildSrc/src/main/kotlin/Config.kt +++ b/buildSrc/src/main/kotlin/Config.kt @@ -1,5 +1,5 @@ object Config { - const val version = "6.3.0" + const val version = "6.4.0" val submodules = listOf("auth", "common", "firestore", "database", "storage") private const val kotlinVersion = "1.3.72" @@ -42,7 +42,7 @@ object Config { } object Firebase { - const val bom = "com.google.firebase:firebase-bom:25.7.0" + const val bom = "com.google.firebase:firebase-bom:25.12.0" const val auth = "com.google.firebase:firebase-auth" const val database = "com.google.firebase:firebase-database" const val firestore = "com.google.firebase:firebase-firestore"