Skip to content

Commit 150f1fa

Browse files
lsiracsamtstern
authored andcommitted
Email link sign in (Phase 1) (#1486)
1 parent abd722b commit 150f1fa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2765
-258
lines changed

app/src/main/java/com/firebase/uidemo/ChooserActivity.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import android.view.ViewGroup;
2727
import android.widget.TextView;
2828

29+
import com.firebase.ui.auth.AuthUI;
30+
import com.firebase.ui.auth.util.ExtraConstants;
2931
import com.firebase.uidemo.auth.AnonymousUpgradeActivity;
3032
import com.firebase.uidemo.auth.AuthUiActivity;
3133
import com.firebase.uidemo.database.firestore.FirestoreChatActivity;
@@ -43,6 +45,16 @@ public class ChooserActivity extends AppCompatActivity {
4345
@Override
4446
protected void onCreate(@Nullable Bundle savedInstanceState) {
4547
super.onCreate(savedInstanceState);
48+
49+
if (AuthUI.canHandleIntent(getIntent())) {
50+
Intent intent = new Intent(ChooserActivity.this, AuthUiActivity
51+
.class);
52+
intent.putExtra(ExtraConstants.EMAIL_LINK_SIGN_IN, getIntent().getData().toString());
53+
startActivity(intent);
54+
finish();
55+
return;
56+
}
57+
4658
setContentView(R.layout.activity_chooser);
4759
ButterKnife.bind(this);
4860

@@ -51,7 +63,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5163
mActivities.setHasFixedSize(true);
5264
}
5365

54-
private static class ActivityChooserAdapter extends RecyclerView.Adapter<ActivityStarterHolder> {
66+
private static class ActivityChooserAdapter
67+
extends RecyclerView.Adapter<ActivityStarterHolder> {
5568
private static final Class[] CLASSES = new Class[]{
5669
AuthUiActivity.class,
5770
AnonymousUpgradeActivity.class,
@@ -97,7 +110,8 @@ public int getItemCount() {
97110
}
98111
}
99112

100-
private static class ActivityStarterHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
113+
private static class ActivityStarterHolder extends RecyclerView.ViewHolder
114+
implements View.OnClickListener {
101115
private TextView mTitle;
102116
private TextView mDescription;
103117

app/src/main/java/com/firebase/uidemo/auth/AnonymousUpgradeActivity.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5757
super.onCreate(savedInstanceState);
5858
setContentView(R.layout.activity_anonymous_upgrade);
5959
ButterKnife.bind(this);
60+
61+
updateUI();
62+
63+
// Got here from AuthUIActivity, and we need to deal with a merge conflict
64+
// Occurs after catching an email link
65+
IdpResponse response = IdpResponse.fromResultIntent(getIntent());
66+
if (response != null) {
67+
handleSignInResult(RC_SIGN_IN, ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT,
68+
getIntent());
69+
}
6070
}
6171

6272
@OnClick(R.id.anon_sign_in)
@@ -81,10 +91,10 @@ public void onComplete(@NonNull Task<AuthResult> task) {
8191
public void startAuthUI() {
8292
List<AuthUI.IdpConfig> providers = ConfigurationUtils.getConfiguredProviders(this);
8393
Intent intent = AuthUI.getInstance().createSignInIntentBuilder()
84-
.setLogo(R.drawable.firebase_auth_120dp)
85-
.setAvailableProviders(providers)
86-
.enableAnonymousUsersAutoUpgrade()
87-
.build();
94+
.setLogo(R.drawable.firebase_auth_120dp)
95+
.setAvailableProviders(providers)
96+
.enableAnonymousUsersAutoUpgrade()
97+
.build();
8898
startActivityForResult(intent, RC_SIGN_IN);
8999
}
90100

@@ -105,7 +115,8 @@ public void onComplete(@NonNull Task<AuthResult> task) {
105115
updateUI();
106116

107117
if (task.isSuccessful()) {
108-
setStatus("Signed in as " + getUserIdentifier(task.getResult().getUser()));
118+
setStatus("Signed in as " + getUserIdentifier(task.getResult()
119+
.getUser()));
109120
} else {
110121
Log.w(TAG, "Merge failed", task.getException());
111122
setStatus("Failed to resolve merge conflict, see logs.");
@@ -129,15 +140,21 @@ public void onComplete(@NonNull Task<Void> task) {
129140
@Override
130141
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
131142
super.onActivityResult(requestCode, resultCode, data);
143+
handleSignInResult(requestCode, resultCode, data);
144+
}
145+
146+
private void handleSignInResult(int requestCode, int resultCode, Intent data) {
132147
if (requestCode == RC_SIGN_IN) {
133148
IdpResponse response = IdpResponse.fromResultIntent(data);
134149
if (response == null) {
135150
// User pressed back button
136151
return;
137152
}
138153
if (resultCode == RESULT_OK) {
139-
setStatus("Signed in as " + getUserIdentifier(FirebaseAuth.getInstance().getCurrentUser()));
140-
} else if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
154+
setStatus("Signed in as " + getUserIdentifier(FirebaseAuth.getInstance()
155+
.getCurrentUser()));
156+
} else if (response.getError().getErrorCode() == ErrorCodes
157+
.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
141158
setStatus("Merge conflict: user already exists.");
142159
mResolveMergeButton.setEnabled(true);
143160
mPendingCredential = response.getCredentialForLinking();

app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@
3737
import com.firebase.ui.auth.AuthUI.IdpConfig;
3838
import com.firebase.ui.auth.ErrorCodes;
3939
import com.firebase.ui.auth.IdpResponse;
40+
import com.firebase.ui.auth.util.ExtraConstants;
4041
import com.firebase.uidemo.R;
4142
import com.firebase.uidemo.util.ConfigurationUtils;
4243
import com.google.android.gms.common.Scopes;
4344
import com.google.android.gms.tasks.OnCompleteListener;
4445
import com.google.android.gms.tasks.Task;
46+
import com.google.firebase.auth.ActionCodeSettings;
4547
import com.google.firebase.auth.AuthResult;
4648
import com.google.firebase.auth.FirebaseAuth;
4749

@@ -57,8 +59,10 @@ public class AuthUiActivity extends AppCompatActivity {
5759

5860
private static final String GOOGLE_TOS_URL = "https://www.google.com/policies/terms/";
5961
private static final String FIREBASE_TOS_URL = "https://firebase.google.com/terms/";
60-
private static final String GOOGLE_PRIVACY_POLICY_URL = "https://www.google.com/policies/privacy/";
61-
private static final String FIREBASE_PRIVACY_POLICY_URL = "https://firebase.google.com/terms/analytics/#7_privacy";
62+
private static final String GOOGLE_PRIVACY_POLICY_URL = "https://www.google" +
63+
".com/policies/privacy/";
64+
private static final String FIREBASE_PRIVACY_POLICY_URL = "https://firebase.google" +
65+
".com/terms/analytics/#7_privacy";
6266

6367
private static final int RC_SIGN_IN = 100;
6468

@@ -69,6 +73,7 @@ public class AuthUiActivity extends AppCompatActivity {
6973
@BindView(R.id.twitter_provider) CheckBox mUseTwitterProvider;
7074
@BindView(R.id.github_provider) CheckBox mUseGitHubProvider;
7175
@BindView(R.id.email_provider) CheckBox mUseEmailProvider;
76+
@BindView(R.id.email_link_provider) CheckBox mUseEmailLinkProvider;
7277
@BindView(R.id.phone_provider) CheckBox mUsePhoneProvider;
7378
@BindView(R.id.anonymous_provider) CheckBox mUseAnonymousProvider;
7479

@@ -163,6 +168,23 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
163168
});
164169
}
165170

171+
mUseEmailLinkProvider.setOnCheckedChangeListener(new OnCheckedChangeListener() {
172+
@Override
173+
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
174+
flipPasswordProviderCheckbox(isChecked);
175+
}
176+
});
177+
178+
mUseEmailProvider.setOnCheckedChangeListener(new OnCheckedChangeListener() {
179+
@Override
180+
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
181+
flipEmailLinkProviderCheckbox(isChecked);
182+
}
183+
});
184+
185+
mUseEmailLinkProvider.setChecked(false);
186+
mUseEmailProvider.setChecked(true);
187+
166188
if (ConfigurationUtils.isGoogleMisconfigured(this)
167189
|| ConfigurationUtils.isFacebookMisconfigured(this)
168190
|| ConfigurationUtils.isTwitterMisconfigured(this)
@@ -173,11 +195,44 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
173195
if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
174196
mDarkTheme.setChecked(true);
175197
}
198+
199+
catchEmailLinkSignIn();
200+
}
201+
202+
public void catchEmailLinkSignIn() {
203+
if (getIntent().getExtras() == null) {
204+
return;
205+
}
206+
String link = getIntent().getExtras().getString(ExtraConstants.EMAIL_LINK_SIGN_IN);
207+
if (link != null) {
208+
signInWithEmailLink(link);
209+
}
210+
}
211+
212+
public void flipPasswordProviderCheckbox(boolean emailLinkProviderIsChecked) {
213+
if (emailLinkProviderIsChecked) {
214+
mUseEmailProvider.setChecked(false);
215+
}
216+
}
217+
218+
public void flipEmailLinkProviderCheckbox(boolean passwordProviderIsChecked) {
219+
if (passwordProviderIsChecked) {
220+
mUseEmailLinkProvider.setChecked(false);
221+
}
176222
}
177223

178224
@OnClick(R.id.sign_in)
179225
public void signIn() {
180-
AuthUI.SignInIntentBuilder builder = AuthUI.getInstance().createSignInIntentBuilder()
226+
startActivityForResult(buildSignInIntent(/*link=*/null), RC_SIGN_IN);
227+
}
228+
229+
public void signInWithEmailLink(@Nullable String link) {
230+
startActivityForResult(buildSignInIntent(link), RC_SIGN_IN);
231+
}
232+
233+
@NonNull
234+
public Intent buildSignInIntent(@Nullable String link) {
235+
AuthUI.SignInIntentBuilder builder = AuthUI.getInstance().createSignInIntentBuilder()
181236
.setTheme(getSelectedTheme())
182237
.setLogo(getSelectedLogo())
183238
.setAvailableProviders(getSelectedProviders())
@@ -190,7 +245,17 @@ public void signIn() {
190245
getSelectedPrivacyPolicyUrl());
191246
}
192247

193-
startActivityForResult(builder.build(), RC_SIGN_IN);
248+
if (link != null) {
249+
builder.setEmailLink(link);
250+
}
251+
252+
FirebaseAuth auth = FirebaseAuth.getInstance();
253+
254+
if (auth.getCurrentUser() != null && auth.getCurrentUser().isAnonymous()) {
255+
builder.enableAnonymousUsersAutoUpgrade();
256+
}
257+
258+
return builder.build();
194259
}
195260

196261
@OnClick(R.id.sign_in_silent)
@@ -220,7 +285,7 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten
220285
protected void onResume() {
221286
super.onResume();
222287
FirebaseAuth auth = FirebaseAuth.getInstance();
223-
if (auth.getCurrentUser() != null) {
288+
if (auth.getCurrentUser() != null && getIntent().getExtras() == null) {
224289
startSignedInActivity(null);
225290
finish();
226291
}
@@ -246,6 +311,12 @@ private void handleSignInResponse(int resultCode, @Nullable Intent data) {
246311
return;
247312
}
248313

314+
if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
315+
Intent intent = new Intent(this, AnonymousUpgradeActivity.class).putExtra
316+
(ExtraConstants.IDP_RESPONSE, response);
317+
startActivity(intent);
318+
}
319+
249320
showSnackbar(R.string.unknown_error);
250321
Log.e(TAG, "Sign-in error: ", response.getError());
251322
}
@@ -317,6 +388,20 @@ private List<IdpConfig> getSelectedProviders() {
317388
.build());
318389
}
319390

391+
if (mUseEmailLinkProvider.isChecked()) {
392+
ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder()
393+
.setAndroidPackageName("com.firebase.uidemo", true, null)
394+
.setHandleCodeInApp(true)
395+
.setUrl("https://google.com")
396+
.build();
397+
398+
selectedProviders.add(new IdpConfig.EmailBuilder()
399+
.setAllowNewAccounts(mAllowNewEmailAccounts.isChecked())
400+
.setActionCodeSettings(actionCodeSettings)
401+
.enableEmailLinkSignIn()
402+
.build());
403+
}
404+
320405
if (mUsePhoneProvider.isChecked()) {
321406
selectedProviders.add(new IdpConfig.PhoneBuilder().build());
322407
}

app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
import butterknife.ButterKnife;
5656
import butterknife.OnClick;
5757

58+
import static com.firebase.ui.auth.AuthUI.EMAIL_LINK_PROVIDER;
59+
5860
public class SignedInActivity extends AppCompatActivity {
5961
private static final String TAG = "SignedInActivity";
6062

@@ -187,6 +189,9 @@ private void populateProfile(@Nullable IdpResponse response) {
187189
case PhoneAuthProvider.PROVIDER_ID:
188190
providers.add(getString(R.string.providers_phone));
189191
break;
192+
case EMAIL_LINK_PROVIDER:
193+
providers.add(getString(R.string.providers_email_link));
194+
break;
190195
case FirebaseAuthProvider.PROVIDER_ID:
191196
// Ignore this provider, it's not very meaningful
192197
break;

app/src/main/java/com/firebase/uidemo/util/ConfigurationUtils.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import com.firebase.ui.auth.AuthUI;
88
import com.firebase.uidemo.R;
9+
import com.google.firebase.auth.ActionCodeSettings;
910

1011
import java.util.ArrayList;
1112
import java.util.Arrays;
@@ -49,8 +50,6 @@ public static boolean isGitHubMisconfigured(@NonNull Context context) {
4950
@NonNull
5051
public static List<AuthUI.IdpConfig> getConfiguredProviders(@NonNull Context context) {
5152
List<AuthUI.IdpConfig> providers = new ArrayList<>();
52-
providers.add(new AuthUI.IdpConfig.EmailBuilder().build());
53-
providers.add(new AuthUI.IdpConfig.PhoneBuilder().build());
5453

5554
if (!isGoogleMisconfigured(context)) {
5655
providers.add(new AuthUI.IdpConfig.GoogleBuilder().build());
@@ -68,6 +67,22 @@ public static List<AuthUI.IdpConfig> getConfiguredProviders(@NonNull Context con
6867
providers.add(new AuthUI.IdpConfig.GitHubBuilder().build());
6968
}
7069

70+
ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder()
71+
.setAndroidPackageName("com.firebase.uidemo", true, null)
72+
.setHandleCodeInApp(true)
73+
.setUrl("https://google.com")
74+
.build();
75+
76+
providers.add(new AuthUI.IdpConfig.EmailBuilder()
77+
.setAllowNewAccounts(true)
78+
.enableEmailLinkSignIn()
79+
.setActionCodeSettings(actionCodeSettings)
80+
.build());
81+
82+
83+
providers.add(new AuthUI.IdpConfig.PhoneBuilder().build());
84+
85+
7186
return providers;
7287
}
7388
}

app/src/main/res/layout/auth_ui_layout.xml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<android.support.design.widget.CoordinatorLayout
3-
xmlns:android="http://schemas.android.com/apk/res/android"
2+
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
43
xmlns:tools="http://schemas.android.com/tools"
54
android:id="@+id/root"
65
android:layout_width="match_parent"
@@ -15,11 +14,11 @@
1514
android:layout_width="match_parent"
1615
android:layout_height="wrap_content"
1716
android:layout_marginLeft="24dp"
18-
android:layout_marginRight="24dp"
1917
android:layout_marginTop="16dp"
18+
android:layout_marginRight="24dp"
2019
android:layout_marginBottom="16dp"
21-
android:paddingBottom="32dp"
22-
android:orientation="vertical">
20+
android:orientation="vertical"
21+
android:paddingBottom="32dp">
2322

2423
<TextView
2524
style="@style/Base.TextAppearance.AppCompat.Headline"
@@ -34,17 +33,17 @@
3433
style="@style/Widget.AppCompat.Button.Colored"
3534
android:layout_width="wrap_content"
3635
android:layout_height="wrap_content"
37-
android:layout_marginTop="16dp"
3836
android:layout_gravity="center"
37+
android:layout_marginTop="16dp"
3938
android:text="@string/sign_in_start" />
4039

4140
<Button
4241
android:id="@+id/sign_in_silent"
4342
style="@style/Widget.AppCompat.Button.Colored"
4443
android:layout_width="wrap_content"
4544
android:layout_height="wrap_content"
46-
android:layout_marginBottom="16dp"
4745
android:layout_gravity="center"
46+
android:layout_marginBottom="16dp"
4847
android:text="@string/sign_in_silent" />
4948

5049
<TextView
@@ -89,6 +88,13 @@
8988
android:checked="true"
9089
android:text="@string/providers_email" />
9190

91+
<CheckBox
92+
android:id="@+id/email_link_provider"
93+
android:layout_width="wrap_content"
94+
android:layout_height="wrap_content"
95+
android:checked="true"
96+
android:text="@string/providers_email_link" />
97+
9298
<CheckBox
9399
android:id="@+id/phone_provider"
94100
android:layout_width="wrap_content"

0 commit comments

Comments
 (0)