From 150b51802a5747e55dee4bd6961d643223990da5 Mon Sep 17 00:00:00 2001 From: Leonardo Siracusa Date: Thu, 14 Jun 2018 12:43:55 -0700 Subject: [PATCH 01/17] Adds anonymous user upgrade to Email/Password sign in --- .../firebase/uidemo/auth/AuthUiActivity.java | 62 +++++++++---- .../java/com/firebase/ui/auth/AuthUI.java | 16 +++- .../java/com/firebase/ui/auth/ErrorCodes.java | 10 ++- ...FirebaseAuthAnonymousUpgradeException.java | 26 ++++++ .../com/firebase/ui/auth/IdpResponse.java | 65 +++++++++----- .../com/firebase/ui/auth/KickoffActivity.java | 4 + .../ui/auth/data/model/FlowParameters.java | 14 ++- .../firebase/ui/auth/data/model/Resource.java | 4 + .../auth/data/remote/EmailSignInHandler.java | 3 +- .../auth/data/remote/SignInKickstarter.java | 10 ++- .../ui/auth/ui/HelperActivityBase.java | 5 ++ .../ui/auth/ui/email/CheckEmailFragment.java | 4 +- .../ui/auth/ui/email/EmailActivity.java | 10 ++- .../auth/ui/email/RegisterEmailFragment.java | 16 ++++ .../ui/email/WelcomeBackPasswordPrompt.java | 15 +++- .../auth/util/data/AnonymousUpgradeUtils.java | 50 +++++++++++ .../email/EmailProviderResponseHandler.java | 44 +++++++--- .../email/WelcomeBackPasswordHandler.java | 86 +++++++++++++------ .../ui/auth/testhelpers/TestHelper.java | 3 +- 19 files changed, 359 insertions(+), 88 deletions(-) create mode 100644 auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java create mode 100644 auth/src/main/java/com/firebase/ui/auth/util/data/AnonymousUpgradeUtils.java diff --git a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java index 6fe6d5d82..61141d668 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java @@ -41,6 +41,7 @@ import com.google.android.gms.common.Scopes; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; @@ -155,17 +156,25 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @OnClick(R.id.sign_in) public void signIn(View view) { - startActivityForResult( - AuthUI.getInstance().createSignInIntentBuilder() - .setTheme(getSelectedTheme()) - .setLogo(getSelectedLogo()) - .setAvailableProviders(getSelectedProviders()) - .setTosAndPrivacyPolicyUrls(getSelectedTosUrl(), - getSelectedPrivacyPolicyUrl()) - .setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(), - mEnableHintSelector.isChecked()) - .build(), - RC_SIGN_IN); + FirebaseAuth.getInstance() + .signInAnonymously() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + startActivityForResult( + AuthUI.getInstance().createSignInIntentBuilder() + .setTheme(getSelectedTheme()) + .setLogo(getSelectedLogo()) + .setAvailableProviders(getSelectedProviders()) + .setTosAndPrivacyPolicyUrls(getSelectedTosUrl(), + getSelectedPrivacyPolicyUrl()) + .setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(), + mEnableHintSelector.isChecked()) + .setAutoUpgradeAnonymousUsers() + .build(), + RC_SIGN_IN); + } + }); } @OnClick(R.id.sign_in_silent) @@ -194,15 +203,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { @Override protected void onResume() { super.onResume(); - FirebaseAuth auth = FirebaseAuth.getInstance(); - if (auth.getCurrentUser() != null) { - startSignedInActivity(null); - finish(); - } +// FirebaseAuth auth = FirebaseAuth.getInstance(); +// if (auth.getCurrentUser() != null) { +// startSignedInActivity(null); +// finish(); +// } } private void handleSignInResponse(int resultCode, Intent data) { - IdpResponse response = IdpResponse.fromResultIntent(data); + final IdpResponse response = IdpResponse.fromResultIntent(data); // Successfully signed in if (resultCode == RESULT_OK) { @@ -221,6 +230,25 @@ private void handleSignInResponse(int resultCode, Intent data) { return; } + if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { + AuthCredential credential = response.getCredentialForLinking(); + // take data from anon user + // log in with credential + // update user + FirebaseAuth.getInstance().signInWithCredential(credential).addOnCompleteListener( + new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + startSignedInActivity(response); + } else { + // cry + } + } + }); + return; + } + showSnackbar(R.string.unknown_error); Log.e(TAG, "Sign-in error: ", response.getError()); } 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 492bad301..9c44e8213 100644 --- a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java +++ b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java @@ -1107,10 +1107,23 @@ public Intent build() { * Builder for the intent to start the user authentication flow. */ public final class SignInIntentBuilder extends AuthIntentBuilder { + + private boolean mEnableAnonymousUpgrade; + private SignInIntentBuilder() { super(); } + /** + * Enables or disables upgrading anonymous accounts to full accounts during the sign-in + * flow. This is disabled by default. + */ + @NonNull + public SignInIntentBuilder setAutoUpgradeAnonymousUsers() { + mEnableAnonymousUpgrade = true; + return this; + } + @Override protected FlowParameters getFlowParams() { return new FlowParameters( @@ -1121,7 +1134,8 @@ protected FlowParameters getFlowParams() { mTosUrl, mPrivacyPolicyUrl, mEnableCredentials, - mEnableHints); + mEnableHints, + mEnableAnonymousUpgrade); } } } diff --git a/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java b/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java index f49a714bd..ce6c300a3 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java +++ b/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java @@ -19,7 +19,8 @@ public final class ErrorCodes { NO_NETWORK, PLAY_SERVICES_UPDATE_CANCELLED, DEVELOPER_ERROR, - PROVIDER_ERROR + PROVIDER_ERROR, + ANONYMOUS_UPGRADE_MERGE_CONFLICT }) @Retention(RetentionPolicy.SOURCE) public @interface Code {} @@ -49,6 +50,11 @@ public final class ErrorCodes { */ public static final int PROVIDER_ERROR = 4; + /** + * Anonymous account linking failed. + */ + public static final int ANONYMOUS_UPGRADE_MERGE_CONFLICT = 5; + private ErrorCodes() { throw new AssertionError("No instance for you!"); } @@ -67,6 +73,8 @@ public static String toFriendlyMessage(@Code int code) { return "Developer error"; case PROVIDER_ERROR: return "Provider error"; + case ANONYMOUS_UPGRADE_MERGE_CONFLICT: + return "Merge conflict"; default: throw new IllegalArgumentException("Unknown code: " + code); } diff --git a/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java new file mode 100644 index 000000000..546797f09 --- /dev/null +++ b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java @@ -0,0 +1,26 @@ +package com.firebase.ui.auth; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; + +import com.firebase.ui.auth.IdpResponse; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.FirebaseAuthUserCollisionException; + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +public class FirebaseAuthAnonymousUpgradeException extends Exception { + + private IdpResponse response; + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + public FirebaseAuthAnonymousUpgradeException(@ErrorCodes.Code int code, + @NonNull IdpResponse response) { + super(ErrorCodes.toFriendlyMessage(code)); + this.response = response; + } + + public IdpResponse getResponse() { + return response; + } +} diff --git a/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java b/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java index b0e24595e..9dcbb5198 100644 --- a/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java +++ b/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java @@ -25,6 +25,7 @@ import com.firebase.ui.auth.data.model.User; import com.firebase.ui.auth.util.ExtraConstants; import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.GoogleAuthProvider; import com.google.firebase.auth.TwitterAuthProvider; @@ -44,7 +45,8 @@ public IdpResponse createFromParcel(Parcel in) { in.readString(), in.readString(), in.readInt() == 1, - (FirebaseUiException) in.readSerializable() + (FirebaseUiException) in.readSerializable(), + in.readParcelable(AuthCredential.class.getClassLoader()) ); } @@ -55,6 +57,7 @@ public IdpResponse[] newArray(int size) { }; private final User mUser; + private final AuthCredential mPendingCredential; private final String mToken; private final String mSecret; @@ -63,7 +66,7 @@ public IdpResponse[] newArray(int size) { private final FirebaseUiException mException; private IdpResponse(@NonNull FirebaseUiException e) { - this(null, null, null, false, e); + this(null, null, null, false, e, null); } private IdpResponse( @@ -71,7 +74,11 @@ private IdpResponse( @Nullable String token, @Nullable String secret, boolean isNewUser) { - this(user, token, secret, isNewUser, null); + this(user, token, secret, isNewUser, null, null); + } + + private IdpResponse(AuthCredential credential, FirebaseUiException e) { + this(null, null, null, false, e, credential); } private IdpResponse( @@ -79,12 +86,14 @@ private IdpResponse( String token, String secret, boolean isNewUser, - FirebaseUiException e) { + FirebaseUiException e, + AuthCredential credential) { mUser = user; mToken = token; mSecret = secret; mIsNewUser = isNewUser; mException = e; + mPendingCredential = credential; } /** @@ -207,6 +216,11 @@ public FirebaseUiException getError() { return mException; } + @Nullable + public AuthCredential getCredentialForLinking() { + return mPendingCredential; + } + @Override public int describeContents() { return 0; @@ -218,7 +232,6 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(mToken); dest.writeString(mSecret); dest.writeInt(mIsNewUser ? 1 : 0); - ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new ByteArrayOutputStream()); @@ -241,6 +254,7 @@ public void writeToParcel(Parcel dest, int flags) { } catch (IOException ignored) {} } } + dest.writeParcelable(mPendingCredential, 0); } @Override @@ -281,6 +295,7 @@ public String toString() { @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public static class Builder { private final User mUser; + private final AuthCredential mPendingCredential; private String mToken; private String mSecret; @@ -288,6 +303,12 @@ public static class Builder { public Builder(@NonNull User user) { mUser = user; + mPendingCredential = null; + } + + public Builder(@NonNull AuthCredential pendingCredential) { + mUser = null; + mPendingCredential = pendingCredential; } public Builder(@NonNull IdpResponse response) { @@ -295,6 +316,7 @@ public Builder(@NonNull IdpResponse response) { mToken = response.mToken; mSecret = response.mSecret; mIsNewUser = response.mIsNewUser; + mPendingCredential = response.mPendingCredential; } public Builder setNewUser(boolean newUser) { @@ -305,7 +327,7 @@ public Builder setNewUser(boolean newUser) { public Builder setToken(String token) { mToken = token; return this; - } + } public Builder setSecret(String secret) { mSecret = secret; @@ -313,21 +335,24 @@ public Builder setSecret(String secret) { } public IdpResponse build() { - String providerId = mUser.getProviderId(); - if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) { - throw new IllegalStateException("Unknown provider: " + providerId); + if (mPendingCredential != null) { + return new IdpResponse(mPendingCredential, new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT)); + } else { + String providerId = mUser.getProviderId(); + if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) { + throw new IllegalStateException("Unknown provider: " + providerId); + } + if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) { + throw new IllegalStateException( + "Token cannot be null when using a non-email provider."); + } + if (providerId.equals(TwitterAuthProvider.PROVIDER_ID) + && TextUtils.isEmpty(mSecret)) { + throw new IllegalStateException( + "Secret cannot be null when using the Twitter provider."); + } + return new IdpResponse(mUser, mToken, mSecret, mIsNewUser); } - if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) { - throw new IllegalStateException( - "Token cannot be null when using a non-email provider."); - } - if (providerId.equals(TwitterAuthProvider.PROVIDER_ID) - && TextUtils.isEmpty(mSecret)) { - throw new IllegalStateException( - "Secret cannot be null when using the Twitter provider."); - } - - return new IdpResponse(mUser, mToken, mSecret, mIsNewUser); } } } 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 27438e7c3..e1ad3104d 100644 --- a/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java +++ b/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java @@ -13,6 +13,7 @@ import com.firebase.ui.auth.data.model.UserCancellationException; import com.firebase.ui.auth.data.remote.SignInKickstarter; import com.firebase.ui.auth.ui.InvisibleActivityBase; +import com.firebase.ui.auth.util.ExtraConstants; import com.firebase.ui.auth.viewmodel.ResourceObserver; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.tasks.OnFailureListener; @@ -41,6 +42,9 @@ protected void onSuccess(@NonNull IdpResponse response) { protected void onFailure(@NonNull Exception e) { if (e instanceof UserCancellationException) { finish(RESULT_CANCELED, null); + } else if (e instanceof FirebaseAuthAnonymousUpgradeException) { + IdpResponse res = ((FirebaseAuthAnonymousUpgradeException) e).getResponse(); + finish(RESULT_CANCELED, new Intent().putExtra(ExtraConstants.IDP_RESPONSE, res)); } else { finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e)); } 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 be4063b69..4cde51957 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 @@ -56,6 +56,7 @@ public class FlowParameters implements Parcelable { public final boolean enableCredentials; public final boolean enableHints; + public final boolean enableAnonymousUpgrade; public FlowParameters( @NonNull String appName, @@ -65,7 +66,8 @@ public FlowParameters( @Nullable String termsOfServiceUrl, @Nullable String privacyPolicyUrl, boolean enableCredentials, - boolean enableHints) { + boolean enableHints, + boolean enableAnonymousUpgrade) { this.appName = Preconditions.checkNotNull(appName, "appName cannot be null"); this.providerInfo = Collections.unmodifiableList( Preconditions.checkNotNull(providerInfo, "providerInfo cannot be null")); @@ -75,6 +77,7 @@ public FlowParameters( this.privacyPolicyUrl = privacyPolicyUrl; this.enableCredentials = enableCredentials; this.enableHints = enableHints; + this.enableAnonymousUpgrade = enableAnonymousUpgrade; } /** @@ -94,6 +97,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(privacyPolicyUrl); dest.writeInt(enableCredentials ? 1 : 0); dest.writeInt(enableHints ? 1 : 0); + dest.writeInt(enableAnonymousUpgrade ? 1 : 0); } @Override @@ -112,6 +116,7 @@ public FlowParameters createFromParcel(Parcel in) { String privacyPolicyUrl = in.readString(); boolean enableCredentials = in.readInt() != 0; boolean enableHints = in.readInt() != 0; + boolean enableAnonymousUpgrade = in.readInt() != 0; return new FlowParameters( appName, @@ -121,7 +126,8 @@ public FlowParameters createFromParcel(Parcel in) { termsOfServiceUrl, privacyPolicyUrl, enableCredentials, - enableHints); + enableHints, + enableAnonymousUpgrade); } @Override @@ -141,4 +147,8 @@ public boolean isTermsOfServiceUrlProvided() { public boolean isPrivacyPolicyUrlProvided() { return !TextUtils.isEmpty(privacyPolicyUrl); } + + public boolean isAnonymousUpgradeEnabled() { + return enableAnonymousUpgrade; + } } diff --git a/auth/src/main/java/com/firebase/ui/auth/data/model/Resource.java b/auth/src/main/java/com/firebase/ui/auth/data/model/Resource.java index 1b526b13e..a2598cbc1 100644 --- a/auth/src/main/java/com/firebase/ui/auth/data/model/Resource.java +++ b/auth/src/main/java/com/firebase/ui/auth/data/model/Resource.java @@ -65,6 +65,10 @@ public T getValue() { return mValue; } + public boolean hasValue() { + return mValue != null; + } + public boolean isUsed() { return mIsUsed; } diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java index f65cc01cd..19b6ab784 100644 --- a/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java +++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java @@ -6,6 +6,7 @@ import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; +import com.firebase.ui.auth.ErrorCodes; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.data.model.Resource; import com.firebase.ui.auth.data.model.UserCancellationException; @@ -29,7 +30,7 @@ public void startSignIn(@NonNull HelperActivityBase activity) { @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if (requestCode == RequestCodes.EMAIL_FLOW) { + if (requestCode == RequestCodes.EMAIL_FLOW && resultCode != ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { IdpResponse response = IdpResponse.fromResultIntent(data); if (response == null) { setResult(Resource.forFailure(new UserCancellationException())); 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 4524bd93f..77d4e57c6 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 @@ -9,6 +9,8 @@ import android.text.TextUtils; import com.firebase.ui.auth.AuthUI; +import com.firebase.ui.auth.ErrorCodes; +import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.data.model.IntentRequiredException; import com.firebase.ui.auth.data.model.PendingIntentRequiredException; @@ -182,7 +184,13 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d } else if (response.isSuccessful()) { setResult(Resource.forSuccess(response)); } else { - setResult(Resource.forFailure(response.getError())); + if (response.getError().getErrorCode() == + ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { + setResult(Resource.forFailure(new FirebaseAuthAnonymousUpgradeException( + ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response))); + } else { + setResult(Resource.forFailure(response.getError())); + } } } } diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java b/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java index 7afb3c727..90ef80223 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java @@ -8,6 +8,7 @@ import android.support.annotation.RestrictTo; import android.support.v7.app.AppCompatActivity; +import com.firebase.ui.auth.ErrorCodes; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.data.model.FlowParameters; import com.firebase.ui.auth.ui.credentials.CredentialSaveActivity; @@ -42,6 +43,10 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == RequestCodes.CRED_SAVE_FLOW) { finish(resultCode, data); } + + if (resultCode == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { + finish(resultCode, data); + } } public FlowParameters getFlowParams() { diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java index cd0e1130d..80930de72 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java @@ -212,7 +212,7 @@ public void showProgress(int message) { @Override public void hideProgress() { - mNextButton.setEnabled(true); - mProgressBar.setVisibility(View.INVISIBLE); + mNextButton.setEnabled(true); + mProgressBar.setVisibility(View.INVISIBLE); } } 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 6e0bb14e7..592d9b5ab 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 @@ -25,6 +25,7 @@ import android.support.v4.view.ViewCompat; import com.firebase.ui.auth.AuthUI; +import com.firebase.ui.auth.ErrorCodes; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.R; import com.firebase.ui.auth.data.model.FlowParameters; @@ -42,7 +43,7 @@ * WelcomeBackIdpPrompt}. */ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -public class EmailActivity extends AppCompatBase implements CheckEmailFragment.CheckEmailListener { +public class EmailActivity extends AppCompatBase implements CheckEmailFragment.CheckEmailListener, RegisterEmailFragment.AnonymousUpgradeListener { public static Intent createIntent(Context context, FlowParameters flowParams) { return createIntent(context, flowParams, null); } @@ -127,6 +128,13 @@ public void onNewUser(User user) { } } + @Override + public void onMergeFailure(IdpResponse response) { + Intent data = new Intent(); + data.putExtra(ExtraConstants.IDP_RESPONSE, response); + finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, data); + } + private void setSlideAnimation() { // Make the next activity slide in overridePendingTransition(R.anim.fui_slide_in_right, R.anim.fui_slide_out_left); diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java index cee53d4b5..5ef09d1cc 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java @@ -17,6 +17,7 @@ import android.widget.TextView; import com.firebase.ui.auth.AuthUI; +import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.R; import com.firebase.ui.auth.data.model.User; @@ -61,6 +62,18 @@ public class RegisterEmailFragment extends FragmentBase implements private User mUser; + /** + * Interface to be implemented by Activities hosting this Fragment. + */ + interface AnonymousUpgradeListener { + + /** + * Email belongs to an existing user - failed to merge anonymous user. + */ + void onMergeFailure(IdpResponse response); + + } + public static RegisterEmailFragment newInstance(User user) { RegisterEmailFragment fragment = new RegisterEmailFragment(); Bundle args = new Bundle(); @@ -98,6 +111,9 @@ protected void onFailure(@NonNull Exception e) { R.integer.fui_min_password_length)); } else if (e instanceof FirebaseAuthInvalidCredentialsException) { mEmailInput.setError(getString(R.string.fui_invalid_email_address)); + } else if (e instanceof FirebaseAuthAnonymousUpgradeException) { + IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse(); + ((AnonymousUpgradeListener) getActivity()).onMergeFailure(response); } else { // General error message, this branch should not be invoked but // covers future API changes diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java index 2c2ace31e..2d0f0c864 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java @@ -35,6 +35,8 @@ import android.widget.ProgressBar; import android.widget.TextView; +import com.firebase.ui.auth.ErrorCodes; +import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.R; import com.firebase.ui.auth.data.model.FlowParameters; @@ -120,7 +122,12 @@ protected void onSuccess(@NonNull IdpResponse response) { @Override protected void onFailure(@NonNull Exception e) { - mPasswordLayout.setError(getString(getErrorMessage(e))); + if (e instanceof FirebaseAuthAnonymousUpgradeException) { + IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse(); + onMergeFailure(response); + } else { + mPasswordLayout.setError(getString(getErrorMessage(e))); + } } }); @@ -128,6 +135,12 @@ protected void onFailure(@NonNull Exception e) { PrivacyDisclosureUtils.setupTermsOfServiceFooter(this, getFlowParams(), footerText); } + public void onMergeFailure(IdpResponse response) { + Intent data = new Intent(); + data.putExtra(ExtraConstants.IDP_RESPONSE, response); + finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, data); + } + @StringRes private int getErrorMessage(Exception exception) { if (exception instanceof FirebaseAuthInvalidCredentialsException) { diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/AnonymousUpgradeUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/data/AnonymousUpgradeUtils.java new file mode 100644 index 000000000..ed040e7a9 --- /dev/null +++ b/auth/src/main/java/com/firebase/ui/auth/util/data/AnonymousUpgradeUtils.java @@ -0,0 +1,50 @@ +package com.firebase.ui.auth.util.data; + +import android.support.annotation.NonNull; +import android.support.annotation.RestrictTo; + +import com.firebase.ui.auth.data.model.FlowParameters; +import com.google.android.gms.tasks.Continuation; +import com.google.android.gms.tasks.Task; +import com.google.firebase.FirebaseApp; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.EmailAuthProvider; +import com.google.firebase.auth.FirebaseAuth; + +import java.util.UUID; + +/** + * Utilities to help with Anonymous user upgrade. + */ +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +public class AnonymousUpgradeUtils { + + public static Task createUserWithEmailAndPasswordOrLink(@NonNull FirebaseAuth auth, + @NonNull FlowParameters flowParameters, + @NonNull String email, + @NonNull String password) { + if (canUpgradeAnonymous(auth, flowParameters)) { + AuthCredential credential = EmailAuthProvider.getCredential(email, password); + return auth.getCurrentUser().linkWithCredential(credential); + } else { + return auth.createUserWithEmailAndPassword(email, password); + } + } + + public static boolean canUpgradeAnonymous(FirebaseAuth auth, FlowParameters flowParameters) { + return flowParameters.isAnonymousUpgradeEnabled() && auth.getCurrentUser() != null && + auth.getCurrentUser().isAnonymous(); + } + + @NonNull + public static Task validateCredential(FirebaseApp app, AuthCredential credential) { + // Create a new FirebaseApp so that the anonymous user state is not lost in our + // original FirebaseAuth instance. + String randomName = UUID.randomUUID().toString(); + FirebaseApp scratchApp = FirebaseApp.initializeApp( + app.getApplicationContext(), app.getOptions(), randomName); + FirebaseAuth scratchAuth = FirebaseAuth.getInstance(scratchApp); + return scratchAuth.signInWithCredential(credential); + } +} diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java index 0ba3dfb20..ea5518bd2 100644 --- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java +++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java @@ -4,6 +4,8 @@ import android.support.annotation.NonNull; import android.support.annotation.RestrictTo; +import com.firebase.ui.auth.ErrorCodes; +import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.data.model.IntentRequiredException; import com.firebase.ui.auth.data.model.Resource; @@ -11,12 +13,14 @@ import com.firebase.ui.auth.data.remote.ProfileMerger; import com.firebase.ui.auth.ui.email.WelcomeBackPasswordPrompt; import com.firebase.ui.auth.ui.idp.WelcomeBackIdpPrompt; +import com.firebase.ui.auth.util.data.AnonymousUpgradeUtils; import com.firebase.ui.auth.util.data.ProviderUtils; import com.firebase.ui.auth.util.data.TaskFailureLogger; import com.firebase.ui.auth.viewmodel.RequestCodes; import com.firebase.ui.auth.viewmodel.SignInViewModelBase; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.EmailAuthProvider; import com.google.firebase.auth.FirebaseAuthUserCollisionException; @@ -29,7 +33,7 @@ public EmailProviderResponseHandler(Application application) { super(application); } - public void startSignIn(@NonNull final IdpResponse response, @NonNull String password) { + public void startSignIn(@NonNull final IdpResponse response, @NonNull final String password) { if (!response.isSuccessful()) { setResult(Resource.forFailure(response.getError())); return; @@ -41,7 +45,10 @@ public void startSignIn(@NonNull final IdpResponse response, @NonNull String pas setResult(Resource.forLoading()); final String email = response.getEmail(); - getAuth().createUserWithEmailAndPassword(email, password) + AnonymousUpgradeUtils.createUserWithEmailAndPasswordOrLink(getAuth(), + getArguments(), + email, + password) .continueWithTask(new ProfileMerger(response)) .addOnFailureListener(new TaskFailureLogger(TAG, "Error creating user")) .addOnSuccessListener(new OnSuccessListener() { @@ -54,16 +61,29 @@ public void onSuccess(AuthResult result) { @Override public void onFailure(@NonNull Exception e) { if (e instanceof FirebaseAuthUserCollisionException) { - // Collision with existing user email, it should be very hard for - // the user to even get to this error due to CheckEmailFragment. - ProviderUtils.fetchTopProvider(getAuth(), email) - .addOnSuccessListener(new StartWelcomeBackFlow(email)) - .addOnFailureListener(new OnFailureListener() { - @Override - public void onFailure(@NonNull Exception e) { - setResult(Resource.forFailure(e)); - } - }); + if (AnonymousUpgradeUtils.canUpgradeAnonymous(getAuth(), + getArguments())) { + AuthCredential credential = EmailAuthProvider.getCredential(email, + password); + IdpResponse failureResponse = new IdpResponse.Builder(credential) + .build(); + + setResult(Resource.forFailure(new FirebaseAuthAnonymousUpgradeException( + ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, + failureResponse))); + } else { + // Collision with existing user email without anonymous upgrade + // it should be very hard for the user to even get to this error + // due to CheckEmailFragment. + ProviderUtils.fetchTopProvider(getAuth(), email) + .addOnSuccessListener(new StartWelcomeBackFlow(email)) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + setResult(Resource.forFailure(e)); + } + }); + } } else { setResult(Resource.forFailure(e)); } diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java index 1527b11b6..392c89332 100644 --- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java +++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java @@ -5,16 +5,20 @@ import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; +import com.firebase.ui.auth.ErrorCodes; +import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.data.model.Resource; import com.firebase.ui.auth.data.model.User; import com.firebase.ui.auth.data.remote.ProfileMerger; +import com.firebase.ui.auth.util.data.AnonymousUpgradeUtils; import com.firebase.ui.auth.util.data.TaskFailureLogger; import com.firebase.ui.auth.viewmodel.SignInViewModelBase; import com.google.android.gms.tasks.Continuation; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.Tasks; +import com.google.firebase.FirebaseApp; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.EmailAuthProvider; @@ -61,38 +65,64 @@ public void startSignIn(@NonNull final String email, .build(); } - // Kick off the flow including signing in, linking accounts, and saving with SmartLock - getAuth().signInWithEmailAndPassword(email, password) - .continueWithTask(new Continuation>() { - @Override - public Task then(@NonNull Task task) throws Exception { - // Forward task failure by asking for result - AuthResult result = task.getResult(Exception.class); + // We first check if we are trying to upgrade an anonymous user + // Calling linkWithCredential will fail, so we can save an RPC call + // We just need to validate the credential + if (AnonymousUpgradeUtils.canUpgradeAnonymous(getAuth(), getArguments())) { + final AuthCredential credToValidate = EmailAuthProvider.getCredential(email, password); - // Task succeeded, link user if necessary - if (credential == null) { - return Tasks.forResult(result); - } else { - return result.getUser() - .linkWithCredential(credential) - .continueWithTask(new ProfileMerger(outputResponse)) - .addOnFailureListener(new TaskFailureLogger(TAG, "linkWithCredential+merge failed.")); + AnonymousUpgradeUtils.validateCredential(FirebaseApp.getInstance(), credToValidate) + .continueWith(new Continuation() { + @Override + public Void then(@NonNull Task task) throws Exception { + if (task.isSuccessful()) { + IdpResponse mergeResponse = new IdpResponse.Builder(credToValidate) + .build(); + setResult(Resource.forFailure(new FirebaseAuthAnonymousUpgradeException( + ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, + mergeResponse))); + } else { + setResult(Resource.forFailure(task.getException())); + } + return null; } - } - }) - .addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (!task.isSuccessful()) { - setResult(Resource.forFailure(task.getException())); - return; + }); + } else { + // Kick off the flow including signing in, linking accounts, and saving with SmartLock + getAuth().signInWithEmailAndPassword(email, password) + .continueWithTask(new Continuation>() { + @Override + public Task then(@NonNull Task task) throws Exception { + // Forward task failure by asking for result + AuthResult result = task.getResult(Exception.class); + + // Task succeeded, link user if necessary + if (credential == null) { + return Tasks.forResult(result); + } else { + return result.getUser() + .linkWithCredential(credential) + .continueWithTask(new ProfileMerger(outputResponse)) + .addOnFailureListener(new TaskFailureLogger(TAG, + "linkWithCredential+merge failed.")); + } } + }) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + setResult(Resource.forFailure(task.getException())); + return; + } + + handleSuccess(outputResponse, task.getResult()); + } + }) + .addOnFailureListener( + new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed.")); + } - handleSuccess(outputResponse, task.getResult()); - } - }) - .addOnFailureListener( - new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed.")); } /** 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 92d57d69c..a6302e7fa 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,7 +126,8 @@ public static FlowParameters getFlowParameters(Collection providerIds) { null, null, true, - true); + true, + false); } } From 2037e851e2c3747c2c80d7f2eda7b86742110f10 Mon Sep 17 00:00:00 2001 From: Leonardo Siracusa Date: Thu, 14 Jun 2018 15:20:59 -0700 Subject: [PATCH 02/17] Changes based on review --- app/src/main/AndroidManifest.xml | 3 + .../com/firebase/uidemo/ChooserActivity.java | 4 + .../uidemo/auth/AnonymousUpgradeActivity.java | 197 ++++++++++++++++++ .../firebase/uidemo/auth/AuthUiActivity.java | 59 ++---- .../res/layout/activity_anonymous_upgrade.xml | 68 ++++++ app/src/main/res/values/strings.xml | 6 + .../com/firebase/ui/auth/IdpResponse.java | 4 +- .../auth/data/remote/EmailSignInHandler.java | 5 +- .../auth/data/remote/SignInKickstarter.java | 15 +- .../auth/ui/email/RegisterEmailFragment.java | 7 +- .../auth/util/data/AnonymousUpgradeUtils.java | 23 +- .../ui/auth/util/data/FirebaseAppManager.java | 20 ++ .../email/EmailProviderResponseHandler.java | 2 +- .../email/WelcomeBackPasswordHandler.java | 9 +- 14 files changed, 354 insertions(+), 68 deletions(-) create mode 100644 app/src/main/java/com/firebase/uidemo/auth/AnonymousUpgradeActivity.java create mode 100644 app/src/main/res/layout/activity_anonymous_upgrade.xml create mode 100644 auth/src/main/java/com/firebase/ui/auth/util/data/FirebaseAppManager.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0a381a18c..0a6d84862 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,6 +37,9 @@ + { private static final Class[] CLASSES = new Class[]{ AuthUiActivity.class, + AnonymousUpgradeActivity.class, FirestoreChatActivity.class, FirestorePagingActivity.class, RealtimeDbChatActivity.class, @@ -61,6 +63,7 @@ private static class ActivityChooserAdapter extends RecyclerView.Adapter() { + @Override + public void onComplete(@NonNull Task task) { + updateUI(); + + if (task.isSuccessful()) { + setStatus("Signed in anonymously as user " + + getUserIdentifier(task.getResult().getUser())); + } else { + setStatus("Anonymous sign in failed."); + } + } + }); + } + + @OnClick(R.id.begin_flow) + public void startAuthUI() { + List providers = Arrays.asList( + new AuthUI.IdpConfig.EmailBuilder().build(), + new AuthUI.IdpConfig.PhoneBuilder().build(), + new AuthUI.IdpConfig.GoogleBuilder().build()); + + Intent intent = AuthUI.getInstance().createSignInIntentBuilder() + .setAvailableProviders(providers) + .setIsSmartLockEnabled(false) + .setAutoUpgradeAnonymousUsers() + .build(); + + startActivityForResult(intent, RC_SIGN_IN); + } + + @OnClick(R.id.resolve_merge) + public void resolveMerge() { + if (mPendingCredential == null) { + Toast.makeText(this, "Nothing to resolve.", Toast.LENGTH_SHORT).show(); + return; + } + + // TODO: Show how to do good data moving + + FirebaseAuth.getInstance().signInWithCredential(mPendingCredential) + .addOnCompleteListener(this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + mPendingCredential = null; + updateUI(); + + if (task.isSuccessful()) { + setStatus("Signed in as " + getUserIdentifier(task.getResult().getUser())); + } else { + Log.w(TAG, "Merge failed", task.getException()); + setStatus("Failed to resolve merge conflict, see logs."); + } + } + }); + } + + @OnClick(R.id.sign_out) + public void signOut() { + AuthUI.getInstance().signOut(this) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + setStatus(null); + updateUI(); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == RC_SIGN_IN) { + IdpResponse response = IdpResponse.fromResultIntent(data); + if (resultCode == RESULT_OK) { + setStatus("Signed in as " + getUserIdentifier(FirebaseAuth.getInstance().getCurrentUser())); + } else { + if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { + setStatus("Merge conflict: user already exists."); + mResolveMergeButton.setEnabled(true); + mPendingCredential = response.getCredentialForLinking(); + } + } + + updateUI(); + } + } + + private void updateUI() { + FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); + + if (currentUser == null) { + // Not signed in + mAnonSignInButton.setEnabled(true); + mLaunchUIButton.setEnabled(false); + mResolveMergeButton.setEnabled(false); + mSignOutButton.setEnabled(false); + } else if (mPendingCredential == null && currentUser.isAnonymous()) { + // Anonymous user, waiting for linking + mAnonSignInButton.setEnabled(false); + mLaunchUIButton.setEnabled(true); + mResolveMergeButton.setEnabled(false); + mSignOutButton.setEnabled(true); + } else if (mPendingCredential == null && !currentUser.isAnonymous()) { + // Fully signed in + mAnonSignInButton.setEnabled(false); + mLaunchUIButton.setEnabled(false); + mResolveMergeButton.setEnabled(false); + mSignOutButton.setEnabled(true); + } else if (mPendingCredential != null) { + // Signed in anonymous, awaiting merge conflict + mAnonSignInButton.setEnabled(false); + mLaunchUIButton.setEnabled(false); + mResolveMergeButton.setEnabled(true); + mSignOutButton.setEnabled(true); + } + } + + private void setStatus(String message) { + mStatus.setText(message); + } + + private String getUserIdentifier(FirebaseUser user) { + if (user.isAnonymous()) { + return user.getUid(); + } else if (!TextUtils.isEmpty(user.getEmail())) { + return user.getEmail(); + } else if (!TextUtils.isEmpty(user.getPhoneNumber())) { + return user.getPhoneNumber(); + } else { + return "unknown"; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java index 61141d668..2fc9ab5bf 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java @@ -156,25 +156,17 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @OnClick(R.id.sign_in) public void signIn(View view) { - FirebaseAuth.getInstance() - .signInAnonymously() - .addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - startActivityForResult( - AuthUI.getInstance().createSignInIntentBuilder() - .setTheme(getSelectedTheme()) - .setLogo(getSelectedLogo()) - .setAvailableProviders(getSelectedProviders()) - .setTosAndPrivacyPolicyUrls(getSelectedTosUrl(), - getSelectedPrivacyPolicyUrl()) - .setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(), - mEnableHintSelector.isChecked()) - .setAutoUpgradeAnonymousUsers() - .build(), - RC_SIGN_IN); - } - }); + startActivityForResult( + AuthUI.getInstance().createSignInIntentBuilder() + .setTheme(getSelectedTheme()) + .setLogo(getSelectedLogo()) + .setAvailableProviders(getSelectedProviders()) + .setTosAndPrivacyPolicyUrls(getSelectedTosUrl(), + getSelectedPrivacyPolicyUrl()) + .setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(), + mEnableHintSelector.isChecked()) + .build(), + RC_SIGN_IN); } @OnClick(R.id.sign_in_silent) @@ -203,11 +195,11 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { @Override protected void onResume() { super.onResume(); -// FirebaseAuth auth = FirebaseAuth.getInstance(); -// if (auth.getCurrentUser() != null) { -// startSignedInActivity(null); -// finish(); -// } + FirebaseAuth auth = FirebaseAuth.getInstance(); + if (auth.getCurrentUser() != null) { + startSignedInActivity(null); + finish(); + } } private void handleSignInResponse(int resultCode, Intent data) { @@ -230,25 +222,6 @@ private void handleSignInResponse(int resultCode, Intent data) { return; } - if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { - AuthCredential credential = response.getCredentialForLinking(); - // take data from anon user - // log in with credential - // update user - FirebaseAuth.getInstance().signInWithCredential(credential).addOnCompleteListener( - new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - startSignedInActivity(response); - } else { - // cry - } - } - }); - return; - } - showSnackbar(R.string.unknown_error); Log.e(TAG, "Sign-in error: ", response.getError()); } diff --git a/app/src/main/res/layout/activity_anonymous_upgrade.xml b/app/src/main/res/layout/activity_anonymous_upgrade.xml new file mode 100644 index 000000000..84139dd52 --- /dev/null +++ b/app/src/main/res/layout/activity_anonymous_upgrade.xml @@ -0,0 +1,68 @@ + + + + + + + + +