permissions) {
return this;
}
}
+
+ /**
+ * {@link IdpConfig} builder for the Anonymous provider.
+ */
+ public static final class AnonymousBuilder extends Builder {
+ public AnonymousBuilder() {
+ super(ANONYMOUS_PROVIDER);
+ }
+ }
}
/**
@@ -1066,7 +1084,8 @@ public T setTosAndPrivacyPolicyUrls(@NonNull String tosUrl,
/**
* Specified the set of supported authentication providers. At least one provider must
- * be specified. There may only be one instance of each provider.
+ * be specified. There may only be one instance of each provider. Anonymous provider cannot
+ * be the only provider specified.
*
*
If no providers are explicitly specified by calling this method, then the email
* provider is the default supported provider.
@@ -1074,9 +1093,19 @@ public T setTosAndPrivacyPolicyUrls(@NonNull String tosUrl,
* @param idpConfigs a list of {@link IdpConfig}s, where each {@link IdpConfig} contains the
* configuration parameters for the IDP.
* @see IdpConfig
+ *
+ * @throws IllegalStateException if anonymous provider is the only specified provider.
*/
@NonNull
public T setAvailableProviders(@NonNull List idpConfigs) {
+ Preconditions.checkNotNull(idpConfigs, "idpConfigs cannot be null");
+ if (idpConfigs.size() == 1 &&
+ idpConfigs.get(0).getProviderId().equals(ANONYMOUS_PROVIDER)) {
+ throw new IllegalStateException("Sign in as guest cannot be the only sign in " +
+ "method. In this case, sign the user in anonymously your self; " +
+ "no UI is needed.");
+ }
+
mProviders.clear();
for (IdpConfig config : idpConfigs) {
@@ -1139,20 +1168,22 @@ public Intent build() {
* Builder for the intent to start the user authentication flow.
*/
public final class SignInIntentBuilder extends AuthIntentBuilder {
-
- private boolean mEnableAnonymousUpgrade;
+ private boolean mIsAccountLinkingEnabled = false;
+ private Class extends ManualMergeService> mAccountLinkingListener;
private SignInIntentBuilder() {
super();
}
/**
- * Enables upgrading anonymous accounts to full accounts during the sign-in flow.
- * This is disabled by default.
+ * Links the current user to an account created in the sign-in flow.
+ *
+ * Linking is disabled by default because of a caveat.
*/
- @NonNull
- public SignInIntentBuilder enableAnonymousUsersAutoUpgrade() {
- mEnableAnonymousUpgrade = true;
+ public SignInIntentBuilder setIsAccountLinkingEnabled(boolean enabled,
+ @Nullable Class extends ManualMergeService> listener) {
+ mIsAccountLinkingEnabled = enabled;
+ mAccountLinkingListener = listener;
return this;
}
@@ -1167,7 +1198,8 @@ protected FlowParameters getFlowParams() {
mPrivacyPolicyUrl,
mEnableCredentials,
mEnableHints,
- mEnableAnonymousUpgrade);
+ mIsAccountLinkingEnabled,
+ mAccountLinkingListener);
}
}
}
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 fca246ac4..f49a714bd 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java
@@ -19,9 +19,7 @@ public final class ErrorCodes {
NO_NETWORK,
PLAY_SERVICES_UPDATE_CANCELLED,
DEVELOPER_ERROR,
- PROVIDER_ERROR,
- ANONYMOUS_UPGRADE_MERGE_CONFLICT,
- EMAIL_MISMATCH_ERROR
+ PROVIDER_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface Code {}
@@ -51,17 +49,6 @@ public final class ErrorCodes {
*/
public static final int PROVIDER_ERROR = 4;
- /**
- * Anonymous account linking failed.
- */
- public static final int ANONYMOUS_UPGRADE_MERGE_CONFLICT = 5;
-
- /**
- * Signing in with a different email in the WelcomeBackIdp flow.
- */
- public static final int EMAIL_MISMATCH_ERROR = 6;
-
-
private ErrorCodes() {
throw new AssertionError("No instance for you!");
}
@@ -80,11 +67,6 @@ public static String toFriendlyMessage(@Code int code) {
return "Developer error";
case PROVIDER_ERROR:
return "Provider error";
- case ANONYMOUS_UPGRADE_MERGE_CONFLICT:
- return "User account merge conflict";
- case EMAIL_MISMATCH_ERROR:
- return "You are are attempting to sign in a different email than previously " +
- "provided";
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
deleted file mode 100644
index 7f859f4a8..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.firebase.ui.auth;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class FirebaseAuthAnonymousUpgradeException extends Exception {
-
- private IdpResponse mResponse;
-
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public FirebaseAuthAnonymousUpgradeException(@ErrorCodes.Code int code,
- @NonNull IdpResponse response) {
- super(ErrorCodes.toFriendlyMessage(code));
- mResponse = response;
- }
-
- public IdpResponse getResponse() {
- return mResponse;
- }
-}
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 18157aa5b..3a1f70da6 100644
--- a/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java
+++ b/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java
@@ -25,7 +25,6 @@
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;
@@ -45,8 +44,7 @@ public IdpResponse createFromParcel(Parcel in) {
in.readString(),
in.readString(),
in.readInt() == 1,
- (FirebaseUiException) in.readSerializable(),
- in.readParcelable(AuthCredential.class.getClassLoader())
+ (FirebaseUiException) in.readSerializable()
);
}
@@ -57,7 +55,6 @@ public IdpResponse[] newArray(int size) {
};
private final User mUser;
- private final AuthCredential mPendingCredential;
private final String mToken;
private final String mSecret;
@@ -66,7 +63,7 @@ public IdpResponse[] newArray(int size) {
private final FirebaseUiException mException;
private IdpResponse(@NonNull FirebaseUiException e) {
- this(null, null, null, false, e, null);
+ this(null, null, null, false, e);
}
private IdpResponse(
@@ -74,11 +71,7 @@ private IdpResponse(
@Nullable String token,
@Nullable String secret,
boolean isNewUser) {
- this(user, token, secret, isNewUser, null, null);
- }
-
- private IdpResponse(AuthCredential credential, FirebaseUiException e) {
- this(null, null, null, false, e, credential);
+ this(user, token, secret, isNewUser, null);
}
private IdpResponse(
@@ -86,14 +79,12 @@ private IdpResponse(
String token,
String secret,
boolean isNewUser,
- FirebaseUiException e,
- AuthCredential credential) {
+ FirebaseUiException e) {
mUser = user;
mToken = token;
mSecret = secret;
mIsNewUser = isNewUser;
mException = e;
- mPendingCredential = credential;
}
/**
@@ -208,6 +199,20 @@ public String getIdpSecret() {
return mSecret;
}
+ /**
+ * Only applies to developers using {@link AuthUI.SignInIntentBuilder#setIsAccountLinkingEnabled(boolean, Class)}
+ * set to {@code true}.
+ *
+ * Get the previous user id if a user collision occurred.
+ * See the README
+ * for a much more detailed explanation.
+ *
+ * @see AuthUI.SignInIntentBuilder#setIsAccountLinkingEnabled(boolean, Class)
+ */
+ public String getPrevUid() {
+ return mUser.getPrevUid();
+ }
+
/**
* Get the error for a failed sign in.
*/
@@ -216,11 +221,6 @@ public FirebaseUiException getError() {
return mException;
}
- @Nullable
- public AuthCredential getCredentialForLinking() {
- return mPendingCredential;
- }
-
@Override
public int describeContents() {
return 0;
@@ -255,8 +255,6 @@ public void writeToParcel(Parcel dest, int flags) {
} catch (IOException ignored) {}
}
}
-
- dest.writeParcelable(mPendingCredential, 0);
}
@Override
@@ -270,9 +268,7 @@ public boolean equals(Object o) {
&& (mToken == null ? response.mToken == null : mToken.equals(response.mToken))
&& (mSecret == null ? response.mSecret == null : mSecret.equals(response.mSecret))
&& (mIsNewUser == response.mIsNewUser)
- && (mException == null ? response.mException == null : mException.equals(response.mException))
- && (mPendingCredential == null ? response.mPendingCredential == null :
- mPendingCredential.getProvider().equals(response.mPendingCredential.getProvider()));
+ && (mException == null ? response.mException == null : mException.equals(response.mException));
}
@Override
@@ -282,7 +278,6 @@ public int hashCode() {
result = 31 * result + (mSecret == null ? 0 : mSecret.hashCode());
result = 31 * result + (mIsNewUser ? 1 : 0);
result = 31 * result + (mException == null ? 0 : mException.hashCode());
- result = 31 * result + (mPendingCredential == null ? 0 : mPendingCredential.getProvider().hashCode());
return result;
}
@@ -294,14 +289,12 @@ public String toString() {
", mSecret='" + mSecret + '\'' +
", mIsNewUser='" + mIsNewUser + '\'' +
", mException=" + mException +
- ", mPendingCredential=" + mPendingCredential +
'}';
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static class Builder {
private final User mUser;
- private final AuthCredential mPendingCredential;
private String mToken;
private String mSecret;
@@ -309,12 +302,6 @@ 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) {
@@ -322,7 +309,6 @@ public Builder(@NonNull IdpResponse response) {
mToken = response.mToken;
mSecret = response.mSecret;
mIsNewUser = response.mIsNewUser;
- mPendingCredential = response.mPendingCredential;
}
public Builder setNewUser(boolean newUser) {
@@ -341,10 +327,6 @@ public Builder setSecret(String secret) {
}
public IdpResponse build() {
- if (mPendingCredential != null) {
- return new IdpResponse(mPendingCredential, new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT));
- }
-
String providerId = mUser.getProviderId();
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
throw new IllegalStateException("Unknown provider: " + providerId);
@@ -358,6 +340,7 @@ public IdpResponse build() {
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 e1ad3104d..27438e7c3 100644
--- a/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java
@@ -13,7 +13,6 @@
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;
@@ -42,9 +41,6 @@ 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 4cde51957..339e57ad4 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
@@ -26,6 +26,7 @@
import com.firebase.ui.auth.AuthUI.IdpConfig;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.Preconditions;
+import com.firebase.ui.auth.util.accountlink.ManualMergeService;
import java.util.Collections;
import java.util.List;
@@ -54,9 +55,12 @@ public class FlowParameters implements Parcelable {
@Nullable
public final String privacyPolicyUrl;
+ public final boolean accountLinkingEnabled;
+ @Nullable
+ public final Class extends ManualMergeService> accountLinkingListener;
+
public final boolean enableCredentials;
public final boolean enableHints;
- public final boolean enableAnonymousUpgrade;
public FlowParameters(
@NonNull String appName,
@@ -67,7 +71,8 @@ public FlowParameters(
@Nullable String privacyPolicyUrl,
boolean enableCredentials,
boolean enableHints,
- boolean enableAnonymousUpgrade) {
+ boolean accountLinkingEnabled,
+ @Nullable Class extends ManualMergeService> accountLinkingListener) {
this.appName = Preconditions.checkNotNull(appName, "appName cannot be null");
this.providerInfo = Collections.unmodifiableList(
Preconditions.checkNotNull(providerInfo, "providerInfo cannot be null"));
@@ -77,7 +82,8 @@ public FlowParameters(
this.privacyPolicyUrl = privacyPolicyUrl;
this.enableCredentials = enableCredentials;
this.enableHints = enableHints;
- this.enableAnonymousUpgrade = enableAnonymousUpgrade;
+ this.accountLinkingEnabled = accountLinkingEnabled;
+ this.accountLinkingListener = accountLinkingListener;
}
/**
@@ -97,7 +103,8 @@ 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);
+ dest.writeInt(accountLinkingEnabled ? 1 : 0);
+ dest.writeSerializable(accountLinkingListener);
}
@Override
@@ -116,7 +123,10 @@ public FlowParameters createFromParcel(Parcel in) {
String privacyPolicyUrl = in.readString();
boolean enableCredentials = in.readInt() != 0;
boolean enableHints = in.readInt() != 0;
- boolean enableAnonymousUpgrade = in.readInt() != 0;
+ boolean accountLinkingEnabled = in.readInt() != 0;
+ Class extends ManualMergeService> accountLinkingListener =
+ (Class extends ManualMergeService>) in.readSerializable();
+
return new FlowParameters(
appName,
@@ -127,7 +137,8 @@ public FlowParameters createFromParcel(Parcel in) {
privacyPolicyUrl,
enableCredentials,
enableHints,
- enableAnonymousUpgrade);
+ accountLinkingEnabled,
+ accountLinkingListener);
}
@Override
@@ -147,8 +158,4 @@ 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/User.java b/auth/src/main/java/com/firebase/ui/auth/data/model/User.java
index 9201490a8..083900b81 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/model/User.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/model/User.java
@@ -22,7 +22,8 @@ public User createFromParcel(Parcel in) {
in.readString(),
in.readString(),
in.readString(),
- in.readParcelable(Uri.class.getClassLoader()));
+ in.readParcelable(Uri.class.getClassLoader()),
+ in.readString());
}
@Override
@@ -37,12 +38,20 @@ public User[] newArray(int size) {
private final String mName;
private final Uri mPhotoUri;
- private User(String providerId, String email, String phoneNumber, String name, Uri photoUri) {
+ private String mPrevUid;
+
+ private User(String providerId,
+ String email,
+ String phoneNumber,
+ String name,
+ Uri photoUri,
+ String prevUid) {
mProviderId = providerId;
mEmail = email;
mPhoneNumber = phoneNumber;
mName = name;
mPhotoUri = photoUri;
+ mPrevUid = prevUid;
}
public static User getUser(Intent intent) {
@@ -79,6 +88,15 @@ public Uri getPhotoUri() {
return mPhotoUri;
}
+ @Nullable
+ public String getPrevUid() {
+ return mPrevUid;
+ }
+
+ public void setPrevUid(@Nullable String prevUid) {
+ mPrevUid = prevUid;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -90,7 +108,8 @@ public boolean equals(Object o) {
&& (mEmail == null ? user.mEmail == null : mEmail.equals(user.mEmail))
&& (mPhoneNumber == null ? user.mPhoneNumber == null : mPhoneNumber.equals(user.mPhoneNumber))
&& (mName == null ? user.mName == null : mName.equals(user.mName))
- && (mPhotoUri == null ? user.mPhotoUri == null : mPhotoUri.equals(user.mPhotoUri));
+ && (mPhotoUri == null ? user.mPhotoUri == null : mPhotoUri.equals(user.mPhotoUri))
+ && (mPrevUid == null ? user.mPrevUid == null : mPrevUid.equals(user.mPrevUid));
}
@Override
@@ -100,6 +119,7 @@ public int hashCode() {
result = 31 * result + (mPhoneNumber == null ? 0 : mPhoneNumber.hashCode());
result = 31 * result + (mName == null ? 0 : mName.hashCode());
result = 31 * result + (mPhotoUri == null ? 0 : mPhotoUri.hashCode());
+ result = 31 * result + (mPrevUid == null ? 0 : mPrevUid.hashCode());
return result;
}
@@ -111,6 +131,7 @@ public String toString() {
", mPhoneNumber='" + mPhoneNumber + '\'' +
", mName='" + mName + '\'' +
", mPhotoUri=" + mPhotoUri +
+ ", mPrevUid=" + mPrevUid +
'}';
}
@@ -126,6 +147,7 @@ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mPhoneNumber);
dest.writeString(mName);
dest.writeParcelable(mPhotoUri, flags);
+ dest.writeString(mPrevUid);
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -136,6 +158,8 @@ public static class Builder {
private String mName;
private Uri mPhotoUri;
+ private String mPrevUid;
+
public Builder(@AuthUI.SupportedProvider @NonNull String providerId,
@Nullable String email) {
mProviderId = providerId;
@@ -157,8 +181,13 @@ public Builder setPhotoUri(Uri photoUri) {
return this;
}
+ public Builder setPrevUid(String prevUid) {
+ mPrevUid = prevUid;
+ return this;
+ }
+
public User build() {
- return new User(mProviderId, mEmail, mPhoneNumber, mName, mPhotoUri);
+ return new User(mProviderId, mEmail, mPhoneNumber, mName, mPhotoUri, mPrevUid);
}
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/AnonymousSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/AnonymousSignInHandler.java
new file mode 100644
index 000000000..5e3f771c4
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/AnonymousSignInHandler.java
@@ -0,0 +1,79 @@
+package com.firebase.ui.auth.data.remote;
+
+import android.app.Application;
+import android.content.Intent;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+
+import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.data.model.FlowParameters;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.data.model.User;
+import com.firebase.ui.auth.ui.HelperActivityBase;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuth;
+
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class AnonymousSignInHandler extends ProviderSignInBase {
+
+ @VisibleForTesting
+ public FirebaseAuth mAuth;
+
+ public AnonymousSignInHandler(Application application) {
+ super(application);
+ }
+
+ @Override
+ protected void onCreate() {
+ mAuth = getAuth();
+ }
+
+ @Override
+ public void startSignIn(@NonNull HelperActivityBase activity) {
+ setResult(Resource.forLoading());
+
+ // Calling signInAnonymously() will always return the same anonymous user if already
+ // available. This is enforced by the client SDK.
+ mAuth.signInAnonymously()
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ setResult(Resource.forSuccess(initResponse(
+ result.getAdditionalUserInfo().isNewUser())));
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
+
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {}
+
+ private IdpResponse initResponse(boolean isNewUser) {
+ return new IdpResponse.Builder(
+ new User.Builder(AuthUI.ANONYMOUS_PROVIDER, null)
+ .build())
+ .setNewUser(isNewUser)
+ .build();
+ }
+
+ // TODO: We need to centralize the auth logic. ProviderSignInBase classes were originally
+ // meant to only retrieve remote provider data.
+ private FirebaseAuth getAuth() {
+ FirebaseApp app = FirebaseApp.getInstance(getArguments().appName);
+ return FirebaseAuth.getInstance(app);
+ }
+}
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 67c8d5fd3..f65cc01cd 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,7 +6,6 @@
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;
@@ -30,9 +29,7 @@ public void startSignIn(@NonNull HelperActivityBase activity) {
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
- if (resultCode == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
- // The activity deals with this case. This conflict is handled by the developer.
- } else if (requestCode == RequestCodes.EMAIL_FLOW) {
+ if (requestCode == RequestCodes.EMAIL_FLOW) {
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/GitHubSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/GitHubSignInHandler.java
index 8498f5b49..20992bc77 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/GitHubSignInHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/GitHubSignInHandler.java
@@ -80,8 +80,15 @@ private static IdpResponse createIdpResponse(
@Override
protected void onCreate() {
- List permissions = new ArrayList<>(getArguments().getParams()
- .getStringArrayList(ExtraConstants.GITHUB_PERMISSIONS));
+ List permissions = getArguments().getParams()
+ .getStringArrayList(ExtraConstants.GITHUB_PERMISSIONS);
+
+ if (permissions == null) {
+ permissions = new ArrayList<>();
+ } else {
+ permissions = new ArrayList<>(permissions);
+ }
+
if (!permissions.contains(EMAIL_PERMISSION)) {
permissions.add(EMAIL_PERMISSION);
}
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 5a6826576..56420fbd5 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,7 +9,6 @@
import android.text.TextUtils;
import com.firebase.ui.auth.AuthUI;
-import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.IntentRequiredException;
import com.firebase.ui.auth.data.model.PendingIntentRequiredException;
@@ -22,6 +21,7 @@
import com.firebase.ui.auth.ui.phone.PhoneActivity;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.GoogleApiUtils;
+import com.firebase.ui.auth.util.accountlink.ManualMergeUtils;
import com.firebase.ui.auth.util.data.ProviderUtils;
import com.firebase.ui.auth.viewmodel.RequestCodes;
import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
@@ -47,6 +47,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Callable;
public class SignInKickstarter extends SignInViewModelBase {
public SignInKickstarter(Application application) {
@@ -184,9 +185,6 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
setResult(Resource.forFailure(new UserCancellationException()));
} else if (response.isSuccessful()) {
setResult(Resource.forSuccess(response));
- } else if (response.getError().getErrorCode() ==
- ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
- handleMergeFailure(response);
} else {
setResult(Resource.forFailure(response.getError()));
}
@@ -194,8 +192,8 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
}
private void handleCredential(final Credential credential) {
- String id = credential.getId();
- String password = credential.getPassword();
+ final String id = credential.getId();
+ final String password = credential.getPassword();
if (TextUtils.isEmpty(password)) {
String identity = credential.getAccountType();
if (identity == null) {
@@ -205,11 +203,24 @@ private void handleCredential(final Credential credential) {
ProviderUtils.accountTypeToProviderId(credential.getAccountType()), id);
}
} else {
- final IdpResponse response = new IdpResponse.Builder(
- new User.Builder(EmailAuthProvider.PROVIDER_ID, id).build()).build();
+ // Because we are being called from Smart Lock,
+ // we can assume that the account already exists and a user collision exception will be
+ // thrown so we don't bother with linking credentials
+ final IdpResponse response =
+ new IdpResponse.Builder(new User.Builder(EmailAuthProvider.PROVIDER_ID, id)
+ .setPrevUid(getUidForAccountLinking())
+ .build()).build();
setResult(Resource.forLoading());
- getAuth().signInWithEmailAndPassword(id, password)
+ ManualMergeUtils.injectSignInTaskBetweenDataTransfer(getApplication(),
+ response,
+ getArguments(),
+ new Callable>() {
+ @Override
+ public Task call() {
+ return getAuth().signInWithEmailAndPassword(id, password);
+ }
+ })
.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(AuthResult result) {
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 3a017d0bb..7afb3c727 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,7 +8,6 @@
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;
@@ -40,8 +39,7 @@ protected static Intent createBaseIntent(
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Forward the results of Smart Lock saving
- if (requestCode == RequestCodes.CRED_SAVE_FLOW
- || resultCode == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
+ if (requestCode == RequestCodes.CRED_SAVE_FLOW) {
finish(resultCode, data);
}
}
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 80930de72..cd0e1130d 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 2b21c2f94..6e0bb14e7 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,7 +25,6 @@
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;
@@ -43,8 +42,7 @@
* WelcomeBackIdpPrompt}.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class EmailActivity extends AppCompatBase implements CheckEmailFragment.CheckEmailListener,
- RegisterEmailFragment.AnonymousUpgradeListener {
+public class EmailActivity extends AppCompatBase implements CheckEmailFragment.CheckEmailListener {
public static Intent createIntent(Context context, FlowParameters flowParams) {
return createIntent(context, flowParams, null);
}
@@ -143,9 +141,4 @@ public void showProgress(@StringRes int message) {
public void hideProgress() {
throw new UnsupportedOperationException("Email fragments must handle progress updates.");
}
-
- @Override
- public void onMergeFailure(IdpResponse response) {
- finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
- }
}
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 2dd7d6938..cee53d4b5 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
@@ -7,7 +7,6 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.design.widget.TextInputLayout;
-import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -18,7 +17,6 @@
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,21 +59,8 @@ public class RegisterEmailFragment extends FragmentBase implements
private PasswordFieldValidator mPasswordFieldValidator;
private BaseValidator mNameValidator;
- private AnonymousUpgradeListener mListener;
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();
@@ -113,9 +98,6 @@ 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();
- mListener.onMergeFailure(response);
} else {
// General error message, this branch should not be invoked but
// covers future API changes
@@ -215,13 +197,7 @@ public void run() {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- FragmentActivity activity = requireActivity();
- activity.setTitle(R.string.fui_title_register_email);
- if (!(activity instanceof AnonymousUpgradeListener)) {
- throw new IllegalStateException("Activity must implement CheckEmailListener");
- }
- mListener = (AnonymousUpgradeListener) activity;
-
+ requireActivity().setTitle(R.string.fui_title_register_email);
}
@Override
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 45218c32d..2c2ace31e 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,8 +35,6 @@
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;
@@ -122,12 +120,7 @@ protected void onSuccess(@NonNull IdpResponse response) {
@Override
protected void onFailure(@NonNull Exception e) {
- if (e instanceof FirebaseAuthAnonymousUpgradeException) {
- IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
- finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
- } else {
- mPasswordLayout.setError(getString(getErrorMessage(e)));
- }
+ mPasswordLayout.setError(getString(getErrorMessage(e)));
}
});
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java
index f0d35c160..4f9c78333 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java
@@ -34,13 +34,11 @@
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.AuthUI.IdpConfig;
-import com.firebase.ui.auth.ErrorCodes;
-import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
-import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.data.model.UserCancellationException;
+import com.firebase.ui.auth.data.remote.AnonymousSignInHandler;
import com.firebase.ui.auth.data.remote.EmailSignInHandler;
import com.firebase.ui.auth.data.remote.FacebookSignInHandler;
import com.firebase.ui.auth.data.remote.GitHubSignInHandler;
@@ -114,14 +112,9 @@ protected void onSuccess(@NonNull IdpResponse response) {
@Override
protected void onFailure(@NonNull Exception e) {
- if (e instanceof FirebaseAuthAnonymousUpgradeException) {
- finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT,
- ((FirebaseAuthAnonymousUpgradeException) e).getResponse().toIntent());
- } else if ( (!(e instanceof UserCancellationException))) {
- String text = e instanceof FirebaseUiException ? e.getMessage() :
- getString(R.string.fui_error_unknown);
+ if (!(e instanceof UserCancellationException)) {
Toast.makeText(AuthMethodPickerActivity.this,
- text,
+ R.string.fui_error_unknown,
Toast.LENGTH_SHORT).show();
}
}
@@ -186,6 +179,13 @@ private void populateIdpList(List providerConfigs,
buttonLayout = R.layout.fui_provider_button_phone;
break;
+ case AuthUI.ANONYMOUS_PROVIDER:
+ AnonymousSignInHandler anonymous = supplier.get(AnonymousSignInHandler.class);
+ anonymous.init(getFlowParams());
+ provider = anonymous;
+
+ buttonLayout = R.layout.fui_provider_button_anonymous;
+ break;
default:
throw new IllegalStateException("Unknown provider: " + providerId);
}
@@ -215,8 +215,9 @@ private void handleResponse(@NonNull IdpResponse response) {
// started.
handler.startSignIn(response);
} else {
- // Email or phone: the credentials should have already been saved so simply
- // move along.
+ // Email or phone: the credentials should have already been saved so
+ // simply move along. Anononymous sign in also does not require any
+ // other operations.
finish(response.isSuccessful() ? RESULT_OK : RESULT_CANCELED,
response.toIntent());
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java b/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java
index ae5634026..910bc7c20 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java
@@ -31,7 +31,6 @@
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.ErrorCodes;
-import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
@@ -91,9 +90,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
supplier.get(LinkingSocialProviderResponseHandler.class);
handler.init(getFlowParams());
if (requestedUserResponse != null) {
- handler.setRequestedSignInCredentialForEmail(
- ProviderUtils.getAuthCredential(requestedUserResponse),
- existingUser.getEmail());
+ handler.setRequestedSignInCredential(
+ ProviderUtils.getAuthCredential(requestedUserResponse));
}
String providerId = existingUser.getProviderId();
@@ -174,12 +172,7 @@ protected void onSuccess(@NonNull IdpResponse response) {
@Override
protected void onFailure(@NonNull Exception e) {
- if (e instanceof FirebaseAuthAnonymousUpgradeException) {
- IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
- finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
- } else {
- finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e));
- }
+ finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e));
}
});
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java
index 2dccd14ff..f843d3add 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java
@@ -24,8 +24,6 @@
import android.support.design.widget.TextInputLayout;
import android.widget.Toast;
-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;
@@ -46,6 +44,8 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class PhoneActivity extends AppCompatBase {
+ private PhoneNumberVerificationHandler mPhoneVerifier;
+
public static Intent createIntent(Context context, FlowParameters params, Bundle args) {
return createBaseIntent(context, PhoneActivity.class, params)
.putExtra(ExtraConstants.PARAMS, args);
@@ -72,10 +72,10 @@ protected void onFailure(@NonNull Exception e) {
}
});
- final PhoneNumberVerificationHandler phoneVerifier =
- ViewModelProviders.of(this).get(PhoneNumberVerificationHandler.class);
- phoneVerifier.init(getFlowParams());
- phoneVerifier.getOperation().observe(this, new ResourceObserver(
+ mPhoneVerifier = ViewModelProviders.of(this).get(PhoneNumberVerificationHandler.class);
+ mPhoneVerifier.init(getFlowParams());
+ mPhoneVerifier.onRestoreInstanceState(savedInstanceState);
+ mPhoneVerifier.getOperation().observe(this, new ResourceObserver(
this, R.string.fui_verifying) {
@Override
protected void onSuccess(@NonNull PhoneVerification verification) {
@@ -121,6 +121,12 @@ protected void onFailure(@NonNull Exception e) {
.commit();
}
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mPhoneVerifier.onSaveInstanceState(outState);
+ }
+
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
@@ -134,10 +140,7 @@ private void handleError(@Nullable Exception e) {
TextInputLayout errorView = getErrorView();
if (errorView == null) { return; }
- if (e instanceof FirebaseAuthAnonymousUpgradeException) {
- IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
- finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
- } else if (e instanceof FirebaseAuthException) {
+ if (e instanceof FirebaseAuthException) {
errorView.setError(getErrorMessage(
FirebaseAuthError.fromException((FirebaseAuthException) e)));
} else if (e != null) {
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java
index ee1ffe53b..a00151006 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java
@@ -1,7 +1,9 @@
package com.firebase.ui.auth.ui.phone;
import android.app.Application;
+import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.firebase.ui.auth.data.model.PhoneNumberVerificationRequiredException;
import com.firebase.ui.auth.data.model.Resource;
@@ -15,6 +17,7 @@
public class PhoneNumberVerificationHandler extends AuthViewModelBase {
private static final long AUTO_RETRIEVAL_TIMEOUT_SECONDS = 120;
+ private static final String VERIFICATION_ID_KEY = "verification_id";
private String mVerificationId;
private PhoneAuthProvider.ForceResendingToken mForceResendingToken;
@@ -60,4 +63,14 @@ public void submitVerificationCode(String number, String code) {
PhoneAuthProvider.getCredential(mVerificationId, code),
false)));
}
+
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putString(VERIFICATION_ID_KEY, mVerificationId);
+ }
+
+ public void onRestoreInstanceState(@Nullable Bundle savedInstanceState) {
+ if (mVerificationId == null && savedInstanceState != null) {
+ mVerificationId = savedInstanceState.getString(VERIFICATION_ID_KEY);
+ }
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/accountlink/AccountLinker.java b/auth/src/main/java/com/firebase/ui/auth/util/accountlink/AccountLinker.java
new file mode 100644
index 000000000..1c1e04970
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/util/accountlink/AccountLinker.java
@@ -0,0 +1,182 @@
+package com.firebase.ui.auth.util.accountlink;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.data.remote.ProfileMerger;
+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.Task;
+import com.google.android.gms.tasks.Tasks;
+import com.google.firebase.auth.AuthCredential;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuthUserCollisionException;
+import com.google.firebase.auth.FirebaseUser;
+
+import java.util.concurrent.Callable;
+
+/**
+ * "One link to rule them all." - AccountLinker
+ *
+ * AccountLinker can handle up to 3 way account linking: user is currently logged in anonymously,
+ * has an existing Google account, and is trying to log in with Facebook. Results: Google and
+ * Facebook are linked and the uid of the anonymous account is returned for manual merging.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class AccountLinker {
+ private static final String TAG = "AccountLinker";
+
+ private final SignInViewModelBase mHandler;
+ private final IdpResponse mIdpResponse;
+
+ /** The credential of the user's existing account. */
+ private final AuthCredential mExistingCredential;
+
+ /** The credential the user originally tried to sign in with. */
+ @Nullable private final AuthCredential mNewCredential;
+
+ private final Task mTask;
+
+ private AccountLinker(SignInViewModelBase handler,
+ IdpResponse response,
+ @NonNull AuthCredential existingCredential,
+ @Nullable AuthCredential newCredential) {
+ mHandler = handler;
+ mIdpResponse = response;
+ mExistingCredential = existingCredential;
+ mNewCredential = newCredential;
+
+ mTask = start();
+ }
+
+ public static Task linkWithCurrentUser(SignInViewModelBase handler,
+ IdpResponse response,
+ AuthCredential existingCredential) {
+ return new AccountLinker(handler, response, existingCredential, null).mTask;
+ }
+
+ public static Task linkToNewUser(SignInViewModelBase handler,
+ IdpResponse response,
+ AuthCredential existingCredential,
+ AuthCredential newCredential) {
+ return new AccountLinker(handler, response, existingCredential, newCredential).mTask;
+ }
+
+ private Task start() {
+ FirebaseUser currentUser = mHandler.getCurrentUser();
+ if (currentUser == null) {
+ // The user has an existing account and is trying to log in with a new provider
+ return mHandler.getAuth()
+ .signInWithCredential(mExistingCredential)
+ .continueWithTask(new NoCurrentUser())
+ .addOnFailureListener(
+ new TaskFailureLogger(TAG, "Error signing in with new credential"));
+ } else {
+ // If the current user is trying to sign in with a new account, just link the two
+ // and we should be fine. Otherwise, we are probably working with an anonymous account
+ // trying to be linked to an existing account which is bound to fail.
+ return currentUser
+ .linkWithCredential(mNewCredential == null ? mExistingCredential : mNewCredential)
+ .continueWithTask(new ProfileMerger(mIdpResponse))
+ .continueWithTask(new ExistingUser())
+ .addOnFailureListener(
+ new TaskFailureLogger(TAG, "Error linking with credential"));
+ }
+ }
+
+ private final class NoCurrentUser implements Continuation> {
+ @Override
+ public Task then(@NonNull Task task) {
+ if (mNewCredential == null) {
+ return task;
+ } else {
+ // Link the user's existing account (mExistingCredential) with the account they were
+ // trying to sign in to (mNewCredential)
+ return task.getResult().getUser()
+ .linkWithCredential(mNewCredential)
+ .continueWithTask(new ProfileMerger(mIdpResponse))
+ .addOnFailureListener(new TaskFailureLogger(
+ TAG, "Error signing in with previous credential"));
+ }
+ }
+ }
+
+ private final class ExistingUser implements Continuation> {
+ @Override
+ public Task then(@NonNull final Task task) {
+ final Exception e = task.getException();
+ if (e instanceof FirebaseAuthUserCollisionException && mHandler.canLinkAccounts()) {
+ mIdpResponse.getUser()
+ .setPrevUid(mHandler.getUidForAccountLinking());
+
+ // Since we still want the user to be able to sign in even though
+ // they have an existing account, we are going to save the uid of the
+ // current user, log them out, and then sign in with the new credential.
+ Task signInTask = ManualMergeUtils.injectSignInTaskBetweenDataTransfer(
+ mHandler.getApplication(),
+ mIdpResponse,
+ mHandler.getArguments(),
+ new Callable>() {
+ @Override
+ public Task call() {
+ AuthCredential existingCred =
+ ((FirebaseAuthUserCollisionException) e)
+ .getUpdatedCredential();
+ if (existingCred == null) { existingCred = mExistingCredential; }
+
+ return mHandler.getAuth()
+ .signInWithCredential(existingCred)
+ .continueWithTask(new ProfileMerger(mIdpResponse))
+ .continueWithTask(new ExceptionWrapper(task));
+ }
+ })
+ .addOnFailureListener(
+ new TaskFailureLogger(TAG, "Error signing in with credential"));
+
+ // Occurs when the user is logged and they are trying to sign in with an existing account.
+ if (mNewCredential == null) {
+ return signInTask;
+ } else {
+ // 3 way account linking!!!
+ // Occurs if the user is logged, trying to sign in with a new provider,
+ // and already has existing providers.
+ return signInTask.continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) {
+ return mHandler.getCurrentUser()
+ .linkWithCredential(mNewCredential)
+ .continueWithTask(new ProfileMerger(mIdpResponse))
+ .continueWithTask(new ExceptionWrapper(task))
+ .addOnFailureListener(
+ new TaskFailureLogger(TAG,
+ "Error linking with credential"));
+ }
+ });
+ }
+ } else {
+ return task;
+ }
+ }
+
+ private final class ExceptionWrapper implements Continuation> {
+ private final Task mWrapped;
+
+ public ExceptionWrapper(Task wrapped) {
+ mWrapped = wrapped;
+ }
+
+ @Override
+ public Task then(@NonNull Task task) {
+ try {
+ task.getResult(Exception.class);
+ return task;
+ } catch (Exception e) {
+ return Tasks.forException((Exception) e.initCause(mWrapped.getException()));
+ }
+ }
+ }
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeService.java b/auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeService.java
new file mode 100644
index 000000000..352c6e692
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeService.java
@@ -0,0 +1,50 @@
+package com.firebase.ui.auth.util.accountlink;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.support.annotation.Nullable;
+
+import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.IdpResponse;
+import com.google.android.gms.tasks.Task;
+
+/**
+ * This service is to be used in conjunction with {@link AuthUI.SignInIntentBuilder#setIsAccountLinkingEnabled(boolean,
+ * Class)}. See a detailed explanation on how
+ * to use this service.
+ */
+public abstract class ManualMergeService extends Service {
+ private final IBinder mBinder = new ManualMergeUtils.MergeBinder(this);
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * During this phase of the login process, you should load any data to be transferred from the
+ * current user to a new one created in the sign-in flow.
+ *
+ * Note: this service will stay alive until {@link #onTransferData(IdpResponse)}
+ * completes so you may store your data in a field.
+ *
+ * @return a task to load your user's data or null if you can load the data synchronously
+ * without blocking the main thread. The login process will wait to create the new user until
+ * this task completes thus allowing you to work around security rules.
+ */
+ @Nullable
+ public abstract Task onLoadData();
+
+ /**
+ * During this phase of the login process, you should transfer the data you loaded in {@link
+ * #onLoadData()} to the new user's account.
+ *
+ * @param response the new user's metadata
+ * @return a task to transfer the old user's data to the new one or null if you don't need to
+ * wait for the data to be transferred. Note: the sign-in won't complete until this task
+ * is complete.
+ */
+ @Nullable
+ public abstract Task onTransferData(IdpResponse response);
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeUtils.java
new file mode 100644
index 000000000..6f851f4fb
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeUtils.java
@@ -0,0 +1,167 @@
+package com.firebase.ui.auth.util.accountlink;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.firebase.ui.auth.IdpResponse;
+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.android.gms.tasks.TaskCompletionSource;
+import com.google.android.gms.tasks.Tasks;
+
+import java.util.concurrent.Callable;
+
+public final class ManualMergeUtils {
+ private ManualMergeUtils() {
+ throw new AssertionError("No instance for you!");
+ }
+
+ public static Task injectSignInTaskBetweenDataTransfer(
+ final Context context,
+ final IdpResponse response,
+ final FlowParameters params,
+ final Callable> insertTask) {
+ if (response.getUser().getPrevUid() == null || params.accountLinkingListener == null) try {
+ return insertTask.call();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+
+ final ServiceConnection keepServiceAliveConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {}
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {}
+ };
+ bindService(context, params, keepServiceAliveConnection);
+
+ return getLoadDataTask(context, params)
+ .continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ task.getResult();
+ return insertTask.call();
+ }
+ })
+ .continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) {
+ task.getResult();
+ return getTransferDataTask(context, response, params, task);
+ }
+ })
+ .continueWith(new Continuation() {
+ @Override
+ public T then(@NonNull Task task) {
+ unbindService(context, keepServiceAliveConnection);
+ return task.getResult();
+ }
+ });
+ }
+
+ private static Task getLoadDataTask(Context context, FlowParameters params) {
+ return getDataTask(context, params, new MergeServiceConnection() {
+ @Override
+ protected Task getDataTask(ManualMergeService service) {
+ return service.onLoadData();
+ }
+ });
+ }
+
+ private static Task getTransferDataTask(Context context,
+ final IdpResponse response,
+ final FlowParameters params,
+ final Task originalTask) {
+ return getDataTask(context, params, new MergeServiceConnection() {
+ @Override
+ protected Task getDataTask(ManualMergeService service) {
+ return service.onTransferData(response);
+ }
+ }).continueWith(new Continuation() {
+ @Override
+ public T then(@NonNull Task task) {
+ return originalTask.getResult();
+ }
+ });
+ }
+
+ private static Task getDataTask(final Context context,
+ final FlowParameters params,
+ final MergeServiceConnection connection) {
+ TaskCompletionSource task = new TaskCompletionSource<>();
+ bindService(context, params, connection.setTask(task));
+ return task.getTask().continueWith(new Continuation() {
+ @Override
+ public Void then(@NonNull Task task) {
+ unbindService(context, connection);
+ return task.getResult();
+ }
+ });
+ }
+
+ private static void bindService(Context context,
+ FlowParameters params,
+ ServiceConnection connection) {
+ Context appContext = context.getApplicationContext();
+ appContext.bindService(
+ new Intent(appContext, params.accountLinkingListener),
+ connection,
+ Context.BIND_AUTO_CREATE);
+ }
+
+ private static void unbindService(Context context, ServiceConnection connection) {
+ context.getApplicationContext().unbindService(connection);
+ }
+
+ public static final class MergeBinder extends Binder {
+ private final ManualMergeService mService;
+
+ public MergeBinder(ManualMergeService service) {
+ mService = service;
+ }
+
+ public ManualMergeService getService() {
+ return mService;
+ }
+ }
+
+ private abstract static class MergeServiceConnection implements ServiceConnection {
+ protected TaskCompletionSource mTask;
+
+ protected MergeServiceConnection setTask(TaskCompletionSource task) {
+ mTask = task;
+ return this;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Task task = getDataTask(((MergeBinder) service).getService());
+
+ if (task == null) { task = Tasks.forResult(null); }
+
+ task.continueWith(new Continuation() {
+ @Override
+ public Void then(@NonNull Task task) {
+ mTask.setResult(null);
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mTask.trySetException(new IllegalStateException("ManualMergeService disconnected"));
+ }
+
+ @Nullable
+ protected abstract Task getDataTask(ManualMergeService service);
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/AuthOperationManager.java b/auth/src/main/java/com/firebase/ui/auth/util/data/AuthOperationManager.java
deleted file mode 100644
index 1a5288a5d..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/util/data/AuthOperationManager.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.firebase.ui.auth.util.data;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-
-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;
-
-/**
- * Utilities to help with Anonymous user upgrade.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class AuthOperationManager {
-
- private static String firebaseAppName = "FUIScratchApp";
-
- private static AuthOperationManager mAuthManager;
-
- @VisibleForTesting
- public FirebaseAuth mScratchAuth;
-
- private AuthOperationManager() {}
-
- public static synchronized AuthOperationManager getInstance() {
- if (mAuthManager == null) {
- mAuthManager = new AuthOperationManager();
- }
- return mAuthManager;
- }
-
- private FirebaseApp getScratchApp(FirebaseApp defaultApp) {
- try {
- return FirebaseApp.getInstance(firebaseAppName);
- } catch (IllegalStateException e) {
- return FirebaseApp.initializeApp(defaultApp.getApplicationContext(),
- defaultApp.getOptions(), firebaseAppName);
- }
- }
-
- private FirebaseAuth getScratchAuth(FlowParameters flowParameters) {
- // Use a different FirebaseApp so that the anonymous user state is not lost in our
- // original FirebaseAuth instance.
- if (mScratchAuth == null) {
- FirebaseApp app = FirebaseApp.getInstance(flowParameters.appName);
- mScratchAuth = FirebaseAuth.getInstance(getScratchApp(app));
- }
- return mScratchAuth;
- }
-
- public Task createOrLinkUserWithEmailAndPassword(@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 Task signInAndLinkWithCredential(@NonNull FirebaseAuth auth,
- @NonNull FlowParameters flowParameters,
- @NonNull AuthCredential credential) {
- if (canUpgradeAnonymous(auth, flowParameters)) {
- return auth.getCurrentUser().linkWithCredential(credential);
- } else {
- return auth.signInWithCredential(credential);
- }
- }
-
- public boolean canUpgradeAnonymous(FirebaseAuth auth, FlowParameters flowParameters) {
- return flowParameters.isAnonymousUpgradeEnabled() && auth.getCurrentUser() != null &&
- auth.getCurrentUser().isAnonymous();
- }
-
- @NonNull
- public Task validateCredential(AuthCredential credential,
- FlowParameters flowParameters) {
- return getScratchAuth(flowParameters).signInWithCredential(credential);
- }
-
- public Task safeLink(final AuthCredential credential,
- final AuthCredential credentialToLink,
- final FlowParameters flowParameters) {
- return getScratchAuth(flowParameters)
- .signInWithCredential(credential)
- .continueWithTask(new Continuation>() {
- @Override
- public Task then(@NonNull Task task) throws Exception {
- if (task.isSuccessful()) {
- return task.getResult().getUser().linkWithCredential(credentialToLink);
- }
- return task;
- }
- });
- }
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java
index 6f3254607..209a1ab63 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java
@@ -21,7 +21,6 @@
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.IdpResponse;
-import com.firebase.ui.auth.util.Preconditions;
import com.google.android.gms.auth.api.credentials.IdentityProviders;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.Task;
@@ -163,11 +162,7 @@ public static Task fetchTopProvider(FirebaseAuth auth, @NonNull String e
.continueWith(new Continuation() {
@Override
public String then(@NonNull Task task) {
- if (!task.isSuccessful()) return null;
-
- List methods = task.getResult().getSignInMethods();
- return methods == null || methods.isEmpty()
- ? null : methods.get(methods.size() - 1);
+ return task.isSuccessful() ? getLastUsedProvider(task.getResult()) : null;
}
}).continueWith(new Continuation() {
@Override
@@ -182,13 +177,10 @@ public String then(@NonNull Task task) {
});
}
- public static String getTopProvider(@NonNull List providers) {
- return providers == null || providers.isEmpty() ? null :
- providers.get(providers.size() - 1);
- }
-
- public static boolean isExistingProvider(@NonNull List providers, String provider) {
- if (providers == null) throw new IllegalArgumentException("The list of providers is null.");
- return providers.contains(provider);
+ @Nullable
+ public static String getLastUsedProvider(SignInMethodQueryResult result) {
+ List methods = result.getSignInMethods();
+ return methods == null || methods.isEmpty()
+ ? null : methods.get(methods.size() - 1);
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/AuthViewModelBase.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/AuthViewModelBase.java
index c617807ce..7ec21f620 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/AuthViewModelBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/AuthViewModelBase.java
@@ -37,7 +37,7 @@ public FirebaseUser getCurrentUser() {
return mAuth.getCurrentUser();
}
- protected FirebaseAuth getAuth() {
+ public FirebaseAuth getAuth() {
return mAuth;
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java
index b47a6f6ec..33723acd7 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java
@@ -2,13 +2,11 @@
import android.app.Application;
import android.support.annotation.NonNull;
+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.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -22,19 +20,16 @@ protected void setResult(Resource output) {
super.setResult(output);
}
- protected void handleSuccess(@NonNull IdpResponse response, @NonNull AuthResult result) {
- setResult(Resource.forSuccess(response.withResult(result)));
+ public boolean canLinkAccounts() {
+ return getArguments().accountLinkingEnabled && getCurrentUser() != null;
}
- protected void handleMergeFailure(@NonNull AuthCredential credential) {
- IdpResponse failureResponse = new IdpResponse.Builder(credential).build();
- handleMergeFailure(failureResponse);
+ @Nullable
+ public String getUidForAccountLinking() {
+ return canLinkAccounts() ? getCurrentUser().getUid() : null;
}
- protected void handleMergeFailure(@NonNull IdpResponse failureResponse) {
- setResult(Resource.forFailure(new FirebaseAuthAnonymousUpgradeException(
- ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT,
- failureResponse)));
+ protected void handleSuccess(@NonNull IdpResponse response, @NonNull AuthResult result) {
+ setResult(Resource.forSuccess(response.withResult(result)));
}
-
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/ViewModelBase.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/ViewModelBase.java
index 05ae22c50..5917e20f8 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/ViewModelBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/ViewModelBase.java
@@ -26,7 +26,7 @@ public void init(T args) {
protected void onCreate() {}
- protected T getArguments() {
+ public T getArguments() {
return mArguments;
}
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 6287cb13f..2922168a2 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
@@ -11,14 +11,13 @@
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.AuthOperationManager;
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.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
@@ -31,7 +30,7 @@ public EmailProviderResponseHandler(Application application) {
super(application);
}
- public void startSignIn(@NonNull final IdpResponse response, @NonNull final String password) {
+ public void startSignIn(@NonNull final IdpResponse response, @NonNull String password) {
if (!response.isSuccessful()) {
setResult(Resource.forFailure(response.getError()));
return;
@@ -42,12 +41,15 @@ public void startSignIn(@NonNull final IdpResponse response, @NonNull final Stri
}
setResult(Resource.forLoading());
- final AuthOperationManager authOperationManager = AuthOperationManager.getInstance();
final String email = response.getEmail();
- authOperationManager.createOrLinkUserWithEmailAndPassword(getAuth(),
- getArguments(),
- email,
- password)
+ Task registerTask;
+ if (canLinkAccounts()) {
+ registerTask = getCurrentUser()
+ .linkWithCredential(EmailAuthProvider.getCredential(email, password));
+ } else {
+ registerTask = getAuth().createUserWithEmailAndPassword(email, password);
+ }
+ registerTask
.continueWithTask(new ProfileMerger(response))
.addOnFailureListener(new TaskFailureLogger(TAG, "Error creating user"))
.addOnSuccessListener(new OnSuccessListener() {
@@ -60,24 +62,16 @@ public void onSuccess(AuthResult result) {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof FirebaseAuthUserCollisionException) {
- if (authOperationManager.canUpgradeAnonymous(getAuth(),
- getArguments())) {
- AuthCredential credential = EmailAuthProvider.getCredential(email,
- password);
- handleMergeFailure(credential);
- } 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));
- }
- });
- }
+ // 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));
+ }
+ });
} 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 dbd860094..5258aea3a 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,24 +5,23 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
-import com.firebase.ui.auth.AuthUI;
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.AuthOperationManager;
+import com.firebase.ui.auth.util.accountlink.ManualMergeUtils;
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.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.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
+import java.util.concurrent.Callable;
+
/**
* Handles the logic for {@link com.firebase.ui.auth.ui.email.WelcomeBackPasswordPrompt} including
* signing in with email and password, linking other credentials, and saving credentials to
@@ -55,7 +54,8 @@ public void startSignIn(@NonNull final String email,
if (credential == null) {
// New credential for the email provider
outputResponse = new IdpResponse.Builder(
- new User.Builder(EmailAuthProvider.PROVIDER_ID, email).build())
+ new User.Builder(EmailAuthProvider.PROVIDER_ID, email)
+ .setPrevUid(getUidForAccountLinking()).build())
.build();
} else {
// New credential for an IDP (Phone or Social)
@@ -63,82 +63,52 @@ public void startSignIn(@NonNull final String email,
.setToken(inputResponse.getIdpToken())
.setSecret(inputResponse.getIdpSecret())
.build();
+ outputResponse.getUser().setPrevUid(getUidForAccountLinking());
}
- final AuthOperationManager authOperationManager = AuthOperationManager.getInstance();
- if (authOperationManager.canUpgradeAnonymous(getAuth(), getArguments())) {
- final AuthCredential credToValidate = EmailAuthProvider.getCredential(email, password);
-
- // Check to see if we need to link (for social providers with the same email)
- if (AuthUI.SOCIAL_PROVIDERS.contains(inputResponse.getProviderType())) {
- // Add the provider to the same account before triggering a merge failure.
- authOperationManager.safeLink(credToValidate, credential, getArguments())
- .addOnSuccessListener(new OnSuccessListener() {
- @Override
- public void onSuccess(AuthResult result) {
- handleMergeFailure(credToValidate);
- }
- })
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- setResult(Resource.forFailure(e));
- }
- });
- } else {
- // The user has not tried to log in with a federated IDP containing the same email.
- // In this case, we just need to verify that the credential they provided is valid.
- // No linking is done for non-federated IDPs.
- // A merge failure occurs because the account exists and the user is anonymous.
- authOperationManager.validateCredential(credToValidate, getArguments())
- .addOnCompleteListener(
- new OnCompleteListener() {
- @Override
- public void onComplete(@NonNull Task task) {
- if (task.isSuccessful()) {
- handleMergeFailure(credToValidate);
- } else {
- setResult(Resource.forFailure(task.getException()));
- }
- }
- });
- }
- } 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);
+ // Kick off the flow including signing in, linking accounts, and saving with SmartLock
+ ManualMergeUtils.injectSignInTaskBetweenDataTransfer(getApplication(),
+ outputResponse,
+ getArguments(),
+ new Callable>() {
+ @Override
+ public Task call() {
+ // Sign in with known email and the password provided
+ return 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."));
- }
+ // 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, "Error signing in with credential " +
+ credential.getProvider()));
}
- })
- .addOnSuccessListener(new OnSuccessListener() {
- @Override
- public void onSuccess(AuthResult result) {
- handleSuccess(outputResponse, result);
+ }
+ })
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (!task.isSuccessful()) {
+ setResult(Resource.forFailure(task.getException()));
+ return;
}
- })
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- setResult(Resource.forFailure(e));
- }
- })
- .addOnFailureListener(
- new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed."));
- }
+
+ handleSuccess(outputResponse, task.getResult());
+ }
+ })
+ .addOnFailureListener(
+ new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed."));
}
/**
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java
index 76e3ff152..4622e5b34 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java
@@ -6,34 +6,26 @@
import android.support.annotation.RestrictTo;
import com.firebase.ui.auth.AuthUI;
-import com.firebase.ui.auth.ErrorCodes;
-import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.Resource;
-import com.firebase.ui.auth.util.data.AuthOperationManager;
+import com.firebase.ui.auth.util.accountlink.AccountLinker;
import com.firebase.ui.auth.util.data.ProviderUtils;
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.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.AuthCredential;
import com.google.firebase.auth.AuthResult;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class LinkingSocialProviderResponseHandler extends SignInViewModelBase {
private AuthCredential mRequestedSignInCredential;
- private String mEmail;
+
public LinkingSocialProviderResponseHandler(Application application) {
super(application);
}
- public void setRequestedSignInCredentialForEmail(@Nullable AuthCredential credential,
- @Nullable String email) {
+ public void setRequestedSignInCredential(@Nullable AuthCredential credential) {
mRequestedSignInCredential = credential;
- mEmail = email;
}
public void startSignIn(@NonNull final IdpResponse response) {
@@ -45,81 +37,21 @@ public void startSignIn(@NonNull final IdpResponse response) {
throw new IllegalStateException(
"This handler cannot be used to link email or phone providers");
}
- if (mEmail != null && !mEmail.equals(response.getEmail())) {
- setResult(Resource.forFailure(new FirebaseUiException
- (ErrorCodes.EMAIL_MISMATCH_ERROR)));
- return;
- }
-
setResult(Resource.forLoading());
- final AuthOperationManager authOperationManager = AuthOperationManager.getInstance();
- final AuthCredential credential = ProviderUtils.getAuthCredential(response);
-
- if (authOperationManager.canUpgradeAnonymous(getAuth(), getArguments())) {
- if (mRequestedSignInCredential == null) {
- // The user has provided a valid credential by signing in with a federated
- // idp. linkWithCredential will fail because the user is anonymous and the account
- // exists (we're in the welcome back flow).
- // We know that they are signing in with the same IDP because requestSignInCredential
- // is null.
- // We just need to have the developer handle the merge failure.
- handleMergeFailure(credential);
- } else {
- // The user has logged in with an IDP that has the same email with another IDP
- // present on the account.
- // These IDPs belong to the same account - they must be linked, but we can't lose
- // our anonymous user session
- authOperationManager.safeLink(credential, mRequestedSignInCredential, getArguments())
- .addOnSuccessListener(new OnSuccessListener() {
- @Override
- public void onSuccess(AuthResult result) {
- handleMergeFailure(credential);
- }
- })
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- setResult(Resource.forFailure(e));
- }
- });
- }
- } else {
- getAuth().signInWithCredential(credential)
- .continueWithTask(new Continuation>() {
- @Override
- public Task then(@NonNull Task task) {
- final AuthResult result = task.getResult();
- if (mRequestedSignInCredential == null) {
- return Tasks.forResult(result);
- } else {
- return result.getUser()
- .linkWithCredential(mRequestedSignInCredential)
- .continueWith(new Continuation() {
- @Override
- public AuthResult then(@NonNull Task task) {
- if (task.isSuccessful()) {
- return task.getResult();
- } else {
- // Since we've already signed in, it's too late
- // to backtrack so we just ignore any errors.
- return result;
- }
- }
- });
- }
- }
- })
- .addOnCompleteListener(new OnCompleteListener() {
- @Override
- public void onComplete(@NonNull Task task) {
- if (task.isSuccessful()) {
- handleSuccess(response, task.getResult());
- } else {
- setResult(Resource.forFailure(task.getException()));
- }
- }
- });
- }
+ AuthCredential credential = ProviderUtils.getAuthCredential(response);
+ AccountLinker.linkToNewUser(this, response, credential, mRequestedSignInCredential)
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ handleSuccess(response, result);
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java
index 1ad639957..26f61bfcd 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java
@@ -17,12 +17,13 @@
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.AuthOperationManager;
+import com.firebase.ui.auth.util.accountlink.AccountLinker;
import com.firebase.ui.auth.util.data.ProviderUtils;
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.android.gms.tasks.Task;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
@@ -46,16 +47,19 @@ public void startSignIn(@NonNull final IdpResponse response) {
throw new IllegalStateException(
"This handler cannot be used with email or phone providers");
}
-
setResult(Resource.forLoading());
- final AuthCredential credential = ProviderUtils.getAuthCredential(response);
+ AuthCredential credential = ProviderUtils.getAuthCredential(response);
+ Task signInTask;
+ if (canLinkAccounts()) {
+ signInTask = getCurrentUser()
+ .linkWithCredential(credential)
+ .continueWithTask(new ProfileMerger(response));
+ } else {
+ signInTask = getAuth().signInWithCredential(credential);
+ }
- AuthOperationManager.getInstance().signInAndLinkWithCredential(
- getAuth(),
- getArguments(),
- credential)
- .continueWithTask(new ProfileMerger(response))
+ signInTask.continueWithTask(new ProfileMerger(response))
.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(AuthResult result) {
@@ -64,79 +68,26 @@ public void onSuccess(AuthResult result) {
})
.addOnFailureListener(new OnFailureListener() {
@Override
- public void onFailure(@NonNull final Exception e) {
- if (e instanceof FirebaseAuthUserCollisionException) {
- final String email = response.getEmail();
- if (email == null) {
- setResult(Resource.forFailure(e));
+ public void onFailure(@NonNull Exception e) {
+ String email = response.getEmail();
+ if (email != null) {
+ if (e instanceof FirebaseAuthUserCollisionException) {
+ getAuth().fetchSignInMethodsForEmail(email)
+ .addOnSuccessListener(new StartWelcomeBackFlow(response))
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
return;
}
- // There can be a collision due to:
- // CASE 1: Anon user signing in with a credential that belongs to an
- // existing user.
- // CASE 2: non - anon user signing in with a credential that does not
- // belong to an existing user, but the email matches an existing user
- // that has another social IDP. We need to link this new IDP to this
- // existing user.
- // CASE 3: CASE 2 with an anonymous user. We link the new IDP to the
- // same account before handling invoking a merge failure.
- getAuth().fetchSignInMethodsForEmail(email)
- .addOnSuccessListener(new OnSuccessListener() {
- @Override
- public void onSuccess(SignInMethodQueryResult result) {
- List providers = result.getSignInMethods();
- if (ProviderUtils.isExistingProvider(providers,
- response.getProviderType())) {
- // Case 1
- handleMergeFailure(credential);
- } else {
- // Case 2 & 3 - we need to link
- startWelcomeBackFlowForLinking(
- ProviderUtils.getTopProvider(providers),
- response);
- }
- }
- })
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- setResult(Resource.forFailure(
- e));
- }
- });
}
+ setResult(Resource.forFailure(e));
}
});
}
- public void startWelcomeBackFlowForLinking(String provider, IdpResponse response) {
- if (provider == null) {
- throw new IllegalStateException(
- "No provider even though we received a FirebaseAuthUserCollisionException");
- }
-
- if (provider.equals(EmailAuthProvider.PROVIDER_ID)) {
- // Start email welcome back flow
- setResult(Resource.forFailure(new IntentRequiredException(
- WelcomeBackPasswordPrompt.createIntent(
- getApplication(),
- getArguments(),
- response),
- RequestCodes.ACCOUNT_LINK_FLOW
- )));
- } else {
- // Start Idp welcome back flow
- setResult(Resource.forFailure(new IntentRequiredException(
- WelcomeBackIdpPrompt.createIntent(
- getApplication(),
- getArguments(),
- new User.Builder(provider, response.getEmail()).build(),
- response),
- RequestCodes.ACCOUNT_LINK_FLOW
- )));
- }
- }
-
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == RequestCodes.ACCOUNT_LINK_FLOW) {
IdpResponse response = IdpResponse.fromResultIntent(data);
@@ -155,4 +106,63 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
}
}
+ private class StartWelcomeBackFlow implements OnSuccessListener {
+ private final IdpResponse mResponse;
+
+ public StartWelcomeBackFlow(IdpResponse response) {
+ mResponse = response;
+ }
+
+ @Override
+ public void onSuccess(SignInMethodQueryResult result) {
+ List methods = result.getSignInMethods();
+ AuthCredential credential = ProviderUtils.getAuthCredential(mResponse);
+ if (canLinkAccounts() && credential != null
+ && methods != null && methods.contains(credential.getSignInMethod())) {
+ // We don't want to show the welcome back dialog since the user selected
+ // an existing account and we can just link the two accounts without knowing
+ // prevCredential.
+ AccountLinker.linkWithCurrentUser(
+ SocialProviderResponseHandler.this, mResponse, credential)
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ setResult(Resource.forSuccess(mResponse));
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
+ return;
+ }
+
+ @AuthUI.SupportedProvider String provider = ProviderUtils.getLastUsedProvider(result);
+ if (provider == null) {
+ throw new IllegalStateException(
+ "No provider even though we received a FirebaseAuthUserCollisionException");
+ } else if (provider.equals(EmailAuthProvider.PROVIDER_ID)) {
+ // Start email welcome back flow
+ setResult(Resource.forFailure(new IntentRequiredException(
+ WelcomeBackPasswordPrompt.createIntent(
+ getApplication(),
+ getArguments(),
+ mResponse),
+ RequestCodes.ACCOUNT_LINK_FLOW
+ )));
+ } else {
+ // Start Idp welcome back flow
+ setResult(Resource.forFailure(new IntentRequiredException(
+ WelcomeBackIdpPrompt.createIntent(
+ getApplication(),
+ getArguments(),
+ new User.Builder(provider, mResponse.getEmail()).build(),
+ mResponse),
+ RequestCodes.ACCOUNT_LINK_FLOW
+ )));
+ }
+ }
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java
index 4c8d5387f..e1a7736bd 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java
@@ -6,12 +6,11 @@
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.Resource;
-import com.firebase.ui.auth.util.data.AuthOperationManager;
+import com.firebase.ui.auth.util.accountlink.AccountLinker;
import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
-import com.google.android.gms.tasks.OnFailureListener;
-import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
-import com.google.firebase.auth.FirebaseAuthUserCollisionException;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;
@@ -31,29 +30,24 @@ public void startSignIn(@NonNull PhoneAuthCredential credential,
throw new IllegalStateException(
"This handler cannot be used without a phone response.");
}
-
setResult(Resource.forLoading());
- AuthOperationManager.getInstance()
- .signInAndLinkWithCredential(getAuth(), getArguments(), credential)
- .addOnSuccessListener(new OnSuccessListener() {
- @Override
- public void onSuccess(AuthResult result) {
- handleSuccess(response, result);
- }
- })
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- if (e instanceof FirebaseAuthUserCollisionException) {
- // With phone auth, this only happens if we are trying to upgrade
- // an anonymous account using a phone number that is already registered
- // on another account
- handleMergeFailure(((FirebaseAuthUserCollisionException) e).getUpdatedCredential());
- } else {
- setResult(Resource.forFailure(e));
- }
- }
- });
+ Task signInTask;
+ if (canLinkAccounts()) {
+ signInTask = AccountLinker.linkWithCurrentUser(this, response, credential);
+ } else {
+ signInTask = getAuth().signInWithCredential(credential);
+ }
+
+ signInTask.addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ handleSuccess(response, task.getResult());
+ } else {
+ setResult(Resource.forFailure(task.getException()));
+ }
+ }
+ });
}
}
diff --git a/auth/src/main/res/drawable/fui_ic_anonymous_white_24dp.xml b/auth/src/main/res/drawable/fui_ic_anonymous_white_24dp.xml
new file mode 100644
index 000000000..212818c29
--- /dev/null
+++ b/auth/src/main/res/drawable/fui_ic_anonymous_white_24dp.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/auth/src/main/res/drawable/fui_idp_button_background_anonymous.xml b/auth/src/main/res/drawable/fui_idp_button_background_anonymous.xml
new file mode 100644
index 000000000..19bf89f26
--- /dev/null
+++ b/auth/src/main/res/drawable/fui_idp_button_background_anonymous.xml
@@ -0,0 +1,19 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/auth/src/main/res/layout/fui_provider_button_anonymous.xml b/auth/src/main/res/layout/fui_provider_button_anonymous.xml
new file mode 100644
index 000000000..361d3c007
--- /dev/null
+++ b/auth/src/main/res/layout/fui_provider_button_anonymous.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/auth/src/main/res/values-ar/strings.xml b/auth/src/main/res/values-ar/strings.xml
index 30334a2a6..2d08f7a0c 100755
--- a/auth/src/main/res/values-ar/strings.xml
+++ b/auth/src/main/res/values-ar/strings.xml
@@ -13,6 +13,7 @@
تسجيل الدخول باستخدام GitHub
تسجيل الدخول عبر البريد الإلكتروني
تسجيل الدخول عبر رقم الهاتف
+ المتابعة كضيف
التالي
البريد الإلكتروني
رقم الهاتف
diff --git a/auth/src/main/res/values-b+es+419/strings.xml b/auth/src/main/res/values-b+es+419/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-b+es+419/strings.xml
+++ b/auth/src/main/res/values-b+es+419/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-bg/strings.xml b/auth/src/main/res/values-bg/strings.xml
index a3a67a10a..01c709045 100755
--- a/auth/src/main/res/values-bg/strings.xml
+++ b/auth/src/main/res/values-bg/strings.xml
@@ -13,6 +13,7 @@
Вход с GitHub
Вход с имейл
Вход с телефон
+ Продължаване като гост
Напред
Имейл
Телефонен номер
diff --git a/auth/src/main/res/values-bn/strings.xml b/auth/src/main/res/values-bn/strings.xml
index 340eb0429..80dbc4f92 100755
--- a/auth/src/main/res/values-bn/strings.xml
+++ b/auth/src/main/res/values-bn/strings.xml
@@ -13,6 +13,7 @@
GitHub ব্যবহার করে সাইন-ইন করুন
ইমেল দিয়ে সাইন-ইন করুন
ফোন দিয়ে সাইন-ইন করুন
+ অতিথি হিসেবে চালিয়ে যান
পরবর্তী
ইমেল
ফোন নম্বর
diff --git a/auth/src/main/res/values-ca/strings.xml b/auth/src/main/res/values-ca/strings.xml
index 0539229f8..fbbd1e0ec 100755
--- a/auth/src/main/res/values-ca/strings.xml
+++ b/auth/src/main/res/values-ca/strings.xml
@@ -13,6 +13,7 @@
Inicia la sessió amb GitHub
Inicia la sessió amb l\'adreça electrònica
Inicia la sessió amb el telèfon
+ Continua com a convidat
Següent
Adreça electrònica
Número de telèfon
diff --git a/auth/src/main/res/values-cs/strings.xml b/auth/src/main/res/values-cs/strings.xml
index e2c818e04..90082b66e 100755
--- a/auth/src/main/res/values-cs/strings.xml
+++ b/auth/src/main/res/values-cs/strings.xml
@@ -13,6 +13,7 @@
Přihlásit se přes GitHub
Přihlásit se pomocí e-mailu
Přihlásit se pomocí telefonu
+ Pokračovat jako host
Další
E-mail
Telefonní číslo
diff --git a/auth/src/main/res/values-da/strings.xml b/auth/src/main/res/values-da/strings.xml
index 9eb0b6061..d15057b74 100755
--- a/auth/src/main/res/values-da/strings.xml
+++ b/auth/src/main/res/values-da/strings.xml
@@ -13,6 +13,7 @@
Log ind med GitHub
Log ind med mail
Log ind med telefon
+ Fortsæt som gæst
Næste
Mail
Telefonnummer
diff --git a/auth/src/main/res/values-de-rAT/strings.xml b/auth/src/main/res/values-de-rAT/strings.xml
index ed621c961..1972b4fea 100755
--- a/auth/src/main/res/values-de-rAT/strings.xml
+++ b/auth/src/main/res/values-de-rAT/strings.xml
@@ -13,6 +13,7 @@
Über GitHub anmelden
Mit einer E-Mail-Adresse anmelden
Mit einer Telefonnummer anmelden
+ Als Gast fortfahren
Weiter
E-Mail-Adresse
Telefonnummer
diff --git a/auth/src/main/res/values-de-rCH/strings.xml b/auth/src/main/res/values-de-rCH/strings.xml
index ed621c961..1972b4fea 100755
--- a/auth/src/main/res/values-de-rCH/strings.xml
+++ b/auth/src/main/res/values-de-rCH/strings.xml
@@ -13,6 +13,7 @@
Über GitHub anmelden
Mit einer E-Mail-Adresse anmelden
Mit einer Telefonnummer anmelden
+ Als Gast fortfahren
Weiter
E-Mail-Adresse
Telefonnummer
diff --git a/auth/src/main/res/values-de/strings.xml b/auth/src/main/res/values-de/strings.xml
index ed621c961..1972b4fea 100755
--- a/auth/src/main/res/values-de/strings.xml
+++ b/auth/src/main/res/values-de/strings.xml
@@ -13,6 +13,7 @@
Über GitHub anmelden
Mit einer E-Mail-Adresse anmelden
Mit einer Telefonnummer anmelden
+ Als Gast fortfahren
Weiter
E-Mail-Adresse
Telefonnummer
diff --git a/auth/src/main/res/values-el/strings.xml b/auth/src/main/res/values-el/strings.xml
index d37fcf26f..ce56ca9ea 100755
--- a/auth/src/main/res/values-el/strings.xml
+++ b/auth/src/main/res/values-el/strings.xml
@@ -13,6 +13,7 @@
Σύνδεση μέσω GitHub
Σύνδεση μέσω ηλεκτρονικού ταχυδρομείου
Σύνδεση μέσω τηλεφώνου
+ Συνέχεια ως επισκέπτης
Επόμενο
Ηλεκτρονικό ταχυδρομείο
Αριθμός τηλεφώνου
diff --git a/auth/src/main/res/values-en-rAU/strings.xml b/auth/src/main/res/values-en-rAU/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rAU/strings.xml
+++ b/auth/src/main/res/values-en-rAU/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-en-rCA/strings.xml b/auth/src/main/res/values-en-rCA/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rCA/strings.xml
+++ b/auth/src/main/res/values-en-rCA/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-en-rGB/strings.xml b/auth/src/main/res/values-en-rGB/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rGB/strings.xml
+++ b/auth/src/main/res/values-en-rGB/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-en-rIE/strings.xml b/auth/src/main/res/values-en-rIE/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rIE/strings.xml
+++ b/auth/src/main/res/values-en-rIE/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-en-rIN/strings.xml b/auth/src/main/res/values-en-rIN/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rIN/strings.xml
+++ b/auth/src/main/res/values-en-rIN/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-en-rSG/strings.xml b/auth/src/main/res/values-en-rSG/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rSG/strings.xml
+++ b/auth/src/main/res/values-en-rSG/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-en-rZA/strings.xml b/auth/src/main/res/values-en-rZA/strings.xml
index 3f77e4877..b9180e5d2 100755
--- a/auth/src/main/res/values-en-rZA/strings.xml
+++ b/auth/src/main/res/values-en-rZA/strings.xml
@@ -13,6 +13,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as a guest
Next
Email
Phone number
diff --git a/auth/src/main/res/values-es-rAR/strings.xml b/auth/src/main/res/values-es-rAR/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rAR/strings.xml
+++ b/auth/src/main/res/values-es-rAR/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rBO/strings.xml b/auth/src/main/res/values-es-rBO/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rBO/strings.xml
+++ b/auth/src/main/res/values-es-rBO/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rCL/strings.xml b/auth/src/main/res/values-es-rCL/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rCL/strings.xml
+++ b/auth/src/main/res/values-es-rCL/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rCO/strings.xml b/auth/src/main/res/values-es-rCO/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rCO/strings.xml
+++ b/auth/src/main/res/values-es-rCO/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rCR/strings.xml b/auth/src/main/res/values-es-rCR/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rCR/strings.xml
+++ b/auth/src/main/res/values-es-rCR/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rDO/strings.xml b/auth/src/main/res/values-es-rDO/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rDO/strings.xml
+++ b/auth/src/main/res/values-es-rDO/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rEC/strings.xml b/auth/src/main/res/values-es-rEC/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rEC/strings.xml
+++ b/auth/src/main/res/values-es-rEC/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rGT/strings.xml b/auth/src/main/res/values-es-rGT/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rGT/strings.xml
+++ b/auth/src/main/res/values-es-rGT/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rHN/strings.xml b/auth/src/main/res/values-es-rHN/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rHN/strings.xml
+++ b/auth/src/main/res/values-es-rHN/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rMX/strings.xml b/auth/src/main/res/values-es-rMX/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rMX/strings.xml
+++ b/auth/src/main/res/values-es-rMX/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rNI/strings.xml b/auth/src/main/res/values-es-rNI/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rNI/strings.xml
+++ b/auth/src/main/res/values-es-rNI/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rPA/strings.xml b/auth/src/main/res/values-es-rPA/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rPA/strings.xml
+++ b/auth/src/main/res/values-es-rPA/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rPE/strings.xml b/auth/src/main/res/values-es-rPE/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rPE/strings.xml
+++ b/auth/src/main/res/values-es-rPE/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rPR/strings.xml b/auth/src/main/res/values-es-rPR/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rPR/strings.xml
+++ b/auth/src/main/res/values-es-rPR/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rPY/strings.xml b/auth/src/main/res/values-es-rPY/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rPY/strings.xml
+++ b/auth/src/main/res/values-es-rPY/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rSV/strings.xml b/auth/src/main/res/values-es-rSV/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rSV/strings.xml
+++ b/auth/src/main/res/values-es-rSV/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rUS/strings.xml b/auth/src/main/res/values-es-rUS/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rUS/strings.xml
+++ b/auth/src/main/res/values-es-rUS/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rUY/strings.xml b/auth/src/main/res/values-es-rUY/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rUY/strings.xml
+++ b/auth/src/main/res/values-es-rUY/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es-rVE/strings.xml b/auth/src/main/res/values-es-rVE/strings.xml
index 7d63da241..76de343b4 100755
--- a/auth/src/main/res/values-es-rVE/strings.xml
+++ b/auth/src/main/res/values-es-rVE/strings.xml
@@ -13,6 +13,7 @@
Acceder con GitHub
Acceder con el correo electrónico
Acceder con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-es/strings.xml b/auth/src/main/res/values-es/strings.xml
index 960d42bcf..5914c9c95 100755
--- a/auth/src/main/res/values-es/strings.xml
+++ b/auth/src/main/res/values-es/strings.xml
@@ -13,6 +13,7 @@
Iniciar sesión con GitHub
Iniciar sesión con el correo electrónico
Iniciar sesión con el teléfono
+ Continuar como invitado
Siguiente
Correo electrónico
Número de teléfono
diff --git a/auth/src/main/res/values-fa/strings.xml b/auth/src/main/res/values-fa/strings.xml
index 9ea43bb1e..d1b1ecdeb 100755
--- a/auth/src/main/res/values-fa/strings.xml
+++ b/auth/src/main/res/values-fa/strings.xml
@@ -13,6 +13,7 @@
ورود به سیستم با GitHub
ورود به سیستم با رایانامه
ورود به سیستم با تلفن
+ ادامه بهعنوان مهمان
بعدی
رایانامه
شماره تلفن
diff --git a/auth/src/main/res/values-fi/strings.xml b/auth/src/main/res/values-fi/strings.xml
index 6e5d776fa..166dd3b0c 100755
--- a/auth/src/main/res/values-fi/strings.xml
+++ b/auth/src/main/res/values-fi/strings.xml
@@ -13,6 +13,7 @@
Kirjaudu GitHub-tilillä
Kirjaudu sähköpostilla
Kirjaudu puhelimella
+ Jatka vieraana
Seuraava
Sähköposti
Puhelinnumero
diff --git a/auth/src/main/res/values-fil/strings.xml b/auth/src/main/res/values-fil/strings.xml
index e9a8de2de..c6cf6f60b 100755
--- a/auth/src/main/res/values-fil/strings.xml
+++ b/auth/src/main/res/values-fil/strings.xml
@@ -13,6 +13,7 @@
Mag-sign in sa GitHub
Mag-sign in gamit ang email
Mag-sign in gamit ang telepono
+ Magpatuloy bilang bisita
Susunod
Mag-email
Numero ng Telepono
diff --git a/auth/src/main/res/values-fr-rCH/strings.xml b/auth/src/main/res/values-fr-rCH/strings.xml
index 747acacae..308e54891 100755
--- a/auth/src/main/res/values-fr-rCH/strings.xml
+++ b/auth/src/main/res/values-fr-rCH/strings.xml
@@ -13,6 +13,7 @@
Se connecter avec GitHub
Se connecter avec une adresse e-mail
Se connecter avec un téléphone
+ Continuer en tant qu\'invité
Suivant
E-mail
Numéro de téléphone
diff --git a/auth/src/main/res/values-fr/strings.xml b/auth/src/main/res/values-fr/strings.xml
index 747acacae..308e54891 100755
--- a/auth/src/main/res/values-fr/strings.xml
+++ b/auth/src/main/res/values-fr/strings.xml
@@ -13,6 +13,7 @@
Se connecter avec GitHub
Se connecter avec une adresse e-mail
Se connecter avec un téléphone
+ Continuer en tant qu\'invité
Suivant
E-mail
Numéro de téléphone
diff --git a/auth/src/main/res/values-gsw/strings.xml b/auth/src/main/res/values-gsw/strings.xml
index ed621c961..1972b4fea 100755
--- a/auth/src/main/res/values-gsw/strings.xml
+++ b/auth/src/main/res/values-gsw/strings.xml
@@ -13,6 +13,7 @@
Über GitHub anmelden
Mit einer E-Mail-Adresse anmelden
Mit einer Telefonnummer anmelden
+ Als Gast fortfahren
Weiter
E-Mail-Adresse
Telefonnummer
diff --git a/auth/src/main/res/values-gu/strings.xml b/auth/src/main/res/values-gu/strings.xml
index 4fbd261d9..69bd1a58f 100755
--- a/auth/src/main/res/values-gu/strings.xml
+++ b/auth/src/main/res/values-gu/strings.xml
@@ -13,6 +13,7 @@
GitHub વડે સાઇન ઇન કરો
ઇમેઇલ વડે સાઇન ઇન કરો
ફોન વડે સાઇન ઇન કરો
+ અતિથિ તરીકે ચાલુ રાખો
આગળ
ઇમેઇલ
ફોન નંબર
diff --git a/auth/src/main/res/values-hi/strings.xml b/auth/src/main/res/values-hi/strings.xml
index 4622c179e..1a4998d2c 100755
--- a/auth/src/main/res/values-hi/strings.xml
+++ b/auth/src/main/res/values-hi/strings.xml
@@ -13,6 +13,7 @@
GitHub के साथ साइन इन करें
ईमेल से प्रवेश करें
फ़ोन से प्रवेश करें
+ मेहमान के रूप में जारी रखें
अगला
ईमेल
फ़ोन नंबर
diff --git a/auth/src/main/res/values-hr/strings.xml b/auth/src/main/res/values-hr/strings.xml
index b677fe535..4dac58ef2 100755
--- a/auth/src/main/res/values-hr/strings.xml
+++ b/auth/src/main/res/values-hr/strings.xml
@@ -13,6 +13,7 @@
Prijava putem GitHuba
Prijava putem e-adrese
Prijava putem telefona
+ Nastavi kao gost
Dalje
E-adresa
Telefonski broj
diff --git a/auth/src/main/res/values-hu/strings.xml b/auth/src/main/res/values-hu/strings.xml
index 0a1dcf73a..46789fbb0 100755
--- a/auth/src/main/res/values-hu/strings.xml
+++ b/auth/src/main/res/values-hu/strings.xml
@@ -13,6 +13,7 @@
Bejelentkezés GitHubbal
Bejelentkezés e-mail-fiókkal
Bejelentkezés telefonnal
+ Folytatás vendégként
Következő
E-mail
Telefonszám
diff --git a/auth/src/main/res/values-in/strings.xml b/auth/src/main/res/values-in/strings.xml
index 4cc582a4e..f773ded65 100755
--- a/auth/src/main/res/values-in/strings.xml
+++ b/auth/src/main/res/values-in/strings.xml
@@ -13,6 +13,7 @@
Login dengan GitHub
Login dengan email
Login dengan nomor telepon
+ Lanjutkan sebagai tamu
Berikutnya
Email
Nomor Telepon
diff --git a/auth/src/main/res/values-it/strings.xml b/auth/src/main/res/values-it/strings.xml
index 4f649ef95..feafccc4b 100755
--- a/auth/src/main/res/values-it/strings.xml
+++ b/auth/src/main/res/values-it/strings.xml
@@ -13,6 +13,7 @@
Accedi con GitHub
Accedi con l\'indirizzo email
Accedi con il telefono
+ Continua come ospite
Avanti
Indirizzo email
Numero di telefono
diff --git a/auth/src/main/res/values-iw/strings.xml b/auth/src/main/res/values-iw/strings.xml
index 8b9aa2e7d..ab2e8baaa 100755
--- a/auth/src/main/res/values-iw/strings.xml
+++ b/auth/src/main/res/values-iw/strings.xml
@@ -13,6 +13,7 @@
כניסה באמצעות GitHub
כניסה באמצעות אימייל
כניסה באמצעות הטלפון
+ המשך כאורח
הבא
אימייל
מספר טלפון
diff --git a/auth/src/main/res/values-ja/strings.xml b/auth/src/main/res/values-ja/strings.xml
index b642db63a..5a94f2958 100755
--- a/auth/src/main/res/values-ja/strings.xml
+++ b/auth/src/main/res/values-ja/strings.xml
@@ -13,6 +13,7 @@
GitHub でログイン
メールアドレスでログイン
電話番号でログイン
+ ゲストとして続行
次へ
メールアドレス
電話番号
diff --git a/auth/src/main/res/values-kn/strings.xml b/auth/src/main/res/values-kn/strings.xml
index 34f906db0..e42171595 100755
--- a/auth/src/main/res/values-kn/strings.xml
+++ b/auth/src/main/res/values-kn/strings.xml
@@ -13,6 +13,7 @@
GitHub ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿ
ಇಮೇಲ್ ಜೊತೆ ಸೈನ್ ಇನ್ ಮಾಡಿ
ಫೋನ್ ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿ
+ ಅತಿಥಿಯಂತೆ ಮುಂದುವರಿಸಿ
ಮುಂದೆ
ಇಮೇಲ್
ಫೋನ್ ಸಂಖ್ಯೆ
diff --git a/auth/src/main/res/values-ko/strings.xml b/auth/src/main/res/values-ko/strings.xml
index 7527fcc3e..cfd6b6db2 100755
--- a/auth/src/main/res/values-ko/strings.xml
+++ b/auth/src/main/res/values-ko/strings.xml
@@ -13,6 +13,7 @@
GitHub로 로그인
이메일로 로그인
전화로 로그인
+ 비회원으로 진행
다음
이메일
전화번호
diff --git a/auth/src/main/res/values-ln/strings.xml b/auth/src/main/res/values-ln/strings.xml
index 747acacae..308e54891 100755
--- a/auth/src/main/res/values-ln/strings.xml
+++ b/auth/src/main/res/values-ln/strings.xml
@@ -13,6 +13,7 @@
Se connecter avec GitHub
Se connecter avec une adresse e-mail
Se connecter avec un téléphone
+ Continuer en tant qu\'invité
Suivant
E-mail
Numéro de téléphone
diff --git a/auth/src/main/res/values-lt/strings.xml b/auth/src/main/res/values-lt/strings.xml
index 8f48c0f64..088b83c40 100755
--- a/auth/src/main/res/values-lt/strings.xml
+++ b/auth/src/main/res/values-lt/strings.xml
@@ -13,6 +13,7 @@
Prisijungti per „GitHub“
Prisijungti nurodant el. pašto adresą
Prisijungti nurodant telefono numerį
+ Tęsti kaip svečiui
Kitas
El. pašto adresas
Telefono numeris
diff --git a/auth/src/main/res/values-lv/strings.xml b/auth/src/main/res/values-lv/strings.xml
index 0c658d719..066534909 100755
--- a/auth/src/main/res/values-lv/strings.xml
+++ b/auth/src/main/res/values-lv/strings.xml
@@ -13,6 +13,7 @@
Pierakstīties, izmantojot GitHub
Pierakstīties ar e-pasta adresi
Pierakstīties ar tālruni
+ Turpināt kā viesim
Tālāk
E-pasts
Tālruņa numurs
diff --git a/auth/src/main/res/values-mo/strings.xml b/auth/src/main/res/values-mo/strings.xml
index 6e8374a04..596926c1b 100755
--- a/auth/src/main/res/values-mo/strings.xml
+++ b/auth/src/main/res/values-mo/strings.xml
@@ -13,6 +13,7 @@
Conectați-vă cu GitHub
Conectați-vă cu adresa de e-mail
Conectați-vă cu numărul de telefon
+ Continuați ca invitat
Înainte
Adresă de e-mail
Număr de telefon
diff --git a/auth/src/main/res/values-mr/strings.xml b/auth/src/main/res/values-mr/strings.xml
index 90123720c..5566777c1 100755
--- a/auth/src/main/res/values-mr/strings.xml
+++ b/auth/src/main/res/values-mr/strings.xml
@@ -13,6 +13,7 @@
GitHub सह साइन इन करा
ईमेलने साइन इन करा
फोनने साइन इन करा
+ अतिथी म्हणून सुरू ठेवा
पुढील
ईमेल
फोन नंबर
diff --git a/auth/src/main/res/values-ms/strings.xml b/auth/src/main/res/values-ms/strings.xml
index da2e1332e..855175cff 100755
--- a/auth/src/main/res/values-ms/strings.xml
+++ b/auth/src/main/res/values-ms/strings.xml
@@ -13,6 +13,7 @@
Log masuk dengan GitHub
Log masuk dengan e-mel
Log masuk dengan telefon
+ Teruskan sebagai tetamu
Seterusnya
E-mel
Nombor Telefon
diff --git a/auth/src/main/res/values-nb/strings.xml b/auth/src/main/res/values-nb/strings.xml
index 6dd286adc..0d43e8305 100755
--- a/auth/src/main/res/values-nb/strings.xml
+++ b/auth/src/main/res/values-nb/strings.xml
@@ -13,6 +13,7 @@
Logg på med GitHub
Logg på med e-postadresse
Logg på med telefonnummeret ditt
+ Fortsett som gjest
Neste
E-post
Telefonnummer
diff --git a/auth/src/main/res/values-nl/strings.xml b/auth/src/main/res/values-nl/strings.xml
index cd399d306..6692ffd33 100755
--- a/auth/src/main/res/values-nl/strings.xml
+++ b/auth/src/main/res/values-nl/strings.xml
@@ -13,6 +13,7 @@
Inloggen met GitHub
Inloggen met e-mailadres
Inloggen met telefoon
+ Doorgaan als gast
Volgende
E-mail
Telefoonnummer
diff --git a/auth/src/main/res/values-no/strings.xml b/auth/src/main/res/values-no/strings.xml
index 6dd286adc..0d43e8305 100755
--- a/auth/src/main/res/values-no/strings.xml
+++ b/auth/src/main/res/values-no/strings.xml
@@ -13,6 +13,7 @@
Logg på med GitHub
Logg på med e-postadresse
Logg på med telefonnummeret ditt
+ Fortsett som gjest
Neste
E-post
Telefonnummer
diff --git a/auth/src/main/res/values-pl/strings.xml b/auth/src/main/res/values-pl/strings.xml
index 42b242242..7c4b4f24b 100755
--- a/auth/src/main/res/values-pl/strings.xml
+++ b/auth/src/main/res/values-pl/strings.xml
@@ -13,6 +13,7 @@
Zaloguj się przez GitHuba
Zaloguj się za pomocą e-maila
Zaloguj się z użyciem numeru telefonu
+ Kontynuuj jako gość
Dalej
Adres e-mail
Numer telefonu
diff --git a/auth/src/main/res/values-pt-rBR/strings.xml b/auth/src/main/res/values-pt-rBR/strings.xml
index bdc357c16..9d04780c7 100755
--- a/auth/src/main/res/values-pt-rBR/strings.xml
+++ b/auth/src/main/res/values-pt-rBR/strings.xml
@@ -13,6 +13,7 @@
Fazer login com o GitHub
Fazer login com o e-mail
Fazer login com o telefone
+ Continuar como convidado
Próxima
E-mail
Número de telefone
diff --git a/auth/src/main/res/values-pt-rPT/strings.xml b/auth/src/main/res/values-pt-rPT/strings.xml
index 25ac63248..209f3dbd9 100755
--- a/auth/src/main/res/values-pt-rPT/strings.xml
+++ b/auth/src/main/res/values-pt-rPT/strings.xml
@@ -13,6 +13,7 @@
Iniciar sessão com o GitHub
Iniciar sessão com o email
Iniciar sessão com o telemóvel
+ Continuar como convidado
Seguinte
Email
Número de telefone
diff --git a/auth/src/main/res/values-pt/strings.xml b/auth/src/main/res/values-pt/strings.xml
index bdc357c16..9d04780c7 100755
--- a/auth/src/main/res/values-pt/strings.xml
+++ b/auth/src/main/res/values-pt/strings.xml
@@ -13,6 +13,7 @@
Fazer login com o GitHub
Fazer login com o e-mail
Fazer login com o telefone
+ Continuar como convidado
Próxima
E-mail
Número de telefone
diff --git a/auth/src/main/res/values-ro/strings.xml b/auth/src/main/res/values-ro/strings.xml
index 6e8374a04..596926c1b 100755
--- a/auth/src/main/res/values-ro/strings.xml
+++ b/auth/src/main/res/values-ro/strings.xml
@@ -13,6 +13,7 @@
Conectați-vă cu GitHub
Conectați-vă cu adresa de e-mail
Conectați-vă cu numărul de telefon
+ Continuați ca invitat
Înainte
Adresă de e-mail
Număr de telefon
diff --git a/auth/src/main/res/values-ru/strings.xml b/auth/src/main/res/values-ru/strings.xml
index b814d2500..4b26ca0c7 100755
--- a/auth/src/main/res/values-ru/strings.xml
+++ b/auth/src/main/res/values-ru/strings.xml
@@ -13,6 +13,7 @@
Войти через аккаунт GitHub
Войти по адресу электронной почты
Войти по номеру телефона
+ Продолжить как гость
Далее
Адрес электронной почты
Номер телефона
diff --git a/auth/src/main/res/values-sk/strings.xml b/auth/src/main/res/values-sk/strings.xml
index 51426de9f..0991a5c4d 100755
--- a/auth/src/main/res/values-sk/strings.xml
+++ b/auth/src/main/res/values-sk/strings.xml
@@ -13,6 +13,7 @@
Prihlásiť sa cez GitHub
Prihlásiť sa e-mailom
Prihlásiť sa telefónom
+ Pokračovať ako hosť
Ďalej
E-mail
Telefónne číslo
diff --git a/auth/src/main/res/values-sl/strings.xml b/auth/src/main/res/values-sl/strings.xml
index b1bfeef2b..20fe6af8a 100755
--- a/auth/src/main/res/values-sl/strings.xml
+++ b/auth/src/main/res/values-sl/strings.xml
@@ -13,6 +13,7 @@
Prijava z računom za GitHub
Prijava z e-poštnim naslovom
Prijava s telefonom
+ Nadaljuj kot gost
Naprej
E-pošta
Telefonska številka
diff --git a/auth/src/main/res/values-sr/strings.xml b/auth/src/main/res/values-sr/strings.xml
index e62189d57..b54e6fa08 100755
--- a/auth/src/main/res/values-sr/strings.xml
+++ b/auth/src/main/res/values-sr/strings.xml
@@ -13,6 +13,7 @@
Пријавите се помоћу GitHub-а
Пријави ме помоћу имејла
Пријави ме помоћу телефона
+ Наставите као гост
Даље
Имејл
Број телефона
diff --git a/auth/src/main/res/values-sv/strings.xml b/auth/src/main/res/values-sv/strings.xml
index bd2c81a37..c9459eb25 100755
--- a/auth/src/main/res/values-sv/strings.xml
+++ b/auth/src/main/res/values-sv/strings.xml
@@ -13,6 +13,7 @@
Logga in med GitHub
Logga in med e-post
Logga in med telefon
+ Fortsätt som gäst
Nästa
E-post
Telefonnummer
diff --git a/auth/src/main/res/values-ta/strings.xml b/auth/src/main/res/values-ta/strings.xml
index 0dfd772a0..6f573dd33 100755
--- a/auth/src/main/res/values-ta/strings.xml
+++ b/auth/src/main/res/values-ta/strings.xml
@@ -13,6 +13,7 @@
GitHub பயன்படுத்தி உள்நுழைக
மின்னஞ்சல் மூலம் உள்நுழைக
ஃபோன் எண் மூலம் உள்நுழைக
+ விருந்தினராகத் தொடர்க
அடுத்து
மின்னஞ்சல்
ஃபோன் எண்
diff --git a/auth/src/main/res/values-th/strings.xml b/auth/src/main/res/values-th/strings.xml
index f5fde37b3..27d6d7cbc 100755
--- a/auth/src/main/res/values-th/strings.xml
+++ b/auth/src/main/res/values-th/strings.xml
@@ -13,6 +13,7 @@
ลงชื่อเข้าใช้ด้วย GitHub
ลงชื่อเข้าใช้ด้วยอีเมล
ลงชื่อเข้าใช้ด้วยโทรศัพท์
+ ดำเนินการต่อในฐานะผู้เข้าร่วม
ถัดไป
อีเมล
หมายเลขโทรศัพท์
diff --git a/auth/src/main/res/values-tl/strings.xml b/auth/src/main/res/values-tl/strings.xml
index e9a8de2de..c6cf6f60b 100755
--- a/auth/src/main/res/values-tl/strings.xml
+++ b/auth/src/main/res/values-tl/strings.xml
@@ -13,6 +13,7 @@
Mag-sign in sa GitHub
Mag-sign in gamit ang email
Mag-sign in gamit ang telepono
+ Magpatuloy bilang bisita
Susunod
Mag-email
Numero ng Telepono
diff --git a/auth/src/main/res/values-tr/strings.xml b/auth/src/main/res/values-tr/strings.xml
index a2e39b28a..c0dc8032f 100755
--- a/auth/src/main/res/values-tr/strings.xml
+++ b/auth/src/main/res/values-tr/strings.xml
@@ -13,6 +13,7 @@
GitHub ile oturum aç
E-posta ile oturum aç
Telefonla oturum aç
+ Misafir olarak devam et
İleri
E-posta
Telefon Numarası
diff --git a/auth/src/main/res/values-uk/strings.xml b/auth/src/main/res/values-uk/strings.xml
index 8fe0677c9..1f1fafa58 100755
--- a/auth/src/main/res/values-uk/strings.xml
+++ b/auth/src/main/res/values-uk/strings.xml
@@ -13,6 +13,7 @@
Увійти через GitHub
Увійти, використовуючи електронну адресу
Увійти, використовуючи телефон
+ Продовжити як гість
Далі
Електронна адреса
Номер телефону
diff --git a/auth/src/main/res/values-ur/strings.xml b/auth/src/main/res/values-ur/strings.xml
index f523cd7b5..2c37ba3f0 100755
--- a/auth/src/main/res/values-ur/strings.xml
+++ b/auth/src/main/res/values-ur/strings.xml
@@ -13,6 +13,7 @@
GitHub کے ساتھ سائن ان کریں
ای میل کے ساتھ سائن ان کریں
فون کے ساتھ سائں ان کریں
+ مہمان کے طور پر جاری رکھیں
اگلا
ای میل
فون نمبر
diff --git a/auth/src/main/res/values-vi/strings.xml b/auth/src/main/res/values-vi/strings.xml
index 183511979..5ab30f268 100755
--- a/auth/src/main/res/values-vi/strings.xml
+++ b/auth/src/main/res/values-vi/strings.xml
@@ -13,6 +13,7 @@
Đăng nhập bằng GitHub
Đăng nhập bằng email
Đăng nhập bằng điện thoại
+ Tiếp tục với vai trò người dùng khách
Tiếp
Email
Số điện thoại
diff --git a/auth/src/main/res/values-zh-rCN/strings.xml b/auth/src/main/res/values-zh-rCN/strings.xml
index cbe41e263..9c445ea60 100755
--- a/auth/src/main/res/values-zh-rCN/strings.xml
+++ b/auth/src/main/res/values-zh-rCN/strings.xml
@@ -13,6 +13,7 @@
使用 GitHub 帐号登录
使用电子邮件地址登录
使用电话号码登录
+ 以访客身份继续
继续
电子邮件地址
电话号码
diff --git a/auth/src/main/res/values-zh-rHK/strings.xml b/auth/src/main/res/values-zh-rHK/strings.xml
index bccfccc5a..b799ce228 100755
--- a/auth/src/main/res/values-zh-rHK/strings.xml
+++ b/auth/src/main/res/values-zh-rHK/strings.xml
@@ -13,6 +13,7 @@
使用 GitHub 登入
使用電子郵件地址登入
使用電話號碼登入
+ 繼續以訪客身分使用
繼續
電子郵件
電話號碼
diff --git a/auth/src/main/res/values-zh-rTW/strings.xml b/auth/src/main/res/values-zh-rTW/strings.xml
index bccfccc5a..b799ce228 100755
--- a/auth/src/main/res/values-zh-rTW/strings.xml
+++ b/auth/src/main/res/values-zh-rTW/strings.xml
@@ -13,6 +13,7 @@
使用 GitHub 登入
使用電子郵件地址登入
使用電話號碼登入
+ 繼續以訪客身分使用
繼續
電子郵件
電話號碼
diff --git a/auth/src/main/res/values-zh/strings.xml b/auth/src/main/res/values-zh/strings.xml
index cbe41e263..9c445ea60 100755
--- a/auth/src/main/res/values-zh/strings.xml
+++ b/auth/src/main/res/values-zh/strings.xml
@@ -13,6 +13,7 @@
使用 GitHub 帐号登录
使用电子邮件地址登录
使用电话号码登录
+ 以访客身份继续
继续
电子邮件地址
电话号码
diff --git a/auth/src/main/res/values/colors.xml b/auth/src/main/res/values/colors.xml
index 8b1a63aed..f3d1c1e74 100644
--- a/auth/src/main/res/values/colors.xml
+++ b/auth/src/main/res/values/colors.xml
@@ -14,5 +14,6 @@
#24292E
#D0021B
#43C5A5
+ #f4b400
#64BEBEBE
diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml
index 1bc3a55e9..8eab9e43e 100644
--- a/auth/src/main/res/values/strings.xml
+++ b/auth/src/main/res/values/strings.xml
@@ -21,6 +21,7 @@
Sign in with GitHub
Sign in with email
Sign in with phone
+ Continue as guest
Next
diff --git a/auth/src/main/res/values/styles.xml b/auth/src/main/res/values/styles.xml
index ce2877137..8a2d661f5 100644
--- a/auth/src/main/res/values/styles.xml
+++ b/auth/src/main/res/values/styles.xml
@@ -236,6 +236,12 @@
- #ffffff
+
+