From f59e1334c8ffaf9bc08cfe07914e18b379aeceec Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 16 Nov 2020 14:24:40 +0000 Subject: [PATCH 1/5] Begin development on v7.1.0 --- buildSrc/src/main/kotlin/Config.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Config.kt b/buildSrc/src/main/kotlin/Config.kt index cb19e71e5..aaf74191e 100644 --- a/buildSrc/src/main/kotlin/Config.kt +++ b/buildSrc/src/main/kotlin/Config.kt @@ -1,5 +1,5 @@ object Config { - const val version = "7.0.0" + const val version = "7.1.0-SNAPSHOT" val submodules = listOf("auth", "common", "firestore", "database", "storage") private const val kotlinVersion = "1.3.72" From a72885b6ea2e53c5912ae75cbb2b2849ca1af7f0 Mon Sep 17 00:00:00 2001 From: Sam Stern Date: Tue, 17 Nov 2020 07:24:34 -0500 Subject: [PATCH 2/5] Allow most auth flows without Play services (#1865) --- CHANGELOG.md | 1 + .../java/com/firebase/ui/auth/AuthUI.java | 36 ++++++++++++++++--- .../com/firebase/ui/auth/KickoffActivity.java | 10 ++++-- .../ui/auth/data/model/FlowParameters.java | 19 ++++++++++ .../firebase/ui/auth/util/GoogleApiUtils.java | 8 +++++ 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb..7d5aae448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Allow most auth flows on devices without Google Play services (#1858) 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 1c39c6d16..79c0efa70 100644 --- a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java +++ b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java @@ -39,8 +39,11 @@ import com.google.android.gms.auth.api.signin.GoogleSignIn; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.CommonStatusCodes; +import com.google.android.gms.common.api.GoogleApi; import com.google.android.gms.common.api.Scope; import com.google.android.gms.tasks.Continuation; import com.google.android.gms.tasks.Task; @@ -340,6 +343,12 @@ public Task silentSignIn(@NonNull Context context, .getParcelable(ExtraConstants.GOOGLE_SIGN_IN_OPTIONS); } + // If Play services are not available we can't attempt to use the credentials client. + if (!GoogleApiUtils.isPlayServicesAvailable(context)) { + return Tasks.forException( + new FirebaseUiException(ErrorCodes.PLAY_SERVICES_UPDATE_CANCELLED)); + } + return GoogleApiUtils.getCredentialsClient(context) .request(new CredentialRequest.Builder() // We can support both email and Google at the same time here because they @@ -392,8 +401,16 @@ public Task then( */ @NonNull public Task signOut(@NonNull Context context) { - Task maybeDisableAutoSignIn = GoogleApiUtils.getCredentialsClient(context) - .disableAutoSignIn() + boolean playServicesAvailable = GoogleApiUtils.isPlayServicesAvailable(context); + if (!playServicesAvailable) { + Log.w(TAG, "Google Play services not available during signOut"); + } + + Task maybeDisableAutoSignIn = playServicesAvailable + ? GoogleApiUtils.getCredentialsClient(context).disableAutoSignIn() + : Tasks.forResult((Void) null); + + maybeDisableAutoSignIn .continueWith(new Continuation() { @Override public Void then(@NonNull Task task) { @@ -434,7 +451,7 @@ public Void then(@NonNull Task task) { * @param context the calling {@link Context}. */ @NonNull - public Task delete(@NonNull Context context) { + public Task delete(@NonNull final Context context) { final FirebaseUser currentUser = mAuth.getCurrentUser(); if (currentUser == null) { return Tasks.forException(new FirebaseAuthInvalidUserException( @@ -443,7 +460,6 @@ public Task delete(@NonNull Context context) { } final List credentials = getCredentialsFromFirebaseUser(currentUser); - final CredentialsClient client = GoogleApiUtils.getCredentialsClient(context); // Ensure the order in which tasks are executed properly destructures the user. return signOutIdps(context).continueWithTask(new Continuation>() { @@ -451,6 +467,12 @@ public Task delete(@NonNull Context context) { public Task then(@NonNull Task task) { task.getResult(); // Propagate exception if there was one + if (!GoogleApiUtils.isPlayServicesAvailable(context)) { + Log.w(TAG, "Google Play services not available during delete"); + return Tasks.forResult((Void) null); + } + + final CredentialsClient client = GoogleApiUtils.getCredentialsClient(context); List> credentialTasks = new ArrayList<>(); for (Credential credential : credentials) { credentialTasks.add(client.delete(credential)); @@ -516,7 +538,11 @@ private Task signOutIdps(@NonNull Context context) { if (ProviderAvailability.IS_FACEBOOK_AVAILABLE) { LoginManager.getInstance().logOut(); } - return GoogleSignIn.getClient(context, GoogleSignInOptions.DEFAULT_SIGN_IN).signOut(); + if (GoogleApiUtils.isPlayServicesAvailable(context)) { + return GoogleSignIn.getClient(context, GoogleSignInOptions.DEFAULT_SIGN_IN).signOut(); + } else { + return Tasks.forResult((Void) null); + } } /** diff --git a/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java b/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java index 226f16d62..ba00e0e51 100644 --- a/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java +++ b/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java @@ -14,6 +14,9 @@ import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.Tasks; +import com.google.firebase.auth.GoogleAuthProvider; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -53,8 +56,11 @@ protected void onFailure(@NonNull Exception e) { } }); - GoogleApiAvailability.getInstance() - .makeGooglePlayServicesAvailable(this) + Task checkPlayServicesTask = getFlowParams().isPlayServicesRequired() + ? GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(this) + : Tasks.forResult((Void) null); + + checkPlayServicesTask .addOnSuccessListener(this, new OnSuccessListener() { @Override public void onSuccess(Void aVoid) { 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 c59e555f7..b43edda53 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 @@ -19,10 +19,12 @@ import android.text.TextUtils; import com.firebase.ui.auth.AuthMethodPickerLayout; +import com.firebase.ui.auth.AuthUI; 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 com.google.firebase.auth.GoogleAuthProvider; import java.util.Collections; import java.util.List; @@ -200,6 +202,23 @@ public boolean isAnonymousUpgradeEnabled() { return enableAnonymousUpgrade; } + public boolean isPlayServicesRequired() { + // Play services only required for Google Sign In and the Credentials API + return isProviderEnabled(GoogleAuthProvider.PROVIDER_ID) + || enableHints + || enableCredentials; + } + + public boolean isProviderEnabled(@AuthUI.SupportedProvider String provider) { + for (AuthUI.IdpConfig idp : providers) { + if (idp.getProviderId().equals(provider)) { + return true; + } + } + + return false; + } + public boolean shouldShowProviderChoice() { return defaultProvider == null && (!isSingleProviderFlow() || alwaysShowProviderChoice); } diff --git a/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java index d12be0ae1..6daf7d545 100644 --- a/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java +++ b/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java @@ -6,6 +6,8 @@ import com.google.android.gms.auth.api.credentials.Credentials; import com.google.android.gms.auth.api.credentials.CredentialsClient; import com.google.android.gms.auth.api.credentials.CredentialsOptions; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; import androidx.annotation.NonNull; import androidx.annotation.RestrictTo; @@ -16,6 +18,12 @@ private GoogleApiUtils() { throw new AssertionError("No instance for you!"); } + public static boolean isPlayServicesAvailable(@NonNull Context context) { + return GoogleApiAvailability + .getInstance() + .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS; + } + @NonNull public static CredentialsClient getCredentialsClient(@NonNull Context context) { CredentialsOptions options = new CredentialsOptions.Builder() From 4c75c23bffada27b3c1d3b4628713f6d41304820 Mon Sep 17 00:00:00 2001 From: Laur <70561735+laurentiu-git@users.noreply.github.com> Date: Wed, 18 Nov 2020 14:04:06 +0200 Subject: [PATCH 3/5] Added setDefaultEmail for EmailBuilder (#1866) --- CHANGELOG.md | 1 + .../java/com/firebase/ui/auth/AuthUI.java | 11 ++++ .../ui/auth/ui/email/EmailActivity.java | 6 +++ .../firebase/ui/auth/util/ExtraConstants.java | 1 + .../java/com/firebase/ui/auth/AuthUITest.java | 15 +++++- .../ui/auth/testhelpers/TestHelper.java | 13 +++-- .../ui/auth/ui/email/EmailActivityTest.java | 52 +++++++++++++++++-- .../ui/idp/AuthMethodPickerActivityTest.java | 30 +++++++++-- 8 files changed, 118 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5aae448..b1a05a688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Allow most auth flows on devices without Google Play services (#1858) +- Add ability to setDefaultEmail to the EmailBuilder (#1670) (contributed by @laurentiu-git) 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 79c0efa70..b8a8350a5 100644 --- a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java +++ b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java @@ -758,6 +758,17 @@ public EmailBuilder setForceSameDevice() { return this; } + /** + * Sets a default sign in email, if the given email has been registered before, then + * it will ask the user for password, if the given email it's not registered, then + * it starts signing up the default email. + */ + @NonNull + public EmailBuilder setDefaultEmail(String email) { + getParams().putString(ExtraConstants.DEFAULT_EMAIL, email); + return this; + } + @Override public IdpConfig build() { if (super.mProviderId.equals(EMAIL_LINK_PROVIDER)) { diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java index d9ac5f7b1..feabf506d 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java @@ -98,6 +98,12 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { responseForLinking, forceSameDevice); switchFragment(fragment, R.id.fragment_register_email, EmailLinkFragment.TAG); } else { + AuthUI.IdpConfig emailConfig = ProviderUtils.getConfigFromIdps( + getFlowParams().providers, EmailAuthProvider.PROVIDER_ID); + + if (emailConfig != null) { + email = emailConfig.getParams().getString(ExtraConstants.DEFAULT_EMAIL);; + } // Start with check email CheckEmailFragment fragment = CheckEmailFragment.newInstance(email); switchFragment(fragment, R.id.fragment_register_email, CheckEmailFragment.TAG); diff --git a/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java b/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java index 843deb6f5..2d2a27317 100644 --- a/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java +++ b/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java @@ -27,6 +27,7 @@ public final class ExtraConstants { public static final String CREDENTIAL = "extra_credential"; public static final String EMAIL = "extra_email"; + public static final String DEFAULT_EMAIL = "extra_default_email"; public static final String ALLOW_NEW_EMAILS = "extra_allow_new_emails"; public static final String REQUIRE_NAME = "extra_require_name"; public static final String GOOGLE_SIGN_IN_OPTIONS = "extra_google_sign_in_options"; 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 47c81b7f5..70c766e95 100644 --- a/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java +++ b/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java @@ -203,7 +203,7 @@ public void testPhoneBuilder_withValidDefaultNumberCode_expectSuccess() { } @Test - public void testPhoneBuilder_withBlacklistedCountryWithSameCountryCode_expectSucess() { + public void testPhoneBuilder_withBlacklistedCountryWithSameCountryCode_expectSuccess() { new IdpConfig.PhoneBuilder() .setDefaultNumber("+1123456789") .setBlacklistedCountries(Arrays.asList("ca")) @@ -333,6 +333,19 @@ public void testEmailBuilder_withAnonymousUpgradeAndNotForcingSameDevice_expectT (actionCodeSettings).build(); } + @Test + public void testEmailBuilder_withSetDefaultEmail_expectSuccess() { + ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder().setUrl(URL).build(); + + IdpConfig config = new IdpConfig.EmailBuilder() + .setDefaultEmail(TestConstants.EMAIL) + .setActionCodeSettings(actionCodeSettings) + .build(); + + assertThat(config.getParams().getString(ExtraConstants.DEFAULT_EMAIL)) + .isEqualTo(TestConstants.EMAIL); + } + @Test(expected = IllegalStateException.class) public void testSignInIntentBuilder_anonymousUpgradeWithEmailLinkCrossDevice_expectThrows() { ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder().setUrl(URL).build(); 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 c2ed71f74..2fab50343 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 @@ -126,12 +126,13 @@ public static FlowParameters getFlowParameters(Collection providerIds) { public static FlowParameters getFlowParameters(Collection providerIds, boolean enableAnonymousUpgrade) { - return getFlowParameters(providerIds, enableAnonymousUpgrade, null); + return getFlowParameters(providerIds, enableAnonymousUpgrade, null, false); } public static FlowParameters getFlowParameters(Collection providerIds, boolean enableAnonymousUpgrade, - AuthMethodPickerLayout customLayout) { + AuthMethodPickerLayout customLayout, + boolean hasDefaultEmail) { List idpConfigs = new ArrayList<>(); for (String providerId : providerIds) { switch (providerId) { @@ -153,7 +154,13 @@ public static FlowParameters getFlowParameters(Collection providerIds, .setHandleCodeInApp(true).build()).build()); break; case EmailAuthProvider.PROVIDER_ID: - idpConfigs.add(new IdpConfig.EmailBuilder().build()); + if (hasDefaultEmail) { idpConfigs.add(new IdpConfig.EmailBuilder() + .setDefaultEmail(TestConstants.EMAIL) + .build()); + } else + { + idpConfigs.add(new IdpConfig.EmailBuilder().build()); + } break; case PhoneAuthProvider.PROVIDER_ID: idpConfigs.add(new IdpConfig.PhoneBuilder().build()); diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/email/EmailActivityTest.java b/auth/src/test/java/com/firebase/ui/auth/ui/email/EmailActivityTest.java index a4873f4fc..9208cbfe3 100644 --- a/auth/src/test/java/com/firebase/ui/auth/ui/email/EmailActivityTest.java +++ b/auth/src/test/java/com/firebase/ui/auth/ui/email/EmailActivityTest.java @@ -25,6 +25,7 @@ import com.firebase.ui.auth.testhelpers.TestHelper; import com.firebase.ui.auth.util.ExtraConstants; import com.firebase.ui.auth.util.data.EmailLinkPersistenceManager; +import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; import com.google.firebase.auth.EmailAuthProvider; import com.google.firebase.auth.GoogleAuthProvider; @@ -34,6 +35,8 @@ import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import org.robolectric.Shadows; +import org.robolectric.shadows.ShadowActivity; import java.util.Collections; @@ -73,7 +76,7 @@ public void testOnCreate_emailLinkLinkingFlow_expectSendEmailLinkFlowStarted() { EmailLinkPersistenceManager.getInstance().saveEmail(ApplicationProvider.getApplicationContext(), EMAIL, TestConstants.SESSION_ID, TestConstants.UID); - EmailActivity emailActivity = createActivity(AuthUI.EMAIL_LINK_PROVIDER, true); + EmailActivity emailActivity = createActivity(AuthUI.EMAIL_LINK_PROVIDER, true, false); EmailLinkFragment fragment = (EmailLinkFragment) emailActivity .getSupportFragmentManager().findFragmentByTag(EmailLinkFragment.TAG); @@ -141,16 +144,59 @@ public void testSignUpButton_validatesFields() { passwordLayout.getError().toString()); } + @Test + public void testSetDefaultEmail_validField() { + EmailActivity emailActivity = createActivity(EmailAuthProvider.PROVIDER_ID, false, true); + + CheckEmailFragment fragment = (CheckEmailFragment) emailActivity + .getSupportFragmentManager().findFragmentByTag(CheckEmailFragment.TAG); + assertThat(fragment).isNotNull(); + + TextInputEditText email = emailActivity.findViewById(R.id.email); + assertEquals(TestConstants.EMAIL, email.getText().toString()); + + } + + @Test + public void testSetDefaultEmail_expectWelcomeBackPasswordPrompt() { + EmailActivity emailActivity = createActivity(EmailAuthProvider.PROVIDER_ID, false, true); + + emailActivity.onExistingEmailUser(new User.Builder(EmailAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build()); + + ShadowActivity.IntentForResult nextIntent = + Shadows.shadowOf(emailActivity).getNextStartedActivityForResult(); + assertEquals(WelcomeBackPasswordPrompt.class.getName(), + nextIntent.intent.getComponent().getClassName()); + + } + + @Test + public void testSetDefaultEmail_expectRegisterEmailFragment() { + EmailActivity emailActivity = createActivity(EmailAuthProvider.PROVIDER_ID, false, true); + + emailActivity.onNewUser(new User.Builder(EmailAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build()); + + RegisterEmailFragment registerEmailFragment = (RegisterEmailFragment) emailActivity + .getSupportFragmentManager().findFragmentByTag(RegisterEmailFragment.TAG); + assertThat(registerEmailFragment).isNotNull(); + } + private EmailActivity createActivity(String providerId) { - return createActivity(providerId, false); + return createActivity(providerId, false, false); } - private EmailActivity createActivity(String providerId, boolean emailLinkLinkingFlow) { + private EmailActivity createActivity(String providerId, boolean emailLinkLinkingFlow, boolean hasDefaultEmail) { Intent startIntent = EmailActivity.createIntent( ApplicationProvider.getApplicationContext(), TestHelper.getFlowParameters(Collections.singletonList(providerId))); + if (hasDefaultEmail) { + startIntent = EmailActivity.createIntent( + ApplicationProvider.getApplicationContext(), + TestHelper.getFlowParameters(Collections.singletonList(providerId), false, null, true)); + } + if (emailLinkLinkingFlow) { startIntent.putExtra(ExtraConstants.EMAIL, EMAIL); startIntent.putExtra(ExtraConstants.IDP_RESPONSE, buildGoogleIdpResponse()); diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java b/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java index 3cef98399..11eb1cf44 100644 --- a/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java +++ b/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java @@ -111,7 +111,7 @@ public void testCustomAuthMethodPickerLayout() { .setEmailButtonId(R.id.email_button) .build(); - AuthMethodPickerActivity authMethodPickerActivity = createActivityWithCustomLayout(providers, customLayout); + AuthMethodPickerActivity authMethodPickerActivity = createActivityWithCustomLayout(providers, customLayout, false); Button emailButton = authMethodPickerActivity.findViewById(R.id.email_button); emailButton.performClick(); @@ -133,7 +133,7 @@ public void testCustomAuthMethodPickerLayoutWithEmailLink() { .setEmailButtonId(R.id.email_button) .build(); - AuthMethodPickerActivity authMethodPickerActivity = createActivityWithCustomLayout(providers, customLayout); + AuthMethodPickerActivity authMethodPickerActivity = createActivityWithCustomLayout(providers, customLayout, false); Button emailButton = authMethodPickerActivity.findViewById(R.id.email_button); emailButton.performClick(); @@ -146,11 +146,33 @@ public void testCustomAuthMethodPickerLayoutWithEmailLink() { nextIntent.intent.getComponent().getClassName()); } + @Test + public void testCustomAuthMethodPickerLayoutWithDefaultEmail() { + List providers = Arrays.asList(EmailAuthProvider.PROVIDER_ID); + + AuthMethodPickerLayout customLayout = new AuthMethodPickerLayout + .Builder(R.layout.fui_provider_button_email) + .setEmailButtonId(R.id.email_button) + .build(); + + AuthMethodPickerActivity authMethodPickerActivity = createActivityWithCustomLayout(providers, customLayout, true); + Button emailButton = authMethodPickerActivity.findViewById(R.id.email_button); + emailButton.performClick(); + + //Expected result -> Directing users to EmailActivity + ShadowActivity.IntentForResult nextIntent = + Shadows.shadowOf(authMethodPickerActivity).getNextStartedActivityForResult(); + assertEquals( + EmailActivity.class.getName(), + nextIntent.intent.getComponent().getClassName()); + } + private AuthMethodPickerActivity createActivityWithCustomLayout(List providers, - AuthMethodPickerLayout layout) { + AuthMethodPickerLayout layout, + boolean hasDefaultEmail) { Intent startIntent = AuthMethodPickerActivity.createIntent( ApplicationProvider.getApplicationContext(), - TestHelper.getFlowParameters(providers, false, layout)); + TestHelper.getFlowParameters(providers, false, layout, hasDefaultEmail)); return Robolectric .buildActivity(AuthMethodPickerActivity.class, startIntent) From 39a8cf01e20ac620b9ffa58b08748d7e6b0c01c1 Mon Sep 17 00:00:00 2001 From: Laur <70561735+laurentiu-git@users.noreply.github.com> Date: Thu, 19 Nov 2020 20:30:51 +0200 Subject: [PATCH 4/5] Added setDocumentSnapshot() for FirestorePagingOptions (#1869) --- CHANGELOG.md | 1 + .../paging/FirestorePagingOptions.java | 38 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1a05a688..91d2221c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,3 @@ - Allow most auth flows on devices without Google Play services (#1858) - Add ability to setDefaultEmail to the EmailBuilder (#1670) (contributed by @laurentiu-git) +- Add ability to set data directly on FirestorePagingOptions (#1750) (contributed by @laurentiu-git) diff --git a/firestore/src/main/java/com/firebase/ui/firestore/paging/FirestorePagingOptions.java b/firestore/src/main/java/com/firebase/ui/firestore/paging/FirestorePagingOptions.java index 3fdedaee6..3b7997e88 100644 --- a/firestore/src/main/java/com/firebase/ui/firestore/paging/FirestorePagingOptions.java +++ b/firestore/src/main/java/com/firebase/ui/firestore/paging/FirestorePagingOptions.java @@ -14,6 +14,8 @@ import androidx.paging.PagedList; import androidx.recyclerview.widget.DiffUtil; +import static com.firebase.ui.common.Preconditions.assertNull; + /** * Options to configure an {@link FirestorePagingAdapter}. * @@ -21,6 +23,9 @@ */ public final class FirestorePagingOptions { + private static final String ERR_DATA_SET = "Data already set. " + + "Call only one of setData() or setQuery()"; + private final LiveData> mData; private final SnapshotParser mParser; private final DiffUtil.ItemCallback mDiffCallback; @@ -66,6 +71,34 @@ public static final class Builder { private LifecycleOwner mOwner; private DiffUtil.ItemCallback mDiffCallback; + /** + * Directly set data using and parse with a {@link ClassSnapshotParser} based on + * the given class. + *

+ * Do not call this method after calling {@code setQuery}. + */ + @NonNull + public Builder setData(@NonNull LiveData> data, + @NonNull Class modelClass) { + + return setData(data, new ClassSnapshotParser<>(modelClass)); + } + + /** + * Directly set data and parse with a custom {@link SnapshotParser}. + *

+ * Do not call this method after calling {@code setQuery}. + */ + @NonNull + public Builder setData(@NonNull LiveData> data, + @NonNull SnapshotParser parser) { + assertNull(mData, ERR_DATA_SET); + + mData = data; + mParser = parser; + return this; + } + /** * Sets the query using {@link Source#DEFAULT} and a {@link ClassSnapshotParser} based * on the given Class. @@ -121,6 +154,8 @@ public Builder setQuery(@NonNull Query query, @NonNull Source source, @NonNull PagedList.Config config, @NonNull SnapshotParser parser) { + assertNull(mData, ERR_DATA_SET); + // Build paged list FirestoreDataSource.Factory factory = new FirestoreDataSource.Factory(query, source); mData = new LivePagedListBuilder<>(factory, config).build(); @@ -162,7 +197,8 @@ public Builder setLifecycleOwner(@NonNull LifecycleOwner owner) { @NonNull public FirestorePagingOptions build() { if (mData == null || mParser == null) { - throw new IllegalStateException("Must call setQuery() before calling build()."); + throw new IllegalStateException("Must call setQuery() or setDocumentSnapshot()" + + " before calling build()."); } if (mDiffCallback == null) { From 94e1005922294be36339e0b3bedd72c01e1a4878 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 20 Nov 2020 14:35:59 +0000 Subject: [PATCH 5/5] Version 7.1.0 --- CHANGELOG.md | 3 --- README.md | 10 +++++----- auth/README.md | 2 +- buildSrc/src/main/kotlin/Config.kt | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91d2221c0..e69de29bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +0,0 @@ -- Allow most auth flows on devices without Google Play services (#1858) -- Add ability to setDefaultEmail to the EmailBuilder (#1670) (contributed by @laurentiu-git) -- Add ability to set data directly on FirestorePagingOptions (#1750) (contributed by @laurentiu-git) diff --git a/README.md b/README.md index b1c93a9ef..aba3bcc66 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:7.0.0' + implementation 'com.firebaseui:firebase-ui-database:7.1.0' // FirebaseUI for Cloud Firestore - implementation 'com.firebaseui:firebase-ui-firestore:7.0.0' + implementation 'com.firebaseui:firebase-ui-firestore:7.1.0' // FirebaseUI for Firebase Auth - implementation 'com.firebaseui:firebase-ui-auth:7.0.0' + implementation 'com.firebaseui:firebase-ui-auth:7.1.0' // FirebaseUI for Cloud Storage - implementation 'com.firebaseui:firebase-ui-storage:7.0.0' + implementation 'com.firebaseui:firebase-ui-storage:7.1.0' } ``` @@ -244,4 +244,4 @@ accept your pull requests. 1. Submit a pull request targeting the latest dev branch. [gh-actions]: https://github.com/firebase/FirebaseUI-Android/actions -[gh-actions-badge]: https://github.com/firebase/FirebaseUI-Android/workflows/Android%20CI/badge.svg \ No newline at end of file +[gh-actions-badge]: https://github.com/firebase/FirebaseUI-Android/workflows/Android%20CI/badge.svg diff --git a/auth/README.md b/auth/README.md index 46ece2a88..f10c55232 100644 --- a/auth/README.md +++ b/auth/README.md @@ -66,7 +66,7 @@ Gradle, add the dependency: ```groovy dependencies { // ... - implementation 'com.firebaseui:firebase-ui-auth:7.0.0' + implementation 'com.firebaseui:firebase-ui-auth:7.1.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/buildSrc/src/main/kotlin/Config.kt b/buildSrc/src/main/kotlin/Config.kt index aaf74191e..5fe605887 100644 --- a/buildSrc/src/main/kotlin/Config.kt +++ b/buildSrc/src/main/kotlin/Config.kt @@ -1,5 +1,5 @@ object Config { - const val version = "7.1.0-SNAPSHOT" + const val version = "7.1.0" val submodules = listOf("auth", "common", "firestore", "database", "storage") private const val kotlinVersion = "1.3.72"