diff --git a/app/src/main/java/com/firebase/uidemo/ChooserActivity.java b/app/src/main/java/com/firebase/uidemo/ChooserActivity.java index 612fe4ab9..158a2ebe7 100644 --- a/app/src/main/java/com/firebase/uidemo/ChooserActivity.java +++ b/app/src/main/java/com/firebase/uidemo/ChooserActivity.java @@ -26,6 +26,8 @@ import android.view.ViewGroup; import android.widget.TextView; +import com.firebase.ui.auth.AuthUI; +import com.firebase.ui.auth.util.ExtraConstants; import com.firebase.uidemo.auth.AnonymousUpgradeActivity; import com.firebase.uidemo.auth.AuthUiActivity; import com.firebase.uidemo.database.firestore.FirestoreChatActivity; @@ -43,6 +45,16 @@ public class ChooserActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + if (AuthUI.canHandleIntent(getIntent())) { + Intent intent = new Intent(ChooserActivity.this, AuthUiActivity + .class); + intent.putExtra(ExtraConstants.EMAIL_LINK_SIGN_IN, getIntent().getData().toString()); + startActivity(intent); + finish(); + return; + } + setContentView(R.layout.activity_chooser); ButterKnife.bind(this); @@ -51,7 +63,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { mActivities.setHasFixedSize(true); } - private static class ActivityChooserAdapter extends RecyclerView.Adapter { + private static class ActivityChooserAdapter + extends RecyclerView.Adapter { private static final Class[] CLASSES = new Class[]{ AuthUiActivity.class, AnonymousUpgradeActivity.class, @@ -97,7 +110,8 @@ public int getItemCount() { } } - private static class ActivityStarterHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private static class ActivityStarterHolder extends RecyclerView.ViewHolder + implements View.OnClickListener { private TextView mTitle; private TextView mDescription; diff --git a/app/src/main/java/com/firebase/uidemo/auth/AnonymousUpgradeActivity.java b/app/src/main/java/com/firebase/uidemo/auth/AnonymousUpgradeActivity.java index db106193d..89ca92387 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/AnonymousUpgradeActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/AnonymousUpgradeActivity.java @@ -57,6 +57,16 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_anonymous_upgrade); ButterKnife.bind(this); + + updateUI(); + + // Got here from AuthUIActivity, and we need to deal with a merge conflict + // Occurs after catching an email link + IdpResponse response = IdpResponse.fromResultIntent(getIntent()); + if (response != null) { + handleSignInResult(RC_SIGN_IN, ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, + getIntent()); + } } @OnClick(R.id.anon_sign_in) @@ -81,10 +91,10 @@ public void onComplete(@NonNull Task task) { public void startAuthUI() { List providers = ConfigurationUtils.getConfiguredProviders(this); Intent intent = AuthUI.getInstance().createSignInIntentBuilder() - .setLogo(R.drawable.firebase_auth_120dp) - .setAvailableProviders(providers) - .enableAnonymousUsersAutoUpgrade() - .build(); + .setLogo(R.drawable.firebase_auth_120dp) + .setAvailableProviders(providers) + .enableAnonymousUsersAutoUpgrade() + .build(); startActivityForResult(intent, RC_SIGN_IN); } @@ -105,7 +115,8 @@ public void onComplete(@NonNull Task task) { updateUI(); if (task.isSuccessful()) { - setStatus("Signed in as " + getUserIdentifier(task.getResult().getUser())); + setStatus("Signed in as " + getUserIdentifier(task.getResult() + .getUser())); } else { Log.w(TAG, "Merge failed", task.getException()); setStatus("Failed to resolve merge conflict, see logs."); @@ -129,6 +140,10 @@ public void onComplete(@NonNull Task task) { @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); + handleSignInResult(requestCode, resultCode, data); + } + + private void handleSignInResult(int requestCode, int resultCode, Intent data) { if (requestCode == RC_SIGN_IN) { IdpResponse response = IdpResponse.fromResultIntent(data); if (response == null) { @@ -136,8 +151,10 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten return; } if (resultCode == RESULT_OK) { - setStatus("Signed in as " + getUserIdentifier(FirebaseAuth.getInstance().getCurrentUser())); - } else if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { + 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(); 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 a6efd38f6..668a11b0e 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java @@ -37,11 +37,13 @@ import com.firebase.ui.auth.AuthUI.IdpConfig; import com.firebase.ui.auth.ErrorCodes; import com.firebase.ui.auth.IdpResponse; +import com.firebase.ui.auth.util.ExtraConstants; import com.firebase.uidemo.R; import com.firebase.uidemo.util.ConfigurationUtils; import com.google.android.gms.common.Scopes; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.ActionCodeSettings; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; @@ -57,8 +59,10 @@ public class AuthUiActivity extends AppCompatActivity { private static final String GOOGLE_TOS_URL = "https://www.google.com/policies/terms/"; private static final String FIREBASE_TOS_URL = "https://firebase.google.com/terms/"; - private static final String GOOGLE_PRIVACY_POLICY_URL = "https://www.google.com/policies/privacy/"; - private static final String FIREBASE_PRIVACY_POLICY_URL = "https://firebase.google.com/terms/analytics/#7_privacy"; + private static final String GOOGLE_PRIVACY_POLICY_URL = "https://www.google" + + ".com/policies/privacy/"; + private static final String FIREBASE_PRIVACY_POLICY_URL = "https://firebase.google" + + ".com/terms/analytics/#7_privacy"; private static final int RC_SIGN_IN = 100; @@ -69,6 +73,7 @@ public class AuthUiActivity extends AppCompatActivity { @BindView(R.id.twitter_provider) CheckBox mUseTwitterProvider; @BindView(R.id.github_provider) CheckBox mUseGitHubProvider; @BindView(R.id.email_provider) CheckBox mUseEmailProvider; + @BindView(R.id.email_link_provider) CheckBox mUseEmailLinkProvider; @BindView(R.id.phone_provider) CheckBox mUsePhoneProvider; @BindView(R.id.anonymous_provider) CheckBox mUseAnonymousProvider; @@ -163,6 +168,23 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { }); } + mUseEmailLinkProvider.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + flipPasswordProviderCheckbox(isChecked); + } + }); + + mUseEmailProvider.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + flipEmailLinkProviderCheckbox(isChecked); + } + }); + + mUseEmailLinkProvider.setChecked(false); + mUseEmailProvider.setChecked(true); + if (ConfigurationUtils.isGoogleMisconfigured(this) || ConfigurationUtils.isFacebookMisconfigured(this) || ConfigurationUtils.isTwitterMisconfigured(this) @@ -173,11 +195,44 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) { mDarkTheme.setChecked(true); } + + catchEmailLinkSignIn(); + } + + public void catchEmailLinkSignIn() { + if (getIntent().getExtras() == null) { + return; + } + String link = getIntent().getExtras().getString(ExtraConstants.EMAIL_LINK_SIGN_IN); + if (link != null) { + signInWithEmailLink(link); + } + } + + public void flipPasswordProviderCheckbox(boolean emailLinkProviderIsChecked) { + if (emailLinkProviderIsChecked) { + mUseEmailProvider.setChecked(false); + } + } + + public void flipEmailLinkProviderCheckbox(boolean passwordProviderIsChecked) { + if (passwordProviderIsChecked) { + mUseEmailLinkProvider.setChecked(false); + } } @OnClick(R.id.sign_in) public void signIn() { - AuthUI.SignInIntentBuilder builder = AuthUI.getInstance().createSignInIntentBuilder() + startActivityForResult(buildSignInIntent(/*link=*/null), RC_SIGN_IN); + } + + public void signInWithEmailLink(@Nullable String link) { + startActivityForResult(buildSignInIntent(link), RC_SIGN_IN); + } + + @NonNull + public Intent buildSignInIntent(@Nullable String link) { + AuthUI.SignInIntentBuilder builder = AuthUI.getInstance().createSignInIntentBuilder() .setTheme(getSelectedTheme()) .setLogo(getSelectedLogo()) .setAvailableProviders(getSelectedProviders()) @@ -190,7 +245,17 @@ public void signIn() { getSelectedPrivacyPolicyUrl()); } - startActivityForResult(builder.build(), RC_SIGN_IN); + if (link != null) { + builder.setEmailLink(link); + } + + FirebaseAuth auth = FirebaseAuth.getInstance(); + + if (auth.getCurrentUser() != null && auth.getCurrentUser().isAnonymous()) { + builder.enableAnonymousUsersAutoUpgrade(); + } + + return builder.build(); } @OnClick(R.id.sign_in_silent) @@ -220,7 +285,7 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten protected void onResume() { super.onResume(); FirebaseAuth auth = FirebaseAuth.getInstance(); - if (auth.getCurrentUser() != null) { + if (auth.getCurrentUser() != null && getIntent().getExtras() == null) { startSignedInActivity(null); finish(); } @@ -246,6 +311,12 @@ private void handleSignInResponse(int resultCode, @Nullable Intent data) { return; } + if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) { + Intent intent = new Intent(this, AnonymousUpgradeActivity.class).putExtra + (ExtraConstants.IDP_RESPONSE, response); + startActivity(intent); + } + showSnackbar(R.string.unknown_error); Log.e(TAG, "Sign-in error: ", response.getError()); } @@ -317,6 +388,20 @@ private List getSelectedProviders() { .build()); } + if (mUseEmailLinkProvider.isChecked()) { + ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder() + .setAndroidPackageName("com.firebase.uidemo", true, null) + .setHandleCodeInApp(true) + .setUrl("https://google.com") + .build(); + + selectedProviders.add(new IdpConfig.EmailBuilder() + .setAllowNewAccounts(mAllowNewEmailAccounts.isChecked()) + .setActionCodeSettings(actionCodeSettings) + .enableEmailLinkSignIn() + .build()); + } + if (mUsePhoneProvider.isChecked()) { selectedProviders.add(new IdpConfig.PhoneBuilder().build()); } 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 e0215891e..cd59b1a9e 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java @@ -55,6 +55,8 @@ import butterknife.ButterKnife; import butterknife.OnClick; +import static com.firebase.ui.auth.AuthUI.EMAIL_LINK_PROVIDER; + public class SignedInActivity extends AppCompatActivity { private static final String TAG = "SignedInActivity"; @@ -187,6 +189,9 @@ private void populateProfile(@Nullable IdpResponse response) { case PhoneAuthProvider.PROVIDER_ID: providers.add(getString(R.string.providers_phone)); break; + case EMAIL_LINK_PROVIDER: + providers.add(getString(R.string.providers_email_link)); + break; case FirebaseAuthProvider.PROVIDER_ID: // Ignore this provider, it's not very meaningful break; diff --git a/app/src/main/java/com/firebase/uidemo/util/ConfigurationUtils.java b/app/src/main/java/com/firebase/uidemo/util/ConfigurationUtils.java index 63809340e..04049ff1d 100644 --- a/app/src/main/java/com/firebase/uidemo/util/ConfigurationUtils.java +++ b/app/src/main/java/com/firebase/uidemo/util/ConfigurationUtils.java @@ -6,6 +6,7 @@ import com.firebase.ui.auth.AuthUI; import com.firebase.uidemo.R; +import com.google.firebase.auth.ActionCodeSettings; import java.util.ArrayList; import java.util.Arrays; @@ -49,8 +50,6 @@ public static boolean isGitHubMisconfigured(@NonNull Context context) { @NonNull public static List getConfiguredProviders(@NonNull Context context) { List providers = new ArrayList<>(); - providers.add(new AuthUI.IdpConfig.EmailBuilder().build()); - providers.add(new AuthUI.IdpConfig.PhoneBuilder().build()); if (!isGoogleMisconfigured(context)) { providers.add(new AuthUI.IdpConfig.GoogleBuilder().build()); @@ -68,6 +67,22 @@ public static List getConfiguredProviders(@NonNull Context con providers.add(new AuthUI.IdpConfig.GitHubBuilder().build()); } + ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder() + .setAndroidPackageName("com.firebase.uidemo", true, null) + .setHandleCodeInApp(true) + .setUrl("https://google.com") + .build(); + + providers.add(new AuthUI.IdpConfig.EmailBuilder() + .setAllowNewAccounts(true) + .enableEmailLinkSignIn() + .setActionCodeSettings(actionCodeSettings) + .build()); + + + providers.add(new AuthUI.IdpConfig.PhoneBuilder().build()); + + return providers; } } diff --git a/app/src/main/res/layout/auth_ui_layout.xml b/app/src/main/res/layout/auth_ui_layout.xml index 6f99974a0..7edc9f76f 100644 --- a/app/src/main/res/layout/auth_ui_layout.xml +++ b/app/src/main/res/layout/auth_ui_layout.xml @@ -1,6 +1,5 @@ - + android:orientation="vertical" + android:paddingBottom="32dp">