Skip to content

Commit 44a4f27

Browse files
SUPERCILEXsamtstern
authored andcommitted
Differentiate between user cancellation and actual errors (#426)
1 parent ac1fb39 commit 44a4f27

24 files changed

+248
-130
lines changed

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

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@
3333

3434
import com.firebase.ui.auth.AuthUI;
3535
import com.firebase.ui.auth.AuthUI.IdpConfig;
36+
import com.firebase.ui.auth.ErrorCodes;
3637
import com.firebase.ui.auth.IdpResponse;
37-
import com.firebase.ui.auth.ui.ResultCodes;
38+
import com.firebase.ui.auth.ResultCodes;
3839
import com.firebase.uidemo.R;
3940
import com.google.android.gms.common.Scopes;
4041
import com.google.firebase.auth.FirebaseAuth;
@@ -199,20 +200,30 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
199200

200201
@MainThread
201202
private void handleSignInResponse(int resultCode, Intent data) {
202-
if (resultCode == RESULT_OK) {
203-
startActivity(SignedInActivity.createIntent(this, IdpResponse.fromResultIntent(data)));
204-
finish();
205-
return;
206-
}
207-
208-
if (resultCode == RESULT_CANCELED) {
209-
showSnackbar(R.string.sign_in_cancelled);
210-
return;
211-
}
203+
IdpResponse response = IdpResponse.fromResultIntent(data);
212204

213-
if (resultCode == ResultCodes.RESULT_NO_NETWORK) {
214-
showSnackbar(R.string.no_internet_connection);
205+
// Successfully signed in
206+
if (resultCode == ResultCodes.OK) {
207+
startActivity(SignedInActivity.createIntent(this, response));
208+
finish();
215209
return;
210+
} else {
211+
// Sign in failed
212+
if (response == null) {
213+
// User pressed back button
214+
showSnackbar(R.string.sign_in_cancelled);
215+
return;
216+
}
217+
218+
if (response.getErrorCode() == ErrorCodes.NO_NETWORK) {
219+
showSnackbar(R.string.no_internet_connection);
220+
return;
221+
}
222+
223+
if (response.getErrorCode() == ErrorCodes.UNKNOWN_ERROR) {
224+
showSnackbar(R.string.unknown_error);
225+
return;
226+
}
216227
}
217228

218229
showSnackbar(R.string.unknown_sign_in_response);

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public class SignedInActivity extends AppCompatActivity {
6565
@BindView(R.id.user_enabled_providers)
6666
TextView mEnabledProviders;
6767

68+
private IdpResponse mIdpResponse;
69+
6870
@Override
6971
public void onCreate(Bundle savedInstanceState) {
7072
super.onCreate(savedInstanceState);
@@ -76,6 +78,8 @@ public void onCreate(Bundle savedInstanceState) {
7678
return;
7779
}
7880

81+
mIdpResponse = getIntent().getParcelableExtra(EXTRA_IDP_RESPONSE);
82+
7983
setContentView(R.layout.signed_in_layout);
8084
ButterKnife.bind(this);
8185
populateProfile();
@@ -177,10 +181,9 @@ private void populateProfile() {
177181
}
178182

179183
private void populateIdpToken() {
180-
IdpResponse idpResponse = getIntent().getParcelableExtra(EXTRA_IDP_RESPONSE);
181-
if (idpResponse != null) {
182-
String token = idpResponse.getIdpToken();
183-
String secret = idpResponse.getIdpSecret();
184+
if (mIdpResponse != null) {
185+
String token = mIdpResponse.getIdpToken();
186+
String secret = mIdpResponse.getIdpSecret();
184187
if (token == null) {
185188
findViewById(R.id.idp_token_layout).setVisibility(View.GONE);
186189
} else {

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
<string name="photos">Photos</string>
5858
<string name="idp_token">IDP Token</string>
5959
<string name="idp_secret">IDP Secret</string>
60+
<string name="unknown_error">An unknown error occurred</string>
6061
<string name="send">Send</string>
6162
<string name="download">Download</string>
6263
<string name="upload">Upload</string>

auth/README.md

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -216,42 +216,47 @@ startActivityForResult(
216216
#### Handling the sign-in response
217217

218218
#####Response codes
219-
The authentication flow only provides three response codes:
220-
`Activity.RESULT_OK` if a user is signed in, `Activity.RESULT_CANCELLED` if
221-
sign in failed, and `ResultCodes.RESULT_NO_NETWORK` if sign in failed due to a lack of network connectivity.
222-
No further information on failure is provided as it is not
223-
typically useful; the only recourse for most apps if sign in fails is to ask
224-
the user to sign in again later, or proceed with anonymous sign-in if
225-
supported.
219+
The authentication flow provides several response codes of which the most common are as follows:
220+
`ResultCodes.OK` if a user is signed in, `ResultCodes.CANCELLED` if the user manually canceled the sign in,
221+
`ResultCodes.NO_NETWORK` if sign in failed due to a lack of network connectivity,
222+
and `ResultCodes.UNKNOWN_ERROR` for all other errors.
223+
Typically, the only recourse for most apps if sign in fails is to ask
224+
the user to sign in again later, or proceed with anonymous sign-in if supported.
226225

227226
```java
228227
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
229228
super.onActivityResult(requestCode, resultCode, data);
230-
// RC_SIGN_IN is the request code you passed into startActivityForResult(...) when starting the sign in flow
229+
// RC_SIGN_IN is the request code you passed into startActivityForResult(...) when starting the sign in flow.
231230
if (requestCode == RC_SIGN_IN) {
232-
if (resultCode == RESULT_OK) {
233-
// user is signed in!
234-
startActivity(new Intent(this, WelcomeBackActivity.class));
231+
IdpResponse response = IdpResponse.fromResultIntent(data);
232+
233+
// Successfully signed in
234+
if (resultCode == ResultCodes.OK) {
235+
startActivity(SignedInActivity.createIntent(this, response));
235236
finish();
236237
return;
237-
}
238+
} else {
239+
// Sign in failed
240+
if (response == null) {
241+
// User pressed back button
242+
showSnackbar(R.string.sign_in_cancelled);
243+
return;
244+
}
238245

239-
// Sign in canceled
240-
if (resultCode == RESULT_CANCELED) {
241-
showSnackbar(R.string.sign_in_cancelled);
242-
return;
243-
}
246+
if (response.getErrorCode() == ErrorCodes.NO_NETWORK) {
247+
showSnackbar(R.string.no_internet_connection);
248+
return;
249+
}
244250

245-
// No network
246-
if (resultCode == ResultCodes.RESULT_NO_NETWORK) {
247-
showSnackbar(R.string.no_internet_connection);
248-
return;
251+
if (response.getErrorCode() == ErrorCodes.UNKNOWN_ERROR) {
252+
showSnackbar(R.string.unknown_error);
253+
return;
254+
}
249255
}
250256

251-
// User is not signed in. Maybe just wait for the user to press
252-
// "sign in" again, or show a message.
257+
showSnackbar(R.string.unknown_sign_in_response);
253258
}
254-
}
259+
}
255260
```
256261

257262
Alternatively, you can register a listener for authentication state changes;
@@ -266,7 +271,7 @@ Intent.
266271
```java
267272
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
268273
super.onActivityResult(requestCode, resultCode, data);
269-
if (resultCode == RESULT_OK) {
274+
if (resultCode == ResultCodes.OK) {
270275
IdpResponse idpResponse = IdpResponse.fromResultIntent(data);
271276
startActivity(new Intent(this, WelcomeBackActivity.class)
272277
.putExtra("my_token", idpResponse.getIdpToken()));

auth/src/main/java/com/firebase/ui/auth/AuthUI.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@
137137
*
138138
* <h3>Handling the Sign-in response</h3>
139139
*
140-
* The authentication flow provides only two response codes: {@link Activity#RESULT_OK RESULT_OK}
141-
* if a user is signed in, and {@link Activity#RESULT_CANCELED RESULT_CANCELLED} if sign in
140+
* The authentication flow provides only two response codes:
141+
* {@link ResultCodes#OK RESULT_OK} if a user is signed in,
142+
* and {@link ResultCodes#CANCELED RESULT_CANCELLED} if sign in
142143
* failed. No further information on failure is provided as it is not typically useful; the only
143144
* recourse for most apps if sign in fails is to ask the user to sign in again later, or proceed
144145
* with an anonymous account if supported.
@@ -149,7 +150,7 @@
149150
* protected void onActivityResult(int requestCode, int resultCode, Intent data) {
150151
* super.onActivityResult(requestCode, resultCode, data);
151152
* if (requestCode == RC_SIGN_IN) {
152-
* if (resultCode == RESULT_OK) {
153+
* if (resultCode == ResultCodes.OK) {
153154
* // user is signed in!
154155
* startActivity(new Intent(this, WelcomeBackActivity.class));
155156
* finish();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.firebase.ui.auth;
2+
3+
/**
4+
* Error codes retrieved from {@link IdpResponse#getErrorCode()}.
5+
*/
6+
public final class ErrorCodes {
7+
private ErrorCodes() {
8+
// We don't want people to initialize this class
9+
}
10+
11+
/**
12+
* Sign in failed due to lack of network connection
13+
**/
14+
public static final int NO_NETWORK = 10;
15+
16+
/**
17+
* An unknown error has occurred
18+
**/
19+
public static final int UNKNOWN_ERROR = 20;
20+
}

auth/src/main/java/com/firebase/ui/auth/IdpResponse.java

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,21 @@
2727
public class IdpResponse implements Parcelable {
2828

2929
private final String mProviderId;
30-
@Nullable private final String mEmail;
30+
@Nullable
31+
private final String mEmail;
3132
private final String mToken;
3233
private final String mSecret;
34+
private final int mErrorCode;
35+
36+
public IdpResponse(int errorCode) {
37+
this(null, null, null, null, errorCode);
38+
}
3339

34-
public IdpResponse(String providerId, @Nullable String email) {
40+
public IdpResponse(String providerId, String email) {
3541
this(providerId, email, null, null);
3642
}
3743

38-
public IdpResponse(
39-
String providerId, @Nullable String email, @Nullable String token) {
44+
public IdpResponse(String providerId, @Nullable String email, @Nullable String token) {
4045
this(providerId, email, token, null);
4146
}
4247

@@ -45,10 +50,20 @@ public IdpResponse(
4550
@Nullable String email,
4651
@Nullable String token,
4752
@Nullable String secret) {
53+
this(providerId, email, token, secret, ResultCodes.OK);
54+
}
55+
56+
public IdpResponse(
57+
String providerId,
58+
@Nullable String email,
59+
@Nullable String token,
60+
@Nullable String secret,
61+
int errorCode) {
4862
mProviderId = providerId;
4963
mEmail = email;
5064
mToken = token;
5165
mSecret = secret;
66+
mErrorCode = errorCode;
5267
}
5368

5469
public static final Creator<IdpResponse> CREATOR = new Creator<IdpResponse>() {
@@ -58,7 +73,8 @@ public IdpResponse createFromParcel(Parcel in) {
5873
in.readString(),
5974
in.readString(),
6075
in.readString(),
61-
in.readString()
76+
in.readString(),
77+
in.readInt()
6278
);
6379
}
6480

@@ -71,6 +87,7 @@ public IdpResponse[] newArray(int size) {
7187
/**
7288
* Get the type of provider. e.g. {@link AuthUI#GOOGLE_PROVIDER}
7389
*/
90+
@Nullable
7491
public String getProviderType() {
7592
return mProviderId;
7693
}
@@ -99,6 +116,13 @@ public String getEmail() {
99116
return mEmail;
100117
}
101118

119+
/**
120+
* Get the error code for a failed sign in
121+
*/
122+
public int getErrorCode() {
123+
return mErrorCode;
124+
}
125+
102126
@Override
103127
public int describeContents() {
104128
return 0;
@@ -110,6 +134,7 @@ public void writeToParcel(Parcel dest, int flags) {
110134
dest.writeString(mEmail);
111135
dest.writeString(mToken);
112136
dest.writeString(mSecret);
137+
dest.writeInt(mErrorCode);
113138
}
114139

115140
/**
@@ -120,6 +145,18 @@ public void writeToParcel(Parcel dest, int flags) {
120145
*/
121146
@Nullable
122147
public static IdpResponse fromResultIntent(Intent resultIntent) {
123-
return resultIntent.getParcelableExtra(ExtraConstants.EXTRA_IDP_RESPONSE);
148+
if (resultIntent != null) {
149+
return resultIntent.getParcelableExtra(ExtraConstants.EXTRA_IDP_RESPONSE);
150+
} else {
151+
return null;
152+
}
153+
}
154+
155+
public static Intent getIntent(IdpResponse response) {
156+
return new Intent().putExtra(ExtraConstants.EXTRA_IDP_RESPONSE, response);
157+
}
158+
159+
public static Intent getErrorCodeIntent(int errorCode) {
160+
return new Intent().putExtra(ExtraConstants.EXTRA_IDP_RESPONSE, new IdpResponse(errorCode));
124161
}
125162
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.firebase.ui.auth;
2+
3+
import android.app.Activity;
4+
5+
/**
6+
* Result codes returned when using {@link AuthUI.SignInIntentBuilder#build()} with
7+
* {@code startActivityForResult}.
8+
*/
9+
public final class ResultCodes {
10+
private ResultCodes() {
11+
// We don't want people to initialize this class
12+
}
13+
14+
/**
15+
* Sign in succeeded
16+
**/
17+
public static final int OK = Activity.RESULT_OK;
18+
19+
/**
20+
* Sign in canceled by user
21+
**/
22+
public static final int CANCELED = Activity.RESULT_CANCELED;
23+
}

auth/src/main/java/com/firebase/ui/auth/ui/ActivityHelper.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import android.support.annotation.NonNull;
1919
import android.support.annotation.Nullable;
2020

21+
import com.firebase.ui.auth.IdpResponse;
2122
import com.firebase.ui.auth.util.signincontainer.SaveSmartLock;
2223
import com.google.firebase.auth.FirebaseUser;
2324

@@ -48,7 +49,8 @@ public SaveSmartLock getSaveSmartLockInstance() {
4849
public void saveCredentialsOrFinish(
4950
@Nullable SaveSmartLock saveSmartLock,
5051
FirebaseUser firebaseUser,
51-
@NonNull String password) {
52-
saveCredentialsOrFinish(saveSmartLock, mActivity, firebaseUser, password, null);
52+
@NonNull String password,
53+
IdpResponse response) {
54+
saveCredentialsOrFinish(saveSmartLock, mActivity, firebaseUser, password, response);
5355
}
5456
}

auth/src/main/java/com/firebase/ui/auth/ui/BaseHelper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
import android.support.v4.app.FragmentActivity;
1111

1212
import com.firebase.ui.auth.IdpResponse;
13+
import com.firebase.ui.auth.ResultCodes;
1314
import com.firebase.ui.auth.util.signincontainer.SaveSmartLock;
1415
import com.google.android.gms.auth.api.Auth;
1516
import com.google.android.gms.auth.api.credentials.CredentialsApi;
1617
import com.google.firebase.FirebaseApp;
1718
import com.google.firebase.auth.FirebaseAuth;
1819
import com.google.firebase.auth.FirebaseUser;
1920

20-
import static android.app.Activity.RESULT_OK;
2121
import static com.firebase.ui.auth.util.Preconditions.checkNotNull;
2222

2323
public class BaseHelper {
@@ -111,9 +111,9 @@ public void saveCredentialsOrFinish(
111111
Activity activity,
112112
FirebaseUser firebaseUser,
113113
@Nullable String password,
114-
@Nullable IdpResponse response) {
114+
IdpResponse response) {
115115
if (saveSmartLock == null) {
116-
finishActivity(activity, RESULT_OK, new Intent());
116+
finishActivity(activity, ResultCodes.OK, new Intent());
117117
} else {
118118
saveSmartLock.saveCredentialsOrFinish(
119119
firebaseUser,

0 commit comments

Comments
 (0)