Skip to content

Commit 7ca3cbf

Browse files
SUPERCILEXsamtstern
authored andcommitted
Rewrite relevant parts of the public API (#1010)
1 parent 0f9f1e9 commit 7ca3cbf

File tree

7 files changed

+247
-142
lines changed

7 files changed

+247
-142
lines changed

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,6 @@ public void onCreate(Bundle savedInstanceState) {
148148
setContentView(R.layout.auth_ui_layout);
149149
ButterKnife.bind(this);
150150

151-
FirebaseAuth auth = FirebaseAuth.getInstance();
152-
if (auth.getCurrentUser() != null) {
153-
startSignedInActivity(null);
154-
finish();
155-
return;
156-
}
157-
158151
if (isGoogleMisconfigured()) {
159152
mUseGoogleProvider.setChecked(false);
160153
mUseGoogleProvider.setEnabled(false);
@@ -227,6 +220,16 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
227220
showSnackbar(R.string.unknown_response);
228221
}
229222

223+
@Override
224+
protected void onResume() {
225+
super.onResume();
226+
FirebaseAuth auth = FirebaseAuth.getInstance();
227+
if (auth.getCurrentUser() != null) {
228+
startSignedInActivity(null);
229+
finish();
230+
}
231+
}
232+
230233
@MainThread
231234
private void handleSignInResponse(int resultCode, Intent data) {
232235
IdpResponse response = IdpResponse.fromResultIntent(data);

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import com.google.firebase.auth.FirebaseAuth;
4444
import com.google.firebase.auth.FirebaseUser;
4545
import com.google.firebase.auth.GoogleAuthProvider;
46+
import com.google.firebase.auth.PhoneAuthProvider;
47+
import com.google.firebase.auth.TwitterAuthProvider;
4648

4749
import java.util.ArrayList;
4850
import java.util.Iterator;
@@ -187,14 +189,24 @@ private void populateProfile() {
187189
Iterator<String> providerIter = user.getProviders().iterator();
188190
while (providerIter.hasNext()) {
189191
String provider = providerIter.next();
190-
if (GoogleAuthProvider.PROVIDER_ID.equals(provider)) {
191-
providerList.append("Google");
192-
} else if (FacebookAuthProvider.PROVIDER_ID.equals(provider)) {
193-
providerList.append("Facebook");
194-
} else if (EmailAuthProvider.PROVIDER_ID.equals(provider)) {
195-
providerList.append("Password");
196-
} else {
197-
providerList.append(provider);
192+
switch (provider) {
193+
case GoogleAuthProvider.PROVIDER_ID:
194+
providerList.append("Google");
195+
break;
196+
case FacebookAuthProvider.PROVIDER_ID:
197+
providerList.append("Facebook");
198+
break;
199+
case TwitterAuthProvider.PROVIDER_ID:
200+
providerList.append("Twitter");
201+
break;
202+
case EmailAuthProvider.PROVIDER_ID:
203+
providerList.append("Email");
204+
break;
205+
case PhoneAuthProvider.PROVIDER_ID:
206+
providerList.append("Phone");
207+
break;
208+
default:
209+
throw new IllegalStateException("Unknown provider: " + provider);
198210
}
199211

200212
if (providerIter.hasNext()) {

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

Lines changed: 105 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
package com.firebase.ui.auth;
1616

17-
import android.app.Activity;
17+
import android.content.Context;
1818
import android.content.Intent;
1919
import android.os.Bundle;
2020
import android.os.Parcel;
@@ -23,31 +23,39 @@
2323
import android.support.annotation.DrawableRes;
2424
import android.support.annotation.NonNull;
2525
import android.support.annotation.Nullable;
26+
import android.support.annotation.RestrictTo;
2627
import android.support.annotation.StringDef;
2728
import android.support.annotation.StyleRes;
28-
import android.support.v4.app.FragmentActivity;
29+
import android.text.TextUtils;
2930

3031
import com.facebook.login.LoginManager;
3132
import com.firebase.ui.auth.provider.TwitterProvider;
3233
import com.firebase.ui.auth.ui.ExtraConstants;
3334
import com.firebase.ui.auth.ui.FlowParameters;
3435
import com.firebase.ui.auth.ui.idp.AuthMethodPickerActivity;
35-
import com.firebase.ui.auth.util.GoogleSignInHelper;
36+
import com.firebase.ui.auth.util.GoogleApiUtils;
3637
import com.firebase.ui.auth.util.Preconditions;
37-
import com.firebase.ui.auth.util.signincontainer.SmartLockBase;
38+
import com.firebase.ui.auth.util.signincontainer.SaveSmartLock;
3839
import com.google.android.gms.auth.api.credentials.Credential;
39-
import com.google.android.gms.common.api.Status;
40+
import com.google.android.gms.auth.api.credentials.CredentialsClient;
41+
import com.google.android.gms.auth.api.signin.GoogleSignIn;
42+
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
43+
import com.google.android.gms.common.api.ApiException;
44+
import com.google.android.gms.common.api.CommonStatusCodes;
4045
import com.google.android.gms.tasks.Continuation;
4146
import com.google.android.gms.tasks.Task;
4247
import com.google.android.gms.tasks.Tasks;
4348
import com.google.firebase.FirebaseApp;
4449
import com.google.firebase.auth.EmailAuthProvider;
4550
import com.google.firebase.auth.FacebookAuthProvider;
4651
import com.google.firebase.auth.FirebaseAuth;
52+
import com.google.firebase.auth.FirebaseAuthInvalidUserException;
53+
import com.google.firebase.auth.FirebaseAuthProvider;
4754
import com.google.firebase.auth.FirebaseUser;
4855
import com.google.firebase.auth.GoogleAuthProvider;
4956
import com.google.firebase.auth.PhoneAuthProvider;
5057
import com.google.firebase.auth.TwitterAuthProvider;
58+
import com.google.firebase.auth.UserInfo;
5159

5260
import java.lang.annotation.Retention;
5361
import java.lang.annotation.RetentionPolicy;
@@ -138,6 +146,16 @@ public class AuthUI {
138146
PHONE_VERIFICATION_PROVIDER
139147
)));
140148

149+
/**
150+
* The set of social authentication providers supported in Firebase Auth UI.
151+
*/
152+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
153+
public static final Set<String> SOCIAL_PROVIDERS =
154+
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
155+
GoogleAuthProvider.PROVIDER_ID,
156+
FacebookAuthProvider.PROVIDER_ID,
157+
TwitterAuthProvider.PROVIDER_ID)));
158+
141159
private static final IdentityHashMap<FirebaseApp, AuthUI> INSTANCES = new IdentityHashMap<>();
142160

143161
private final FirebaseApp mApp;
@@ -189,40 +207,17 @@ public static int getDefaultTheme() {
189207
/**
190208
* Signs the current user out, if one is signed in.
191209
*
192-
* @param activity the activity requesting the user be signed out
210+
* @param context the context requesting the user be signed out
193211
* @return A task which, upon completion, signals that the user has been signed out ({@link
194212
* Task#isSuccessful()}, or that the sign-out attempt failed unexpectedly !{@link
195213
* Task#isSuccessful()}).
196214
*/
197215
@NonNull
198-
public Task<Void> signOut(@NonNull FragmentActivity activity) {
199-
// Get Credentials Helper
200-
GoogleSignInHelper signInHelper = GoogleSignInHelper.getInstance(activity);
201-
202-
// Firebase Sign out
216+
public Task<Void> signOut(@NonNull Context context) {
203217
mAuth.signOut();
204-
205-
// Disable credentials auto sign-in
206-
Task<Status> disableCredentialsTask = signInHelper.disableAutoSignIn();
207-
208-
// Google sign out
209-
Task<Status> signOutTask = signInHelper.signOut();
210-
211-
// Facebook sign out
212-
try {
213-
LoginManager.getInstance().logOut();
214-
} catch (NoClassDefFoundError e) {
215-
// do nothing
216-
}
217-
218-
// Twitter sign out
219-
try {
220-
TwitterProvider.signOut(activity);
221-
} catch (NoClassDefFoundError e) {
222-
// do nothing
223-
}
224-
// Wait for all tasks to complete
225-
return Tasks.whenAll(disableCredentialsTask, signOutTask);
218+
return Tasks.whenAll(
219+
signOutIdps(context),
220+
GoogleApiUtils.getCredentialsClient(context).disableAutoSignIn());
226221
}
227222

228223
/**
@@ -231,48 +226,94 @@ public Task<Void> signOut(@NonNull FragmentActivity activity) {
231226
* fails if the Firebase Auth deletion fails. Credentials deletion failures are handled
232227
* silently.
233228
*
234-
* @param activity the calling {@link Activity}.
229+
* @param context the calling {@link Context}.
235230
*/
236231
@NonNull
237-
public Task<Void> delete(@NonNull FragmentActivity activity) {
238-
// Initialize SmartLock helper
239-
GoogleSignInHelper signInHelper = GoogleSignInHelper.getInstance(activity);
240-
241-
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
242-
if (firebaseUser == null) {
243-
// If the current user is null, return a failed task immediately
244-
return Tasks.forException(new Exception("No currently signed in user."));
232+
public Task<Void> delete(@NonNull Context context) {
233+
final FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
234+
if (currentUser == null) {
235+
return Tasks.forException(new FirebaseAuthInvalidUserException(
236+
String.valueOf(CommonStatusCodes.SIGN_IN_REQUIRED),
237+
"No currently signed in user."));
245238
}
246239

247-
// Delete the Firebase user
248-
Task<Void> deleteUserTask = firebaseUser.delete();
240+
final List<Credential> credentials = getCredentialsFromFirebaseUser(currentUser);
241+
final CredentialsClient client = GoogleApiUtils.getCredentialsClient(context);
249242

250-
// Get all SmartLock credentials associated with the user
251-
List<Credential> credentials = SmartLockBase.credentialsFromFirebaseUser(firebaseUser);
243+
// Ensure the order in which tasks are executed properly destructures the user.
244+
return signOutIdps(context).continueWithTask(new Continuation<Void, Task<Void>>() {
245+
@Override
246+
public Task<Void> then(@NonNull Task<Void> task) {
247+
task.getResult(); // Propagate exception if there was one
248+
return currentUser.delete();
249+
}
250+
}).continueWithTask(new Continuation<Void, Task<Void>>() {
251+
@Override
252+
public Task<Void> then(@NonNull Task<Void> task) {
253+
task.getResult(); // Propagate exception if there was one
252254

253-
// For each Credential in the list, create a task to delete it.
254-
List<Task<?>> credentialTasks = new ArrayList<>();
255-
for (Credential credential : credentials) {
256-
credentialTasks.add(signInHelper.delete(credential));
255+
List<Task<?>> credentialTasks = new ArrayList<>();
256+
for (Credential credential : credentials) {
257+
credentialTasks.add(client.delete(credential));
258+
}
259+
return Tasks.whenAll(credentialTasks)
260+
.continueWithTask(new Continuation<Void, Task<Void>>() {
261+
@Override
262+
public Task<Void> then(@NonNull Task<Void> task) {
263+
Exception e = task.getException();
264+
Throwable t = e == null ? null : e.getCause();
265+
if (!(t instanceof ApiException)
266+
|| ((ApiException) t).getStatusCode() != CommonStatusCodes.CANCELED) {
267+
// Only propagate the exception if it isn't an invalid account
268+
// one. This can occur if we failed to save the credential or it
269+
// was deleted elsewhere. However, a lack of stored credential
270+
// doesn't mean fully deleting the user failed.
271+
task.getResult();
272+
}
273+
274+
return Tasks.forResult(null);
275+
}
276+
});
277+
}
278+
});
279+
}
280+
281+
private Task<Void> signOutIdps(@NonNull Context context) {
282+
try {
283+
LoginManager.getInstance().logOut();
284+
TwitterProvider.signOut(context);
285+
} catch (NoClassDefFoundError e) {
286+
// Do nothing: this is perfectly fine if the dev doesn't include Facebook/Twitter
287+
// support
257288
}
258289

259-
// Create a combined task that will succeed when all credential delete operations
260-
// have completed (even if they fail).
261-
final Task<Void> combinedCredentialTask = Tasks.whenAll(credentialTasks);
290+
return GoogleSignIn.getClient(context, GoogleSignInOptions.DEFAULT_SIGN_IN).signOut();
291+
}
262292

263-
// Chain the Firebase Auth delete task with the combined Credentials task
264-
// and return.
265-
return deleteUserTask.continueWithTask(new Continuation<Void, Task<Void>>() {
266-
@Override
267-
public Task<Void> then(@NonNull Task<Void> task) throws Exception {
268-
// Call getResult() to propagate failure by throwing an exception
269-
// if there was one.
270-
task.getResult(Exception.class);
293+
/**
294+
* Make a list of {@link Credential} from a FirebaseUser. Useful for deleting Credentials, not
295+
* for saving since we don't have access to the password.
296+
*/
297+
private static List<Credential> getCredentialsFromFirebaseUser(@NonNull FirebaseUser user) {
298+
if (TextUtils.isEmpty(user.getEmail()) && TextUtils.isEmpty(user.getPhoneNumber())) {
299+
return Collections.emptyList();
300+
}
271301

272-
// Return the combined credential task
273-
return combinedCredentialTask;
302+
List<Credential> credentials = new ArrayList<>();
303+
for (UserInfo userInfo : user.getProviderData()) {
304+
if (FirebaseAuthProvider.PROVIDER_ID.equals(userInfo.getProviderId())) {
305+
continue;
274306
}
275-
});
307+
308+
String type = SaveSmartLock.providerIdToAccountType(userInfo.getProviderId());
309+
310+
credentials.add(new Credential.Builder(
311+
user.getEmail() == null ? user.getPhoneNumber() : user.getEmail())
312+
.setAccountType(type)
313+
.build());
314+
}
315+
316+
return credentials;
276317
}
277318

278319
/**

0 commit comments

Comments
 (0)