-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Upgrading anonymous accounts #1358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
150b518
2037e85
de66606
db825f3
be0d864
268b80a
71c93da
eee18ce
2acd64c
9d8fbbf
30436b8
736eb9e
d6e0705
24f9c25
e7ee453
ab1b0ee
5271c39
92bfc67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package com.firebase.uidemo.auth; | ||
|
||
import android.content.Intent; | ||
import android.os.Bundle; | ||
import android.support.annotation.NonNull; | ||
import android.support.v7.app.AppCompatActivity; | ||
import android.text.TextUtils; | ||
import android.util.Log; | ||
import android.widget.Button; | ||
import android.widget.TextView; | ||
import android.widget.Toast; | ||
|
||
import com.firebase.ui.auth.AuthUI; | ||
import com.firebase.ui.auth.ErrorCodes; | ||
import com.firebase.ui.auth.IdpResponse; | ||
import com.firebase.uidemo.R; | ||
import com.google.android.gms.tasks.OnCompleteListener; | ||
import com.google.android.gms.tasks.Task; | ||
import com.google.firebase.auth.AuthCredential; | ||
import com.google.firebase.auth.AuthResult; | ||
import com.google.firebase.auth.FirebaseAuth; | ||
import com.google.firebase.auth.FirebaseUser; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import butterknife.BindView; | ||
import butterknife.ButterKnife; | ||
import butterknife.OnClick; | ||
|
||
public class AnonymousUpgradeActivity extends AppCompatActivity { | ||
|
||
private static final String TAG = "AccountLink"; | ||
|
||
private static final int RC_SIGN_IN = 123; | ||
|
||
@BindView(R.id.status_text) | ||
TextView mStatus; | ||
|
||
@BindView(R.id.anon_sign_in) | ||
Button mAnonSignInButton; | ||
|
||
@BindView(R.id.begin_flow) | ||
Button mLaunchUIButton; | ||
|
||
@BindView(R.id.resolve_merge) | ||
Button mResolveMergeButton; | ||
|
||
@BindView(R.id.sign_out) | ||
Button mSignOutButton; | ||
|
||
private AuthCredential mPendingCredential; | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
setContentView(R.layout.activity_anonymous_upgrade); | ||
ButterKnife.bind(this); | ||
} | ||
|
||
@OnClick(R.id.anon_sign_in) | ||
public void signInAnonymously() { | ||
FirebaseAuth.getInstance().signInAnonymously() | ||
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { | ||
@Override | ||
public void onComplete(@NonNull Task<AuthResult> task) { | ||
updateUI(); | ||
|
||
if (task.isSuccessful()) { | ||
setStatus("Signed in anonymously as user " | ||
+ getUserIdentifier(task.getResult().getUser())); | ||
} else { | ||
setStatus("Anonymous sign in failed."); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
@OnClick(R.id.begin_flow) | ||
public void startAuthUI() { | ||
List<AuthUI.IdpConfig> providers = Arrays.asList( | ||
new AuthUI.IdpConfig.EmailBuilder().build(), | ||
new AuthUI.IdpConfig.PhoneBuilder().build(), | ||
new AuthUI.IdpConfig.GoogleBuilder().build()); | ||
|
||
Intent intent = AuthUI.getInstance().createSignInIntentBuilder() | ||
.setAvailableProviders(providers) | ||
.setIsSmartLockEnabled(false) | ||
.setAutoUpgradeAnonymousUsers() | ||
.build(); | ||
|
||
startActivityForResult(intent, RC_SIGN_IN); | ||
} | ||
|
||
@OnClick(R.id.resolve_merge) | ||
public void resolveMerge() { | ||
if (mPendingCredential == null) { | ||
Toast.makeText(this, "Nothing to resolve.", Toast.LENGTH_SHORT).show(); | ||
return; | ||
} | ||
|
||
// TODO: Show how to do good data moving | ||
|
||
FirebaseAuth.getInstance().signInWithCredential(mPendingCredential) | ||
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { | ||
@Override | ||
public void onComplete(@NonNull Task<AuthResult> task) { | ||
mPendingCredential = null; | ||
updateUI(); | ||
|
||
if (task.isSuccessful()) { | ||
setStatus("Signed in as " + getUserIdentifier(task.getResult().getUser())); | ||
} else { | ||
Log.w(TAG, "Merge failed", task.getException()); | ||
setStatus("Failed to resolve merge conflict, see logs."); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
@OnClick(R.id.sign_out) | ||
public void signOut() { | ||
AuthUI.getInstance().signOut(this) | ||
.addOnCompleteListener(new OnCompleteListener<Void>() { | ||
@Override | ||
public void onComplete(@NonNull Task<Void> task) { | ||
setStatus(null); | ||
updateUI(); | ||
} | ||
}); | ||
} | ||
|
||
@Override | ||
protected void onActivityResult(int requestCode, int resultCode, Intent data) { | ||
super.onActivityResult(requestCode, resultCode, data); | ||
if (requestCode == RC_SIGN_IN) { | ||
IdpResponse response = IdpResponse.fromResultIntent(data); | ||
if (resultCode == RESULT_OK) { | ||
setStatus("Signed in as " + getUserIdentifier(FirebaseAuth.getInstance().getCurrentUser())); | ||
} else { | ||
if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { | ||
setStatus("Merge conflict: user already exists."); | ||
mResolveMergeButton.setEnabled(true); | ||
mPendingCredential = response.getCredentialForLinking(); | ||
} | ||
} | ||
|
||
updateUI(); | ||
} | ||
} | ||
|
||
private void updateUI() { | ||
FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); | ||
|
||
if (currentUser == null) { | ||
// Not signed in | ||
mAnonSignInButton.setEnabled(true); | ||
mLaunchUIButton.setEnabled(false); | ||
mResolveMergeButton.setEnabled(false); | ||
mSignOutButton.setEnabled(false); | ||
} else if (mPendingCredential == null && currentUser.isAnonymous()) { | ||
// Anonymous user, waiting for linking | ||
mAnonSignInButton.setEnabled(false); | ||
mLaunchUIButton.setEnabled(true); | ||
mResolveMergeButton.setEnabled(false); | ||
mSignOutButton.setEnabled(true); | ||
} else if (mPendingCredential == null && !currentUser.isAnonymous()) { | ||
// Fully signed in | ||
mAnonSignInButton.setEnabled(false); | ||
mLaunchUIButton.setEnabled(false); | ||
mResolveMergeButton.setEnabled(false); | ||
mSignOutButton.setEnabled(true); | ||
} else if (mPendingCredential != null) { | ||
// Signed in anonymous, awaiting merge conflict | ||
mAnonSignInButton.setEnabled(false); | ||
mLaunchUIButton.setEnabled(false); | ||
mResolveMergeButton.setEnabled(true); | ||
mSignOutButton.setEnabled(true); | ||
} | ||
} | ||
|
||
private void setStatus(String message) { | ||
mStatus.setText(message); | ||
} | ||
|
||
private String getUserIdentifier(FirebaseUser user) { | ||
if (user.isAnonymous()) { | ||
return user.getUid(); | ||
} else if (!TextUtils.isEmpty(user.getEmail())) { | ||
return user.getEmail(); | ||
} else if (!TextUtils.isEmpty(user.getPhoneNumber())) { | ||
return user.getPhoneNumber(); | ||
} else { | ||
return "unknown"; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<LinearLayout | ||
xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
android:id="@+id/root" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:layout_marginLeft="24dp" | ||
android:layout_marginRight="24dp" | ||
android:layout_marginTop="16dp" | ||
android:layout_marginBottom="16dp" | ||
android:orientation="vertical" | ||
tools:context=".auth.AuthUiActivity"> | ||
|
||
|
||
<TextView | ||
style="@style/Base.TextAppearance.AppCompat.Headline" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:layout_gravity="center_horizontal" | ||
android:drawableTop="@drawable/firebase_auth_120dp" | ||
android:text="@string/title_anonymous_upgrade" /> | ||
|
||
<TextView | ||
android:id="@+id/status_text" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:layout_margin="16dp" | ||
android:gravity="center" | ||
android:textIsSelectable="true" | ||
tools:text="This is the status view, sometimes it will have a very long status and other..." /> | ||
|
||
<Button | ||
android:id="@+id/anon_sign_in" | ||
style="@style/Widget.AppCompat.Button.Colored" | ||
android:layout_width="200dp" | ||
android:layout_height="wrap_content" | ||
android:layout_gravity="center" | ||
android:text="@string/anonymous_sign_in" /> | ||
|
||
<Button | ||
android:id="@+id/begin_flow" | ||
style="@style/Widget.AppCompat.Button.Colored" | ||
android:layout_width="200dp" | ||
android:layout_height="wrap_content" | ||
android:layout_gravity="center" | ||
android:text="@string/launch_auth_ui" | ||
android:enabled="false" /> | ||
|
||
<Button | ||
android:id="@+id/resolve_merge" | ||
style="@style/Widget.AppCompat.Button.Colored" | ||
android:layout_width="200dp" | ||
android:layout_height="wrap_content" | ||
android:layout_gravity="center" | ||
android:text="@string/resolve_merge_conflict" | ||
android:enabled="false" /> | ||
|
||
<Button | ||
android:id="@+id/sign_out" | ||
style="@style/Widget.AppCompat.Button.Colored" | ||
android:layout_width="200dp" | ||
android:layout_height="wrap_content" | ||
android:layout_gravity="center" | ||
android:text="@string/sign_out" | ||
android:enabled="false" /> | ||
|
||
</LinearLayout> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1107,10 +1107,23 @@ public Intent build() { | |
* Builder for the intent to start the user authentication flow. | ||
*/ | ||
public final class SignInIntentBuilder extends AuthIntentBuilder<SignInIntentBuilder> { | ||
|
||
private boolean mEnableAnonymousUpgrade; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason why this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The doc says to add it in SignInIntentBuilder. You also added it here in your PR. |
||
|
||
private SignInIntentBuilder() { | ||
super(); | ||
} | ||
|
||
/** | ||
* Enables or disables upgrading anonymous accounts to full accounts during the sign-in | ||
* flow. This is disabled by default. | ||
*/ | ||
@NonNull | ||
public SignInIntentBuilder setAutoUpgradeAnonymousUsers() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should take in a boolean There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure but when would they ever call this with false? It's disabled by default. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, gotya. Then the javadoc needs to be updated to just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I'm going to ask if I can change the API actually. It'll probably have to take in a boolean to be the same as iOS/Web There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lsirac you can definitely change the API to take a boolean without asking anyone. |
||
mEnableAnonymousUpgrade = true; | ||
return this; | ||
} | ||
|
||
@Override | ||
protected FlowParameters getFlowParams() { | ||
return new FlowParameters( | ||
|
@@ -1121,7 +1134,8 @@ protected FlowParameters getFlowParams() { | |
mTosUrl, | ||
mPrivacyPolicyUrl, | ||
mEnableCredentials, | ||
mEnableHints); | ||
mEnableHints, | ||
mEnableAnonymousUpgrade); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Erroneous import
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.