Skip to content

Commit 01f1ca1

Browse files
committed
Very basic linking
Change-Id: I50b05d1e50865c9f2dc5e231569e237c631e0003
1 parent b7a3b7f commit 01f1ca1

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,25 +40,36 @@ public class IdpResponse implements Parcelable {
3940

4041
private final FirebaseUiException mException;
4142

43+
private final AuthCredential mPendingCredential;
44+
4245
private IdpResponse(@NonNull FirebaseUiException e) {
43-
this(null, null, null, e);
46+
this(null, null, null, null, e);
47+
}
48+
49+
private IdpResponse(@NonNull AuthCredential pendingCredential) {
50+
this(
51+
null, null, null, /* user, token, and secret */
52+
pendingCredential,
53+
new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT));
4454
}
4555

4656
private IdpResponse(
4757
@NonNull User user,
4858
@Nullable String token,
4959
@Nullable String secret) {
50-
this(user, token, secret, null);
60+
this(user, token, secret, null, null);
5161
}
5262

5363
private IdpResponse(
54-
User user,
55-
String token,
56-
String secret,
57-
FirebaseUiException e) {
64+
@Nullable User user,
65+
@Nullable String token,
66+
@Nullable String secret,
67+
@Nullable AuthCredential pendingCredential,
68+
@Nullable FirebaseUiException e) {
5869
mUser = user;
5970
mToken = token;
6071
mSecret = secret;
72+
mPendingCredential = pendingCredential;
6173
mException = e;
6274
}
6375

@@ -146,6 +158,14 @@ public String getIdpSecret() {
146158
return mSecret;
147159
}
148160

161+
/**
162+
* TODO: Docs and return type
163+
*/
164+
@Nullable
165+
public AuthCredential getPendingCredential() {
166+
return mPendingCredential;
167+
}
168+
149169
/**
150170
* Get the error code for a failed sign in
151171
*
@@ -178,6 +198,7 @@ public void writeToParcel(Parcel dest, int flags) {
178198
dest.writeParcelable(mUser, flags);
179199
dest.writeString(mToken);
180200
dest.writeString(mSecret);
201+
dest.writeParcelable(mPendingCredential, 0);
181202
dest.writeSerializable(mException);
182203
}
183204

@@ -188,6 +209,7 @@ public IdpResponse createFromParcel(Parcel in) {
188209
in.<User>readParcelable(User.class.getClassLoader()),
189210
in.readString(),
190211
in.readString(),
212+
(AuthCredential) in.readParcelable(AuthCredential.class.getClassLoader()),
191213
(FirebaseUiException) in.readSerializable()
192214
);
193215
}
@@ -200,13 +222,21 @@ public IdpResponse[] newArray(int size) {
200222

201223
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
202224
public static class Builder {
225+
203226
private final User mUser;
227+
private final AuthCredential mCredential;
204228

205229
private String mToken;
206230
private String mSecret;
207231

208232
public Builder(@NonNull User user) {
209233
mUser = user;
234+
mCredential = null;
235+
}
236+
237+
public Builder(@NonNull AuthCredential pendingCredential) {
238+
mUser = null;
239+
mCredential = pendingCredential;
210240
}
211241

212242
public Builder setToken(String token) {
@@ -220,21 +250,28 @@ public Builder setSecret(String secret) {
220250
}
221251

222252
public IdpResponse build() {
223-
String providerId = mUser.getProviderId();
224-
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
225-
throw new IllegalStateException("Unknown provider: " + providerId);
226-
}
227-
if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) {
228-
throw new IllegalStateException(
229-
"Token cannot be null when using a non-email provider.");
230-
}
231-
if (providerId.equals(TwitterAuthProvider.PROVIDER_ID)
232-
&& TextUtils.isEmpty(mSecret)) {
253+
if (mUser != null) {
254+
String providerId = mUser.getProviderId();
255+
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
256+
throw new IllegalStateException("Unknown provider: " + providerId);
257+
}
258+
if (AuthUI.SOCIAL_PROVIDERS.contains(providerId) && TextUtils.isEmpty(mToken)) {
259+
throw new IllegalStateException(
260+
"Token cannot be null when using a non-email provider.");
261+
}
262+
if (providerId.equals(TwitterAuthProvider.PROVIDER_ID)
263+
&& TextUtils.isEmpty(mSecret)) {
264+
throw new IllegalStateException(
265+
"Secret cannot be null when using the Twitter provider.");
266+
}
267+
268+
return new IdpResponse(mUser, mToken, mSecret);
269+
} else if (mCredential != null) {
270+
return new IdpResponse(mCredential);
271+
} else {
233272
throw new IllegalStateException(
234-
"Secret cannot be null when using the Twitter provider.");
273+
"IdpResponse requires either a User or an AuthCredential.");
235274
}
236-
237-
return new IdpResponse(mUser, mToken, mSecret);
238275
}
239276
}
240277
}

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)