From c8a890d83200b3d9a93037010ca1eeb4546c9bb4 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Thu, 10 Aug 2017 12:31:09 -0700 Subject: [PATCH 01/28] Add support for account linking Signed-off-by: Alex Saveau --- .../firebase/uidemo/auth/AuthUiActivity.java | 12 +- .../uidemo/auth/SignedInActivity.java | 33 ++- .../uidemo/database/ChatIndexActivity.java | 12 +- app/src/main/res/layout/signed_in_layout.xml | 41 +++- app/src/main/res/values/strings.xml | 2 + auth/README.md | 90 +++++++++ .../java/com/firebase/ui/auth/AuthUI.java | 17 ++ .../com/firebase/ui/auth/IdpResponse.java | 14 ++ .../main/java/com/firebase/ui/auth/User.java | 37 +++- .../firebase/ui/auth/ui/FlowParameters.java | 15 ++ .../ui/auth/ui/TaskFailureLogger.java | 5 +- .../ui/accountlink/WelcomeBackIdpPrompt.java | 68 +------ .../WelcomeBackPasswordPrompt.java | 23 ++- .../auth/ui/email/RegisterEmailFragment.java | 14 +- .../auth/ui/idp/AuthMethodPickerActivity.java | 20 +- .../auth/ui/idp/CredentialSignInHandler.java | 12 ++ .../ui/phone/PhoneVerificationActivity.java | 121 +++++------ .../com/firebase/ui/auth/util/AuthHelper.java | 9 + .../auth/util/accountlink/AccountLinker.java | 189 ++++++++++++++++++ .../util/accountlink/ManualMergeService.java | 50 +++++ .../util/accountlink/ManualMergeUtils.java | 162 +++++++++++++++ .../signincontainer/IdpSignInContainer.java | 16 +- .../util/signincontainer/SignInDelegate.java | 24 ++- .../ui/auth/testhelpers/AuthHelperShadow.java | 12 ++ .../ui/auth/testhelpers/TestHelper.java | 18 +- .../ui/email/RegisterEmailActivityTest.java | 12 +- .../email/WelcomeBackPasswordPromptTest.java | 3 +- .../ui/idp/AuthMethodPickerActivityTest.java | 12 +- .../phone/PhoneVerificationActivityTest.java | 3 + 29 files changed, 866 insertions(+), 180 deletions(-) create mode 100644 auth/src/main/java/com/firebase/ui/auth/util/accountlink/AccountLinker.java create mode 100644 auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeService.java create mode 100644 auth/src/main/java/com/firebase/ui/auth/util/accountlink/ManualMergeUtils.java diff --git a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java index 1b01434e9..da8b6a8f1 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java @@ -55,6 +55,7 @@ public class AuthUiActivity extends AppCompatActivity { private static final String FIREBASE_PRIVACY_POLICY_URL = "https://firebase.google.com/terms/analytics/#7_privacy"; private static final int RC_SIGN_IN = 100; + private static final String OVERRIDE_LOGIN_CHECKS_EXTRA = "overide_login_checks"; @BindView(R.id.default_theme) RadioButton mUseDefaultTheme; @@ -137,8 +138,9 @@ public class AuthUiActivity extends AppCompatActivity { @BindView(R.id.google_scope_youtube_data) CheckBox mGoogleScopeYoutubeData; - public static Intent createIntent(Context context) { - return new Intent(context, AuthUiActivity.class); + public static Intent createIntent(Context context, boolean overrideLoginChecks) { + return new Intent(context, AuthUiActivity.class) + .putExtra(OVERRIDE_LOGIN_CHECKS_EXTRA, overrideLoginChecks); } @Override @@ -147,8 +149,8 @@ public void onCreate(Bundle savedInstanceState) { setContentView(R.layout.auth_ui_layout); ButterKnife.bind(this); - FirebaseAuth auth = FirebaseAuth.getInstance(); - if (auth.getCurrentUser() != null) { + if (FirebaseAuth.getInstance().getCurrentUser() != null + && !getIntent().getBooleanExtra(OVERRIDE_LOGIN_CHECKS_EXTRA, false)) { startSignedInActivity(null); finish(); return; @@ -206,6 +208,7 @@ public void signIn(View view) { .setPrivacyPolicyUrl(getSelectedPrivacyPolicyUrl()) .setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(), mEnableHintSelector.isChecked()) + .setIsAccountLinkingEnabled(true, null) .setAllowNewEmailAccounts(mAllowNewEmailAccounts.isChecked()) .build(), RC_SIGN_IN); @@ -229,6 +232,7 @@ private void handleSignInResponse(int resultCode, Intent data) { // Successfully signed in if (resultCode == RESULT_OK) { startSignedInActivity(response); + setResult(RESULT_OK); finish(); return; } else { diff --git a/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java b/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java index 72ec52629..ca9bd40ec 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java @@ -56,6 +56,7 @@ public class SignedInActivity extends AppCompatActivity { private static final String EXTRA_IDP_RESPONSE = "extra_idp_response"; private static final String EXTRA_SIGNED_IN_CONFIG = "extra_signed_in_config"; + private static final int RC_LINK_ACCOUNT = 4433; @BindView(android.R.id.content) View mRootView; @@ -100,7 +101,7 @@ public void onCreate(Bundle savedInstanceState) { FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); if (currentUser == null) { - startActivity(AuthUiActivity.createIntent(this)); + startActivity(AuthUiActivity.createIntent(this, false)); finish(); return; } @@ -112,6 +113,15 @@ public void onCreate(Bundle savedInstanceState) { ButterKnife.bind(this); populateProfile(); populateIdpToken(); + populatePrevUid(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == RC_LINK_ACCOUNT && resultCode == RESULT_OK) { + finish(); + } } @OnClick(R.id.sign_out) @@ -122,7 +132,7 @@ public void signOut() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { - startActivity(AuthUiActivity.createIntent(SignedInActivity.this)); + startActivity(AuthUiActivity.createIntent(SignedInActivity.this, false)); finish(); } else { showSnackbar(R.string.sign_out_failed); @@ -131,6 +141,11 @@ public void onComplete(@NonNull Task task) { }); } + @OnClick(R.id.link_account) + public void linkAccount() { + startActivityForResult(AuthUiActivity.createIntent(this, true), RC_LINK_ACCOUNT); + } + @OnClick(R.id.delete_account) public void deleteAccountClicked() { new AlertDialog.Builder(this) @@ -141,7 +156,7 @@ public void onClick(DialogInterface dialogInterface, int i) { deleteAccount(); } }) - .setNegativeButton("No", null) + .setNegativeButton(android.R.string.no, null) .show(); } @@ -152,7 +167,7 @@ private void deleteAccount() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { - startActivity(AuthUiActivity.createIntent(SignedInActivity.this)); + startActivity(AuthUiActivity.createIntent(SignedInActivity.this, false)); finish(); } else { showSnackbar(R.string.delete_account_failed); @@ -230,6 +245,16 @@ private void populateIdpToken() { } } + private void populatePrevUid() { + String prevUid = mIdpResponse == null ? null : mIdpResponse.getPrevUid(); + + if (prevUid == null) { + findViewById(R.id.prev_uid_layout).setVisibility(View.GONE); + } else { + ((TextView) findViewById(R.id.prev_uid)).setText(prevUid); + } + } + @MainThread private void showSnackbar(@StringRes int errorMessageRes) { Snackbar.make(mRootView, errorMessageRes, Snackbar.LENGTH_LONG).show(); diff --git a/app/src/main/java/com/firebase/uidemo/database/ChatIndexActivity.java b/app/src/main/java/com/firebase/uidemo/database/ChatIndexActivity.java index dbe9a68d6..e2e4f7671 100644 --- a/app/src/main/java/com/firebase/uidemo/database/ChatIndexActivity.java +++ b/app/src/main/java/com/firebase/uidemo/database/ChatIndexActivity.java @@ -1,6 +1,5 @@ package com.firebase.uidemo.database; -import android.os.Bundle; import android.view.View; import com.firebase.ui.database.FirebaseIndexRecyclerAdapter; @@ -13,12 +12,6 @@ public class ChatIndexActivity extends ChatActivity { private DatabaseReference mChatIndicesRef; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mChatIndicesRef = FirebaseDatabase.getInstance().getReference().child("chatIndices"); - } - @Override public void onClick(View v) { String uid = FirebaseAuth.getInstance().getCurrentUser().getUid(); @@ -34,6 +27,11 @@ public void onClick(View v) { @Override protected FirebaseRecyclerAdapter getAdapter() { + mChatIndicesRef = FirebaseDatabase.getInstance() + .getReference() + .child("chatIndices") + .child(FirebaseAuth.getInstance().getCurrentUser().getUid()); + return new FirebaseIndexRecyclerAdapter( Chat.class, R.layout.message, diff --git a/app/src/main/res/layout/signed_in_layout.xml b/app/src/main/res/layout/signed_in_layout.xml index 37e53875c..4be458891 100644 --- a/app/src/main/res/layout/signed_in_layout.xml +++ b/app/src/main/res/layout/signed_in_layout.xml @@ -38,21 +38,30 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_margin="16dp" + android:layout_margin="8dp" android:text="@string/sign_out" />