Skip to content

Commit cab8213

Browse files
committed
Very basic linking
Change-Id: I50b05d1e50865c9f2dc5e231569e237c631e0003
1 parent ff0e170 commit cab8213

File tree

12 files changed

+197
-51
lines changed

12 files changed

+197
-51
lines changed

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,9 @@ public Intent build() {
10101010
* Builder for the intent to start the user authentication flow.
10111011
*/
10121012
public final class SignInIntentBuilder extends AuthIntentBuilder<SignInIntentBuilder> {
1013+
10131014
private Boolean mAllowNewEmailAccounts;
1015+
private boolean mUpgradeAnonymous = false;
10141016

10151017
private SignInIntentBuilder() {
10161018
super();
@@ -1031,6 +1033,16 @@ public SignInIntentBuilder setAllowNewEmailAccounts(boolean enabled) {
10311033
return this;
10321034
}
10331035

1036+
/**
1037+
* Enables or disables upgrading anonymous accounts to full accounts during the sign-in
1038+
* flow. This is disabled by default.
1039+
*/
1040+
@NonNull
1041+
public SignInIntentBuilder setUpgradeAnonymousAccounts(boolean enabled) {
1042+
mUpgradeAnonymous = enabled;
1043+
return this;
1044+
}
1045+
10341046
@NonNull
10351047
@Override
10361048
public Intent build() {
@@ -1059,7 +1071,8 @@ protected FlowParameters getFlowParams() {
10591071
mTosUrl,
10601072
mPrivacyPolicyUrl,
10611073
mEnableCredentials,
1062-
mEnableHints);
1074+
mEnableHints,
1075+
mUpgradeAnonymous);
10631076
}
10641077
}
10651078
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public final class ErrorCodes {
1616
UNKNOWN_ERROR,
1717
NO_NETWORK,
1818
PLAY_SERVICES_UPDATE_CANCELLED,
19-
DEVELOPER_ERROR
19+
DEVELOPER_ERROR,
20+
ANONYMOUS_UPGRADE_MERGE_CONFLICT
2021
})
2122
@Retention(RetentionPolicy.SOURCE)
2223
public @interface Code {}
@@ -41,6 +42,11 @@ public final class ErrorCodes {
4142
*/
4243
public static final int DEVELOPER_ERROR = 3;
4344

45+
/**
46+
* Anonymous account linking failed.
47+
*/
48+
public static final int ANONYMOUS_UPGRADE_MERGE_CONFLICT = 4;
49+
4450
private ErrorCodes() {
4551
throw new AssertionError("No instance for you!");
4652
}

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

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import com.firebase.ui.auth.data.model.User;
2727
import com.firebase.ui.auth.util.ExtraConstants;
28+
import com.google.firebase.auth.AuthCredential;
2829
import com.google.firebase.auth.GoogleAuthProvider;
2930
import com.google.firebase.auth.TwitterAuthProvider;
3031

@@ -39,6 +40,7 @@ public IdpResponse createFromParcel(Parcel in) {
3940
in.<User>readParcelable(User.class.getClassLoader()),
4041
in.readString(),
4142
in.readString(),
43+
(AuthCredential) in.readParcelable(AuthCredential.class.getClassLoader()),
4244
(FirebaseUiException) in.readSerializable()
4345
);
4446
}
@@ -56,25 +58,36 @@ public IdpResponse[] newArray(int size) {
5658

5759
private final FirebaseUiException mException;
5860

61+
private final AuthCredential mPendingCredential;
62+
5963
private IdpResponse(@NonNull FirebaseUiException e) {
60-
this(null, null, null, e);
64+
this(null, null, null, null, e);
65+
}
66+
67+
private IdpResponse(@NonNull AuthCredential pendingCredential) {
68+
this(
69+
null, null, null, /* user, token, and secret */
70+
pendingCredential,
71+
new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT));
6172
}
6273

6374
private IdpResponse(
6475
@NonNull User user,
6576
@Nullable String token,
6677
@Nullable String secret) {
67-
this(user, token, secret, null);
78+
this(user, token, secret, null, null);
6879
}
6980

7081
private IdpResponse(
71-
User user,
72-
String token,
73-
String secret,
74-
FirebaseUiException e) {
82+
@Nullable User user,
83+
@Nullable String token,
84+
@Nullable String secret,
85+
@Nullable AuthCredential pendingCredential,
86+
@Nullable FirebaseUiException e) {
7587
mUser = user;
7688
mToken = token;
7789
mSecret = secret;
90+
mPendingCredential = pendingCredential;
7891
mException = e;
7992
}
8093

@@ -163,6 +176,14 @@ public String getIdpSecret() {
163176
return mSecret;
164177
}
165178

179+
/**
180+
* TODO: Docs and return type
181+
*/
182+
@Nullable
183+
public AuthCredential getPendingCredential() {
184+
return mPendingCredential;
185+
}
186+
166187
/**
167188
* Get the error code for a failed sign in
168189
*
@@ -195,6 +216,7 @@ public void writeToParcel(Parcel dest, int flags) {
195216
dest.writeParcelable(mUser, flags);
196217
dest.writeString(mToken);
197218
dest.writeString(mSecret);
219+
dest.writeParcelable(mPendingCredential, 0);
198220
dest.writeSerializable(mException);
199221
}
200222

@@ -232,13 +254,21 @@ public String toString() {
232254

233255
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
234256
public static class Builder {
257+
235258
private final User mUser;
259+
private final AuthCredential mCredential;
236260

237261
private String mToken;
238262
private String mSecret;
239263

240264
public Builder(@NonNull User user) {
241265
mUser = user;
266+
mCredential = null;
267+
}
268+
269+
public Builder(@NonNull AuthCredential pendingCredential) {
270+
mUser = null;
271+
mCredential = pendingCredential;
242272
}
243273

244274
public Builder setToken(String token) {
@@ -252,21 +282,28 @@ public Builder setSecret(String secret) {
252282
}
253283

254284
public IdpResponse build() {
255-
String providerId = mUser.getProviderId();
256-
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
257-
throw new IllegalStateException("Unknown provider: " + providerId);
258-
}
259-
if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) {
260-
throw new IllegalStateException(
261-
"Token cannot be null when using a non-email provider.");
262-
}
263-
if (providerId.equals(TwitterAuthProvider.PROVIDER_ID)
264-
&& TextUtils.isEmpty(mSecret)) {
285+
if (mUser != null) {
286+
String providerId = mUser.getProviderId();
287+
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
288+
throw new IllegalStateException("Unknown provider: " + providerId);
289+
}
290+
if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) {
291+
throw new IllegalStateException(
292+
"Token cannot be null when using a non-email provider.");
293+
}
294+
if (providerId.equals(TwitterAuthProvider.PROVIDER_ID)
295+
&& TextUtils.isEmpty(mSecret)) {
296+
throw new IllegalStateException(
297+
"Secret cannot be null when using the Twitter provider.");
298+
}
299+
300+
return new IdpResponse(mUser, mToken, mSecret);
301+
} else if (mCredential != null) {
302+
return new IdpResponse(mCredential);
303+
} else {
265304
throw new IllegalStateException(
266-
"Secret cannot be null when using the Twitter provider.");
305+
"IdpResponse requires either a User or an AuthCredential.");
267306
}
268-
269-
return new IdpResponse(mUser, mToken, mSecret);
270307
}
271308
}
272309
}

auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class FlowParameters implements Parcelable {
5656

5757
public final boolean enableCredentials;
5858
public final boolean enableHints;
59+
public final boolean enableAnonymousUpgrade;
5960

6061
public FlowParameters(
6162
@NonNull String appName,
@@ -65,7 +66,8 @@ public FlowParameters(
6566
@Nullable String termsOfServiceUrl,
6667
@Nullable String privacyPolicyUrl,
6768
boolean enableCredentials,
68-
boolean enableHints) {
69+
boolean enableHints,
70+
boolean enableAnonymousUpgrade) {
6971
this.appName = Preconditions.checkNotNull(appName, "appName cannot be null");
7072
this.providerInfo = Collections.unmodifiableList(
7173
Preconditions.checkNotNull(providerInfo, "providerInfo cannot be null"));
@@ -75,6 +77,7 @@ public FlowParameters(
7577
this.privacyPolicyUrl = privacyPolicyUrl;
7678
this.enableCredentials = enableCredentials;
7779
this.enableHints = enableHints;
80+
this.enableAnonymousUpgrade = enableAnonymousUpgrade;
7881
}
7982

8083
/**
@@ -111,6 +114,7 @@ public void writeToParcel(Parcel dest, int flags) {
111114
dest.writeString(privacyPolicyUrl);
112115
dest.writeInt(enableCredentials ? 1 : 0);
113116
dest.writeInt(enableHints ? 1 : 0);
117+
dest.writeInt(enableAnonymousUpgrade ? 1 : 0);
114118
}
115119

116120
@Override
@@ -129,6 +133,7 @@ public FlowParameters createFromParcel(Parcel in) {
129133
String privacyPolicyUrl = in.readString();
130134
boolean enableCredentials = in.readInt() != 0;
131135
boolean enableHints = in.readInt() != 0;
136+
boolean enableAnonymousUpgrade = in.readInt() != 0;
132137

133138
return new FlowParameters(
134139
appName,
@@ -138,7 +143,8 @@ public FlowParameters createFromParcel(Parcel in) {
138143
termsOfServiceUrl,
139144
privacyPolicyUrl,
140145
enableCredentials,
141-
enableHints);
146+
enableHints,
147+
enableAnonymousUpgrade);
142148
}
143149

144150
@Override

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import com.firebase.ui.auth.data.model.FlowParameters;
1212
import com.firebase.ui.auth.util.AuthHelper;
13+
import com.google.firebase.auth.FirebaseAuth;
1314

1415
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
1516
public class FragmentBase extends Fragment {
@@ -46,6 +47,10 @@ public AuthHelper getAuthHelper() {
4647
return mAuthHelper;
4748
}
4849

50+
public FirebaseAuth getFirebaseAuth() {
51+
return mAuthHelper.getFirebaseAuth();
52+
}
53+
4954
public ProgressDialogHolder getDialogHolder() {
5055
return mProgressDialogHolder;
5156
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.firebase.ui.auth.util.data.ProviderUtils;
2020
import com.firebase.ui.auth.viewmodel.FlowHolder;
2121
import com.google.android.gms.auth.api.credentials.Credential;
22+
import com.google.firebase.auth.FirebaseAuth;
2223
import com.google.firebase.auth.FirebaseUser;
2324

2425
import static com.firebase.ui.auth.util.Preconditions.checkNotNull;
@@ -92,6 +93,10 @@ public AuthHelper getAuthHelper() {
9293
return mAuthHelper;
9394
}
9495

96+
public FirebaseAuth getFirebaseAuth() {
97+
return mAuthHelper.getFirebaseAuth();
98+
}
99+
95100
public ProgressDialogHolder getDialogHolder() {
96101
return mProgressDialogHolder;
97102
}

auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.firebase.ui.auth.ui.FragmentBase;
2424
import com.firebase.ui.auth.ui.TaskFailureLogger;
2525
import com.firebase.ui.auth.ui.idp.WelcomeBackIdpPrompt;
26+
import com.firebase.ui.auth.util.AnonymousUpgradeUtils;
2627
import com.firebase.ui.auth.util.ExtraConstants;
2728
import com.firebase.ui.auth.util.data.ProviderUtils;
2829
import com.firebase.ui.auth.util.ui.ImeHelper;
@@ -43,6 +44,8 @@
4344
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
4445
import com.google.firebase.auth.FirebaseAuthWeakPasswordException;
4546

47+
import static android.app.Activity.RESULT_CANCELED;
48+
4649
/**
4750
* Fragment to display an email/name/password sign up form for new users.
4851
*/
@@ -255,8 +258,8 @@ private void registerUser(final String email, final String name, final String pa
255258
.build())
256259
.build();
257260

258-
getAuthHelper().getFirebaseAuth()
259-
.createUserWithEmailAndPassword(email, password)
261+
AnonymousUpgradeUtils
262+
.signUpOrLink(getFlowParams(), getAuthHelper().getFirebaseAuth(), email, password)
260263
.continueWithTask(new ProfileMerger(response))
261264
.addOnFailureListener(new TaskFailureLogger(TAG, "Error creating user"))
262265
.addOnSuccessListener(getActivity(), new OnSuccessListener<AuthResult>() {
@@ -268,7 +271,12 @@ public void onSuccess(AuthResult authResult) {
268271
.addOnFailureListener(getActivity(), new OnFailureListener() {
269272
@Override
270273
public void onFailure(@NonNull Exception e) {
271-
if (e instanceof FirebaseAuthWeakPasswordException) {
274+
if (AnonymousUpgradeUtils.isUpgradeFailure(getFlowParams(), getFirebaseAuth(), e)) {
275+
// Anonymous collision
276+
IdpResponse res = new IdpResponse.Builder(EmailAuthProvider.getCredential(email, password))
277+
.build();
278+
finish(RESULT_CANCELED, res.toIntent());
279+
} else if (e instanceof FirebaseAuthWeakPasswordException) {
272280
// Password too weak
273281
mPasswordInput.setError(getResources().getQuantityString(
274282
R.plurals.fui_error_weak_password, R.integer.fui_min_password_length));
@@ -323,6 +331,9 @@ public void onComplete(@NonNull Task<String> task) {
323331
getDialogHolder().dismissDialog();
324332
}
325333
});
334+
335+
// This return statement prevents the dialog from being dismissed in
336+
// this case ... we should refactor.
326337
return;
327338
} else {
328339
// General error message, this branch should not be invoked but

auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
import com.firebase.ui.auth.ui.TaskFailureLogger;
4545
import com.firebase.ui.auth.ui.email.EmailActivity;
4646
import com.firebase.ui.auth.ui.phone.PhoneActivity;
47+
import com.firebase.ui.auth.util.AnonymousUpgradeUtils;
4748
import com.firebase.ui.auth.util.data.ProviderUtils;
49+
import com.google.android.gms.tasks.OnFailureListener;
4850
import com.google.android.gms.tasks.OnSuccessListener;
4951
import com.google.firebase.auth.AuthCredential;
5052
import com.google.firebase.auth.AuthResult;
@@ -162,18 +164,30 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
162164

163165
@Override
164166
public void onSuccess(@NonNull final IdpResponse response) {
165-
AuthCredential credential = ProviderUtils.getAuthCredential(response);
166-
getAuthHelper().getFirebaseAuth()
167-
.signInWithCredential(credential)
167+
final AuthCredential credential = ProviderUtils.getAuthCredential(response);
168+
169+
AnonymousUpgradeUtils
170+
.signInOrLink(getFlowParams(), getFirebaseAuth(), credential)
168171
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
169172
@Override
170173
public void onSuccess(AuthResult authResult) {
171174
FirebaseUser firebaseUser = authResult.getUser();
172175
startSaveCredentials(firebaseUser, null, response);
173176
}
174177
})
175-
.addOnFailureListener(new CredentialSignInHandler(
176-
this, RC_ACCOUNT_LINK, response))
178+
.addOnFailureListener(new OnFailureListener() {
179+
@Override
180+
public void onFailure(@NonNull Exception e) {
181+
if (AnonymousUpgradeUtils.isUpgradeFailure(getFlowParams(), getFirebaseAuth(), e)) {
182+
IdpResponse res = new IdpResponse.Builder(credential).build();
183+
finish(RESULT_CANCELED, res.toIntent());
184+
} else {
185+
new CredentialSignInHandler(AuthMethodPickerActivity.this,
186+
RC_ACCOUNT_LINK,
187+
response).onFailure(e);
188+
}
189+
}
190+
})
177191
.addOnFailureListener(
178192
new TaskFailureLogger(TAG, "Firebase sign in with credential " +
179193
credential.getProvider() + " unsuccessful. " +

0 commit comments

Comments
 (0)