Skip to content

Commit 6ddb64f

Browse files
committed
Adds anonymous user upgrade to Email/Password sign in
1 parent 915846d commit 6ddb64f

18 files changed

+355
-86
lines changed

app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.google.android.gms.common.Scopes;
4242
import com.google.android.gms.tasks.OnCompleteListener;
4343
import com.google.android.gms.tasks.Task;
44+
import com.google.firebase.auth.AuthCredential;
4445
import com.google.firebase.auth.AuthResult;
4546
import com.google.firebase.auth.FirebaseAuth;
4647

@@ -155,17 +156,25 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
155156

156157
@OnClick(R.id.sign_in)
157158
public void signIn(View view) {
158-
startActivityForResult(
159-
AuthUI.getInstance().createSignInIntentBuilder()
160-
.setTheme(getSelectedTheme())
161-
.setLogo(getSelectedLogo())
162-
.setAvailableProviders(getSelectedProviders())
163-
.setTosAndPrivacyPolicyUrls(getSelectedTosUrl(),
164-
getSelectedPrivacyPolicyUrl())
165-
.setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(),
166-
mEnableHintSelector.isChecked())
167-
.build(),
168-
RC_SIGN_IN);
159+
FirebaseAuth.getInstance()
160+
.signInAnonymously()
161+
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
162+
@Override
163+
public void onComplete(@NonNull Task<AuthResult> task) {
164+
startActivityForResult(
165+
AuthUI.getInstance().createSignInIntentBuilder()
166+
.setTheme(getSelectedTheme())
167+
.setLogo(getSelectedLogo())
168+
.setAvailableProviders(getSelectedProviders())
169+
.setTosAndPrivacyPolicyUrls(getSelectedTosUrl(),
170+
getSelectedPrivacyPolicyUrl())
171+
.setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(),
172+
mEnableHintSelector.isChecked())
173+
.setAutoUpgradeAnonymousUsers()
174+
.build(),
175+
RC_SIGN_IN);
176+
}
177+
});
169178
}
170179

171180
@OnClick(R.id.sign_in_silent)
@@ -194,15 +203,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
194203
@Override
195204
protected void onResume() {
196205
super.onResume();
197-
FirebaseAuth auth = FirebaseAuth.getInstance();
198-
if (auth.getCurrentUser() != null) {
199-
startSignedInActivity(null);
200-
finish();
201-
}
206+
// FirebaseAuth auth = FirebaseAuth.getInstance();
207+
// if (auth.getCurrentUser() != null) {
208+
// startSignedInActivity(null);
209+
// finish();
210+
// }
202211
}
203212

204213
private void handleSignInResponse(int resultCode, Intent data) {
205-
IdpResponse response = IdpResponse.fromResultIntent(data);
214+
final IdpResponse response = IdpResponse.fromResultIntent(data);
206215

207216
// Successfully signed in
208217
if (resultCode == RESULT_OK) {
@@ -221,6 +230,25 @@ private void handleSignInResponse(int resultCode, Intent data) {
221230
return;
222231
}
223232

233+
if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
234+
AuthCredential credential = response.getCredentialForLinking();
235+
// take data from anon user
236+
// log in with credential
237+
// update user
238+
FirebaseAuth.getInstance().signInWithCredential(credential).addOnCompleteListener(
239+
new OnCompleteListener<AuthResult>() {
240+
@Override
241+
public void onComplete(@NonNull Task<AuthResult> task) {
242+
if (task.isSuccessful()) {
243+
startSignedInActivity(response);
244+
} else {
245+
// cry
246+
}
247+
}
248+
});
249+
return;
250+
}
251+
224252
showSnackbar(R.string.unknown_error);
225253
Log.e(TAG, "Sign-in error: ", response.getError());
226254
}

auth/src/main/java/com/firebase/ui/auth/AuthUI.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,10 +1107,23 @@ public Intent build() {
11071107
* Builder for the intent to start the user authentication flow.
11081108
*/
11091109
public final class SignInIntentBuilder extends AuthIntentBuilder<SignInIntentBuilder> {
1110+
1111+
private boolean mEnableAnonymousUpgrade;
1112+
11101113
private SignInIntentBuilder() {
11111114
super();
11121115
}
11131116

1117+
/**
1118+
* Enables or disables upgrading anonymous accounts to full accounts during the sign-in
1119+
* flow. This is disabled by default.
1120+
*/
1121+
@NonNull
1122+
public SignInIntentBuilder setAutoUpgradeAnonymousUsers() {
1123+
mEnableAnonymousUpgrade = true;
1124+
return this;
1125+
}
1126+
11141127
@Override
11151128
protected FlowParameters getFlowParams() {
11161129
return new FlowParameters(
@@ -1121,7 +1134,8 @@ protected FlowParameters getFlowParams() {
11211134
mTosUrl,
11221135
mPrivacyPolicyUrl,
11231136
mEnableCredentials,
1124-
mEnableHints);
1137+
mEnableHints,
1138+
mEnableAnonymousUpgrade);
11251139
}
11261140
}
11271141
}

auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public final class ErrorCodes {
1919
NO_NETWORK,
2020
PLAY_SERVICES_UPDATE_CANCELLED,
2121
DEVELOPER_ERROR,
22-
PROVIDER_ERROR
22+
PROVIDER_ERROR,
23+
ANONYMOUS_UPGRADE_MERGE_CONFLICT
2324
})
2425
@Retention(RetentionPolicy.SOURCE)
2526
public @interface Code {}
@@ -49,6 +50,11 @@ public final class ErrorCodes {
4950
*/
5051
public static final int PROVIDER_ERROR = 4;
5152

53+
/**
54+
* Anonymous account linking failed.
55+
*/
56+
public static final int ANONYMOUS_UPGRADE_MERGE_CONFLICT = 5;
57+
5258
private ErrorCodes() {
5359
throw new AssertionError("No instance for you!");
5460
}
@@ -67,6 +73,8 @@ public static String toFriendlyMessage(@Code int code) {
6773
return "Developer error";
6874
case PROVIDER_ERROR:
6975
return "Provider error";
76+
case ANONYMOUS_UPGRADE_MERGE_CONFLICT:
77+
return "Merge conflict";
7078
default:
7179
throw new IllegalArgumentException("Unknown code: " + code);
7280
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.firebase.ui.auth;
2+
3+
import android.support.annotation.NonNull;
4+
import android.support.annotation.Nullable;
5+
import android.support.annotation.RestrictTo;
6+
7+
import com.firebase.ui.auth.IdpResponse;
8+
import com.google.firebase.auth.AuthCredential;
9+
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
10+
11+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
12+
public class FirebaseAuthAnonymousUpgradeException extends Exception {
13+
14+
private IdpResponse response;
15+
16+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
17+
public FirebaseAuthAnonymousUpgradeException(@ErrorCodes.Code int code,
18+
@NonNull IdpResponse response) {
19+
super(ErrorCodes.toFriendlyMessage(code));
20+
this.response = response;
21+
}
22+
23+
public IdpResponse getResponse() {
24+
return response;
25+
}
26+
}

auth/src/main/java/com/firebase/ui/auth/IdpResponse.java

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.firebase.ui.auth.data.model.User;
2626
import com.firebase.ui.auth.util.ExtraConstants;
2727
import com.google.firebase.auth.AuthResult;
28+
import com.google.firebase.auth.AuthCredential;
2829
import com.google.firebase.auth.GoogleAuthProvider;
2930
import com.google.firebase.auth.TwitterAuthProvider;
3031

@@ -45,6 +46,7 @@ public IdpResponse createFromParcel(Parcel in) {
4546
in.readString(),
4647
in.readInt() == 1,
4748
(FirebaseUiException) in.readSerializable()
49+
in.<AuthCredential>readParcelable(AuthCredential.class.getClassLoader())
4850
);
4951
}
5052

@@ -55,6 +57,7 @@ public IdpResponse[] newArray(int size) {
5557
};
5658

5759
private final User mUser;
60+
private final AuthCredential mPendingCredential;
5861

5962
private final String mToken;
6063
private final String mSecret;
@@ -63,28 +66,34 @@ public IdpResponse[] newArray(int size) {
6366
private final FirebaseUiException mException;
6467

6568
private IdpResponse(@NonNull FirebaseUiException e) {
66-
this(null, null, null, false, e);
69+
this(null, null, null, false, e, null);
6770
}
6871

6972
private IdpResponse(
7073
@NonNull User user,
7174
@Nullable String token,
7275
@Nullable String secret,
7376
boolean isNewUser) {
74-
this(user, token, secret, isNewUser, null);
77+
this(user, token, secret, isNewUser, null, null);
78+
}
79+
80+
private IdpResponse(AuthCredential credential, FirebaseUiException e) {
81+
this(null, null, null, false, e, credential);
7582
}
7683

7784
private IdpResponse(
7885
User user,
7986
String token,
8087
String secret,
8188
boolean isNewUser,
82-
FirebaseUiException e) {
89+
FirebaseUiException e
90+
AuthCredential credential) {
8391
mUser = user;
8492
mToken = token;
8593
mSecret = secret;
8694
mIsNewUser = isNewUser;
8795
mException = e;
96+
mPendingCredential = credential;
8897
}
8998

9099
/**
@@ -207,6 +216,11 @@ public FirebaseUiException getError() {
207216
return mException;
208217
}
209218

219+
@Nullable
220+
public AuthCredential getCredentialForLinking() {
221+
return mPendingCredential;
222+
}
223+
210224
@Override
211225
public int describeContents() {
212226
return 0;
@@ -218,7 +232,6 @@ public void writeToParcel(Parcel dest, int flags) {
218232
dest.writeString(mToken);
219233
dest.writeString(mSecret);
220234
dest.writeInt(mIsNewUser ? 1 : 0);
221-
222235
ObjectOutputStream oos = null;
223236
try {
224237
oos = new ObjectOutputStream(new ByteArrayOutputStream());
@@ -241,6 +254,7 @@ public void writeToParcel(Parcel dest, int flags) {
241254
} catch (IOException ignored) {}
242255
}
243256
}
257+
dest.writeParcelable(mPendingCredential, 0);
244258
}
245259

246260
@Override
@@ -281,13 +295,20 @@ public String toString() {
281295
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
282296
public static class Builder {
283297
private final User mUser;
298+
private final AuthCredential mPendingCredential;
284299

285300
private String mToken;
286301
private String mSecret;
287302
private boolean mIsNewUser;
288303

289304
public Builder(@NonNull User user) {
290305
mUser = user;
306+
mPendingCredential = null;
307+
}
308+
309+
public Builder(@NonNull AuthCredential pendingCredential) {
310+
mUser = null;
311+
mPendingCredential = pendingCredential;
291312
}
292313

293314
public Builder(@NonNull IdpResponse response) {
@@ -305,29 +326,32 @@ public Builder setNewUser(boolean newUser) {
305326
public Builder setToken(String token) {
306327
mToken = token;
307328
return this;
308-
}
329+
}
309330

310331
public Builder setSecret(String secret) {
311332
mSecret = secret;
312333
return this;
313334
}
314335

315336
public IdpResponse build() {
316-
String providerId = mUser.getProviderId();
317-
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
318-
throw new IllegalStateException("Unknown provider: " + providerId);
337+
if (mPendingCredential != null) {
338+
return new IdpResponse(mPendingCredential, new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT));
339+
} else {
340+
String providerId = mUser.getProviderId();
341+
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
342+
throw new IllegalStateException("Unknown provider: " + providerId);
343+
}
344+
if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) {
345+
throw new IllegalStateException(
346+
"Token cannot be null when using a non-email provider.");
347+
}
348+
if (providerId.equals(TwitterAuthProvider.PROVIDER_ID)
349+
&& TextUtils.isEmpty(mSecret)) {
350+
throw new IllegalStateException(
351+
"Secret cannot be null when using the Twitter provider.");
352+
}
353+
return new IdpResponse(mUser, mToken, mSecret, mIsNewUser);
319354
}
320-
if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) {
321-
throw new IllegalStateException(
322-
"Token cannot be null when using a non-email provider.");
323-
}
324-
if (providerId.equals(TwitterAuthProvider.PROVIDER_ID)
325-
&& TextUtils.isEmpty(mSecret)) {
326-
throw new IllegalStateException(
327-
"Secret cannot be null when using the Twitter provider.");
328-
}
329-
330-
return new IdpResponse(mUser, mToken, mSecret, mIsNewUser);
331355
}
332356
}
333357
}

auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.firebase.ui.auth.data.model.UserCancellationException;
1414
import com.firebase.ui.auth.data.remote.SignInKickstarter;
1515
import com.firebase.ui.auth.ui.InvisibleActivityBase;
16+
import com.firebase.ui.auth.util.ExtraConstants;
1617
import com.firebase.ui.auth.viewmodel.ResourceObserver;
1718
import com.google.android.gms.common.GoogleApiAvailability;
1819
import com.google.android.gms.tasks.OnFailureListener;
@@ -41,6 +42,9 @@ protected void onSuccess(@NonNull IdpResponse response) {
4142
protected void onFailure(@NonNull Exception e) {
4243
if (e instanceof UserCancellationException) {
4344
finish(RESULT_CANCELED, null);
45+
} else if (e instanceof FirebaseAuthAnonymousUpgradeException) {
46+
IdpResponse res = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
47+
finish(RESULT_CANCELED, new Intent().putExtra(ExtraConstants.IDP_RESPONSE, res));
4448
} else {
4549
finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e));
4650
}

0 commit comments

Comments
 (0)