-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Cleanup + make sure IdpResponse is never null if resultCode == ResultCodes.OK #469
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 all commits
e00950d
3e9fb89
5d2c0dc
9f6605c
bb49369
b825b02
5d4bde8
076e3c0
9541c6c
04d9e36
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 |
---|---|---|
|
@@ -80,29 +80,32 @@ | |
android:text="@string/auth_providers_header"/> | ||
|
||
<CheckBox | ||
android:id="@+id/email_provider" | ||
android:id="@+id/google_provider" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:checked="true" | ||
android:text="@string/email_label"/> | ||
android:text="@string/google_label"/> | ||
|
||
<CheckBox | ||
android:id="@+id/facebook_provider" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:checked="true" | ||
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. Make all providers be checked by default and use standard order: Google, Facebook, Twitter, Email. |
||
android:text="@string/facebook_label"/> | ||
|
||
<CheckBox | ||
android:id="@+id/google_provider" | ||
android:id="@+id/twitter_provider" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:text="@string/google_label"/> | ||
android:checked="true" | ||
android:text="@string/twitter_label"/> | ||
|
||
<CheckBox | ||
android:id="@+id/twitter_provider" | ||
android:id="@+id/email_provider" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:text="@string/twitter_label"/> | ||
android:checked="true" | ||
android:text="@string/email_label"/> | ||
|
||
<TextView | ||
style="@style/Base.TextAppearance.AppCompat.Subhead" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,10 +4,6 @@ | |
* Error codes retrieved from {@link IdpResponse#getErrorCode()}. | ||
*/ | ||
public final class ErrorCodes { | ||
private ErrorCodes() { | ||
// We don't want people to initialize this class | ||
} | ||
|
||
/** | ||
* Sign in failed due to lack of network connection | ||
**/ | ||
|
@@ -17,4 +13,8 @@ private ErrorCodes() { | |
* An unknown error has occurred | ||
**/ | ||
public static final int UNKNOWN_ERROR = 20; | ||
|
||
private ErrorCodes() { | ||
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. nit: why do we need a constructor for this class at all? 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. We don't, this was just formalizing the class as a " 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. Got it. Had not seen that technique before but I like it. |
||
// no instance | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,38 +40,40 @@ | |
import com.firebase.ui.auth.ui.ExtraConstants; | ||
import com.firebase.ui.auth.ui.FlowParameters; | ||
import com.firebase.ui.auth.ui.TaskFailureLogger; | ||
import com.firebase.ui.auth.ui.User; | ||
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.firebase.auth.AuthCredential; | ||
import com.google.firebase.auth.AuthResult; | ||
import com.google.firebase.auth.FacebookAuthProvider; | ||
import com.google.firebase.auth.FirebaseAuth; | ||
import com.google.firebase.auth.FirebaseUser; | ||
import com.google.firebase.auth.GoogleAuthProvider; | ||
import com.google.firebase.auth.TwitterAuthProvider; | ||
|
||
public class WelcomeBackIdpPrompt extends AppCompatBase | ||
implements View.OnClickListener, IdpCallback { | ||
public class WelcomeBackIdpPrompt extends AppCompatBase implements IdpCallback { | ||
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 one was a mess!!! I've been struggling to understand what's going on in #309 for a while now so I decided it was time for a rewrite. If you look at the class without all the crazy diff stuff, it's much clearer what's going on now. |
||
private static final String TAG = "WelcomeBackIdpPrompt"; | ||
|
||
private static final String TAG = "WelcomeBackIDPPrompt"; | ||
private IdpProvider mIdpProvider; | ||
private IdpResponse mPrevIdpResponse; | ||
private AuthCredential mPrevCredential; | ||
|
||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
String providerId = getProviderIdFromIntent(); | ||
mPrevIdpResponse = IdpResponse.fromResultIntent(getIntent()); | ||
setContentView(R.layout.welcome_back_idp_prompt_layout); | ||
|
||
mIdpProvider = null; | ||
IdpResponse newUserIdpResponse = IdpResponse.fromResultIntent(getIntent()); | ||
mPrevCredential = AuthCredentialHelper.getAuthCredential(newUserIdpResponse); | ||
|
||
User oldUser = User.getUser(getIntent()); | ||
|
||
String providerId = oldUser.getProvider(); | ||
for (IdpConfig idpConfig : mActivityHelper.getFlowParams().providerInfo) { | ||
if (providerId.equals(idpConfig.getProviderId())) { | ||
switch (providerId) { | ||
case GoogleAuthProvider.PROVIDER_ID: | ||
mIdpProvider = new GoogleProvider(this, idpConfig, getEmailFromIntent()); | ||
mIdpProvider = new GoogleProvider(this, idpConfig, oldUser.getEmail()); | ||
break; | ||
case FacebookAuthProvider.PROVIDER_ID: | ||
mIdpProvider = new FacebookProvider( | ||
|
@@ -89,21 +91,16 @@ protected void onCreate(Bundle savedInstanceState) { | |
} | ||
} | ||
|
||
if (mPrevIdpResponse != null) { | ||
mPrevCredential = AuthCredentialHelper.getAuthCredential(mPrevIdpResponse); | ||
} | ||
|
||
if (mIdpProvider == null) { | ||
getIntent().putExtra( | ||
ExtraConstants.EXTRA_ERROR_MESSAGE, | ||
"Firebase login successful." + | ||
" Account linking failed due to provider not enabled by application"); | ||
Log.w(TAG, "Firebase login unsuccessful." | ||
+ " Account linking failed due to provider not enabled by application: " | ||
+ providerId); | ||
finish(ResultCodes.CANCELED, IdpResponse.getErrorCodeIntent(ErrorCodes.UNKNOWN_ERROR)); | ||
return; | ||
} | ||
|
||
((TextView) findViewById(R.id.welcome_back_idp_prompt)) | ||
.setText(getIdpPromptString(getEmailFromIntent())); | ||
.setText(getIdpPromptString(oldUser.getEmail())); | ||
|
||
mIdpProvider.setAuthenticationCallback(this); | ||
findViewById(R.id.welcome_back_idp_button).setOnClickListener(new OnClickListener() { | ||
|
@@ -127,83 +124,71 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { | |
} | ||
|
||
@Override | ||
public void onClick(View view) { | ||
next(mPrevIdpResponse); | ||
} | ||
|
||
@Override | ||
public void onSuccess(IdpResponse idpResponse) { | ||
next(idpResponse); | ||
} | ||
|
||
@Override | ||
public void onFailure(Bundle extra) { | ||
Toast.makeText(getApplicationContext(), "Error signing in", Toast.LENGTH_LONG).show(); | ||
finish(ResultCodes.CANCELED, IdpResponse.getErrorCodeIntent(ErrorCodes.UNKNOWN_ERROR)); | ||
} | ||
|
||
private String getProviderIdFromIntent() { | ||
return getIntent().getStringExtra(ExtraConstants.EXTRA_PROVIDER); | ||
} | ||
|
||
private String getEmailFromIntent() { | ||
return getIntent().getStringExtra(ExtraConstants.EXTRA_EMAIL); | ||
} | ||
|
||
private void next(final IdpResponse newIdpResponse) { | ||
if (newIdpResponse == null) { | ||
public void onSuccess(final IdpResponse idpResponse) { | ||
if (idpResponse == null) { | ||
return; // do nothing | ||
} | ||
|
||
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. Ahhhhhh!!! It took me so long in #309 to "understand" what was going on only to find out I was wrong: we never even used this click listener! That kills me! 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 it took me a little while to see what was going on here too. Good find! This stray listener could have bitten us down the road. |
||
AuthCredential newCredential = AuthCredentialHelper.getAuthCredential(newIdpResponse); | ||
AuthCredential newCredential = AuthCredentialHelper.getAuthCredential(idpResponse); | ||
if (newCredential == null) { | ||
Log.e(TAG, "No credential returned"); | ||
finish(ResultCodes.CANCELED, IdpResponse.getErrorCodeIntent(ErrorCodes.UNKNOWN_ERROR)); | ||
return; | ||
} | ||
|
||
final FirebaseAuth firebaseAuth = mActivityHelper.getFirebaseAuth(); | ||
FirebaseUser currentUser = firebaseAuth.getCurrentUser(); | ||
|
||
FirebaseUser currentUser = mActivityHelper.getCurrentUser(); | ||
if (currentUser == null) { | ||
Task<AuthResult> authResultTask = firebaseAuth.signInWithCredential(newCredential); | ||
authResultTask.addOnCompleteListener(new OnCompleteListener<AuthResult>() { | ||
@Override | ||
public void onComplete(@NonNull Task<AuthResult> task) { | ||
if (task.isSuccessful() && mPrevCredential != null) { | ||
FirebaseUser firebaseUser = task.getResult().getUser(); | ||
firebaseUser.linkWithCredential(mPrevCredential); | ||
firebaseAuth.signOut(); | ||
firebaseAuth | ||
.signInWithCredential(mPrevCredential) | ||
.addOnFailureListener(new TaskFailureLogger( | ||
TAG, "Error signing in with previous credential")) | ||
.addOnCompleteListener(new FinishListener(newIdpResponse)); | ||
} else { | ||
finish(ResultCodes.OK, IdpResponse.getIntent(newIdpResponse)); | ||
} | ||
} | ||
}).addOnFailureListener( | ||
new TaskFailureLogger(TAG, "Error signing in with new credential")); | ||
mActivityHelper.getFirebaseAuth() | ||
.signInWithCredential(newCredential) | ||
.addOnSuccessListener(new OnSuccessListener<AuthResult>() { | ||
@Override | ||
public void onSuccess(AuthResult result) { | ||
if (mPrevCredential != null) { | ||
result.getUser() | ||
.linkWithCredential(mPrevCredential) | ||
.addOnFailureListener(new TaskFailureLogger( | ||
TAG, "Error signing in with previous credential")) | ||
.addOnCompleteListener(new FinishListener(idpResponse)); | ||
} else { | ||
finish(ResultCodes.OK, IdpResponse.getIntent(idpResponse)); | ||
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 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. I believe this was the original intention: if we have a previous credential, link it, else, finish ok. Previously, if we either didn't have a previous credential or the task failed, we would finish ok. Because we would finish ok if we didn't have a previous credential, this isn't a behavior change. |
||
} | ||
} | ||
}) | ||
.addOnFailureListener(new OnFailureListener() { | ||
@Override | ||
public void onFailure(@NonNull Exception e) { | ||
finishWithError(); | ||
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. On failure, we fail. |
||
} | ||
}) | ||
.addOnFailureListener( | ||
new TaskFailureLogger(TAG, "Error signing in with new credential")); | ||
} else { | ||
Task<AuthResult> authResultTask = currentUser.linkWithCredential(newCredential); | ||
authResultTask | ||
currentUser | ||
.linkWithCredential(newCredential) | ||
.addOnFailureListener( | ||
new TaskFailureLogger(TAG, "Error linking with credential")) | ||
.addOnCompleteListener(new FinishListener(newIdpResponse)); | ||
.addOnCompleteListener(new FinishListener(idpResponse)); | ||
} | ||
} | ||
|
||
@Override | ||
public void onFailure(Bundle extra) { | ||
finishWithError(); | ||
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. 😢 |
||
} | ||
|
||
private void finishWithError() { | ||
Toast.makeText(this, R.string.general_error, Toast.LENGTH_LONG).show(); | ||
finish(ResultCodes.CANCELED, IdpResponse.getErrorCodeIntent(ErrorCodes.UNKNOWN_ERROR)); | ||
} | ||
|
||
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. BAD! (I think) |
||
public static Intent createIntent( | ||
Context context, | ||
FlowParameters flowParams, | ||
String providerId, | ||
IdpResponse idpResponse, | ||
String email) { | ||
User existingUser, | ||
IdpResponse newUserResponse) { | ||
return BaseHelper.createBaseIntent(context, WelcomeBackIdpPrompt.class, flowParams) | ||
.putExtra(ExtraConstants.EXTRA_PROVIDER, providerId) | ||
.putExtra(ExtraConstants.EXTRA_IDP_RESPONSE, idpResponse) | ||
.putExtra(ExtraConstants.EXTRA_EMAIL, email); | ||
.putExtra(ExtraConstants.EXTRA_USER, existingUser) | ||
.putExtra(ExtraConstants.EXTRA_IDP_RESPONSE, newUserResponse); | ||
} | ||
|
||
private class FinishListener implements OnCompleteListener<AuthResult> { | ||
|
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.
Only show the token/secret if we have one.