Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.annotation.StyleRes;
Expand All @@ -26,7 +27,6 @@
import android.support.v7.app.AppCompatDelegate;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
Expand All @@ -39,6 +39,9 @@
import com.firebase.ui.auth.IdpResponse;
import com.firebase.uidemo.R;
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.AuthResult;
import com.google.firebase.auth.FirebaseAuth;

import java.util.ArrayList;
Expand All @@ -60,7 +63,6 @@ public class AuthUiActivity extends AppCompatActivity {
private static final int RC_SIGN_IN = 100;

@BindView(R.id.root) View mRootView;
@BindView(R.id.sign_in) Button mSignIn;

@BindView(R.id.google_provider) CheckBox mUseGoogleProvider;
@BindView(R.id.facebook_provider) CheckBox mUseFacebookProvider;
Expand Down Expand Up @@ -166,6 +168,21 @@ public void signIn(View view) {
RC_SIGN_IN);
}

@OnClick(R.id.sign_in_silent)
public void silentSignIn(View view) {
AuthUI.getInstance().silentSignIn(this, getSelectedProviders())
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
startSignedInActivity(null);
} else {
showSnackbar(R.string.sign_in_failed);
}
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/res/layout/auth_ui_layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="16dp"
android:layout_marginTop="16dp"
android:text="@string/sign_in_start" />

<Button
android:id="@+id/sign_in_silent"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="16dp"
android:text="@string/sign_in_silent" />

<TextView
style="@style/Base.TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<!-- Auth UI -->
<string name="launch_title">FirebaseUI Auth Demo</string>
<string name="sign_in_start">Start</string>
<string name="sign_in_silent">Sign in silently</string>

<string name="providers_header">Auth providers</string>
<string name="providers_google">Google</string>
Expand Down Expand Up @@ -72,6 +73,7 @@
<string name="sign_out">Sign out</string>
<string name="delete_account_label">Delete account</string>

<string name="sign_in_failed">Sign in failed</string>
<string name="sign_out_failed">Sign out failed</string>
<string name="delete_account_failed">Delete account failed</string>

Expand Down
41 changes: 38 additions & 3 deletions auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ and [Web](https://github.com/firebase/firebaseui-web/).
1. [Configuration](#configuration)
1. [Provider config](#identity-provider-configuration)
1. [Usage instructions](#using-firebaseui-for-authentication)
1. [Sign in](#sign-in)
1. [AuthUI sign-in](#authui-sign-in)
1. [Handling responses](#handling-the-sign-in-response)
1. [Silent sign-in](#silent-sign-in)
1. [Sign out](#sign-out)
1. [Account deletion](#deleting-accounts)
1. [Auth flow chart](#authentication-flow-chart)
Expand Down Expand Up @@ -169,7 +170,7 @@ If an alternative app instance is required, call
`AuthUI.getInstance(app)` instead, passing the appropriate `FirebaseApp`
instance.

### Sign in
### AuthUI sign-in

If a user is not currently signed in, as can be determined by checking
`auth.getCurrentUser() != null` (where `auth` is the `FirebaseAuth` instance
Expand Down Expand Up @@ -352,7 +353,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
showSnackbar(R.string.no_internet_connection);
return;
}

showSnackbar(R.string.unknown_error);
Log.e(TAG, "Sign-in error: ", response.getError());
}
Expand Down Expand Up @@ -401,6 +402,40 @@ if (metadata.getCreationTimestamp() == metadata.getLastSignInTimestamp()) {
}
```

### Silent sign-in

If a user is not currently signed in, then a silent sign-in process can be started first before
displaying any UI to provide a seamless experience. Silent sign-in uses saved Smart Lock credentials
and returns a successful `Task` only if the user has been fully signed in with Firebase.

Here's an example of how you could use silent sign-in paired with Firebase anonymous sign-in to get
your users up and running as fast as possible:

```java
List<IdpConfig> providers = getSelectedProviders();
AuthUI.getInstance().silentSignIn(this, providers)
.continueWithTask(this, new Continuation<AuthResult, Task<AuthResult>>() {
@Override
public Task<AuthResult> then(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
return task;
} else {
// Ignore any exceptions since we don't care about credential fetch errors.
return FirebaseAuth.getInstance().signInAnonymously();
}
}
}).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Signed in! Start loading data
} else {
// Uh oh, show error message
}
}
});
```

### Sign out

With the integrations provided by AuthUI, signing out a user is a multi-stage process:
Expand Down
84 changes: 84 additions & 0 deletions auth/src/main/java/com/firebase/ui/auth/AuthUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@
import com.firebase.ui.auth.util.data.PhoneNumberUtils;
import com.firebase.ui.auth.util.data.ProviderUtils;
import com.google.android.gms.auth.api.credentials.Credential;
import com.google.android.gms.auth.api.credentials.CredentialRequest;
import com.google.android.gms.auth.api.credentials.CredentialRequestResponse;
import com.google.android.gms.auth.api.credentials.CredentialsClient;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.CommonStatusCodes;
Expand All @@ -51,6 +54,8 @@
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuth;
Expand Down Expand Up @@ -267,6 +272,85 @@ public static int getDefaultTheme() {
return R.style.FirebaseUI;
}

/**
* Signs the user in without any UI if possible. If this operation fails, you can safely start a
* UI-based sign-in flow knowing it is required.
*
* @param context requesting the user be signed in
* @param desiredConfigs to use for silent sign in. Only Google and email are currently
* supported, the rest will be ignored.
* @return a task which indicates whether or not the user was successfully signed in.
*/
@NonNull
public Task<AuthResult> silentSignIn(@NonNull Context context,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am somewhat uncomfortable with all this code and chained async operations happening in one huge method block in AuthUI. Should we consider making this happen inside a ViewModel in KickoffActivity or something so that it's rotation-immune? Obviously then we couldn't directly return a Task but I think onActivityResult would be appropriate (and more consistent with our general mechanism anyway)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't like the number of chained tasks we have either, but I strongly disagree about the onActivityResult and ViewModel stuff. The point of this method is that it doesn't have any UI and should be done in the background (so it's up to the dev to deal with async callbacks as usual). As for rotation problems, they're up to the dev just like with any other Task. Also, I tried calling the method multiple times myself and it doesn't seem to matter besides being signed-in several times with the same credentials on the Firebase side (so the method is deterministic in that you'll just get the same result multiple times).

Do you see where I'm coming from? I literally call this method in my Application#onCreate() and I think other people will want to do something similar.

@NonNull List<IdpConfig> configs) {
if (mAuth.getCurrentUser() != null) {
throw new IllegalArgumentException("User already signed in!");
}

final Context appContext = context.getApplicationContext();
final IdpConfig google =
ProviderUtils.getConfigFromIdps(configs, GoogleAuthProvider.PROVIDER_ID);
final IdpConfig email =
ProviderUtils.getConfigFromIdps(configs, EmailAuthProvider.PROVIDER_ID);

if (google == null && email == null) {
throw new IllegalArgumentException("No supported providers were supplied. " +
"Add either Google or email support.");
}

final GoogleSignInOptions googleOptions;
if (google == null) {
googleOptions = null;
} else {
GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(appContext);
if (last != null && last.getIdToken() != null) {
return mAuth.signInWithCredential(GoogleAuthProvider.getCredential(
last.getIdToken(), null));
}

googleOptions = google.getParams()
.getParcelable(ExtraConstants.GOOGLE_SIGN_IN_OPTIONS);
}

return GoogleApiUtils.getCredentialsClient(context)
.request(new CredentialRequest.Builder()
// We can support both email and Google at the same time here because they
// are mutually exclusive. If a user signs in with Google, their email
// account will automatically be upgraded (a.k.a. replaced) with the Google
// one, meaning Smart Lock won't have to show the picker UI.
.setPasswordLoginSupported(email != null)
.setAccountTypes(google == null ? null :
ProviderUtils.providerIdToAccountType(GoogleAuthProvider.PROVIDER_ID))
.build())
.continueWithTask(new Continuation<CredentialRequestResponse, Task<AuthResult>>() {
@Override
public Task<AuthResult> then(@NonNull Task<CredentialRequestResponse> task) {
Credential credential = task.getResult().getCredential();
String email = credential.getId();
String password = credential.getPassword();

if (TextUtils.isEmpty(password)) {
return GoogleSignIn.getClient(appContext,
new GoogleSignInOptions.Builder(googleOptions)
.setAccountName(email)
.build())
.silentSignIn()
.continueWithTask(new Continuation<GoogleSignInAccount, Task<AuthResult>>() {
@Override
public Task<AuthResult> then(@NonNull Task<GoogleSignInAccount> task) {
AuthCredential authCredential = GoogleAuthProvider.getCredential(
task.getResult().getIdToken(), null);
return mAuth.signInWithCredential(authCredential);
}
});
} else {
return mAuth.signInWithEmailAndPassword(email, password);
}
}
});
}

/**
* Signs the current user out, if one is signed in.
*
Expand Down