diff --git a/README.md b/README.md
index c656407c1..1bcd3f4e2 100644
--- a/README.md
+++ b/README.md
@@ -47,16 +47,16 @@ libraries.
```groovy
dependencies {
// FirebaseUI for Firebase Realtime Database
- implementation 'com.firebaseui:firebase-ui-database:4.0.1'
+ implementation 'com.firebaseui:firebase-ui-database:4.1.0'
// FirebaseUI for Cloud Firestore
- implementation 'com.firebaseui:firebase-ui-firestore:4.0.1'
+ implementation 'com.firebaseui:firebase-ui-firestore:4.1.0'
// FirebaseUI for Firebase Auth
- implementation 'com.firebaseui:firebase-ui-auth:4.0.1'
+ implementation 'com.firebaseui:firebase-ui-auth:4.1.0'
// FirebaseUI for Cloud Storage
- implementation 'com.firebaseui:firebase-ui-storage:4.0.1'
+ implementation 'com.firebaseui:firebase-ui-storage:4.1.0'
}
```
@@ -99,7 +99,7 @@ versions. This means that FirebaseUI has independent dependencies on each of the
For best results, your app should depend on a version of each dependency with the same major
version number as the version used by FirebaseUI.
-As of version `4.0.0`, FirebaseUI has the following dependency versions:
+As of version `4.1.0`, FirebaseUI has the following dependency versions:
| Library | Version |
|----------------------|--------------------------------|
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0a381a18c..0a6d84862 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -37,6 +37,9 @@
+ {
private static final Class[] CLASSES = new Class[]{
AuthUiActivity.class,
+ AnonymousUpgradeActivity.class,
FirestoreChatActivity.class,
FirestorePagingActivity.class,
RealtimeDbChatActivity.class,
@@ -61,6 +63,7 @@ private static class ActivityChooserAdapter extends RecyclerView.Adapter() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ updateUI();
+
+ if (task.isSuccessful()) {
+ setStatus("Signed in anonymously as user "
+ + getUserIdentifier(task.getResult().getUser()));
+ } else {
+ setStatus("Anonymous sign in failed.");
+ }
+ }
+ });
+ }
+
+ @OnClick(R.id.begin_flow)
+ public void startAuthUI() {
+ List providers = ConfigurationUtils.getConfiguredProviders(this);
+ Intent intent = AuthUI.getInstance().createSignInIntentBuilder()
+ .setLogo(R.drawable.firebase_auth_120dp)
+ .setAvailableProviders(providers)
+ .setIsSmartLockEnabled(false)
+ .enableAnonymousUsersAutoUpgrade()
+ .build();
+ startActivityForResult(intent, RC_SIGN_IN);
+ }
+
+ @OnClick(R.id.resolve_merge)
+ public void resolveMerge() {
+ if (mPendingCredential == null) {
+ Toast.makeText(this, "Nothing to resolve.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // TODO: Show how to do good data moving
+
+ FirebaseAuth.getInstance().signInWithCredential(mPendingCredential)
+ .addOnCompleteListener(this, new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ mPendingCredential = null;
+ updateUI();
+
+ if (task.isSuccessful()) {
+ setStatus("Signed in as " + getUserIdentifier(task.getResult().getUser()));
+ } else {
+ Log.w(TAG, "Merge failed", task.getException());
+ setStatus("Failed to resolve merge conflict, see logs.");
+ }
+ }
+ });
+ }
+
+ @OnClick(R.id.sign_out)
+ public void signOut() {
+ AuthUI.getInstance().signOut(this)
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ setStatus(null);
+ updateUI();
+ }
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == RC_SIGN_IN) {
+ IdpResponse response = IdpResponse.fromResultIntent(data);
+ if (response == null) {
+ // User pressed back button
+ return;
+ }
+ if (resultCode == RESULT_OK) {
+ 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();
+ }
+ }
+
+ updateUI();
+ }
+ }
+
+ private void updateUI() {
+ FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
+
+ if (currentUser == null) {
+ // Not signed in
+ mAnonSignInButton.setEnabled(true);
+ mLaunchUIButton.setEnabled(false);
+ mResolveMergeButton.setEnabled(false);
+ mSignOutButton.setEnabled(false);
+ } else if (mPendingCredential == null && currentUser.isAnonymous()) {
+ // Anonymous user, waiting for linking
+ mAnonSignInButton.setEnabled(false);
+ mLaunchUIButton.setEnabled(true);
+ mResolveMergeButton.setEnabled(false);
+ mSignOutButton.setEnabled(true);
+ } else if (mPendingCredential == null && !currentUser.isAnonymous()) {
+ // Fully signed in
+ mAnonSignInButton.setEnabled(false);
+ mLaunchUIButton.setEnabled(false);
+ mResolveMergeButton.setEnabled(false);
+ mSignOutButton.setEnabled(true);
+ } else if (mPendingCredential != null) {
+ // Signed in anonymous, awaiting merge conflict
+ mAnonSignInButton.setEnabled(false);
+ mLaunchUIButton.setEnabled(false);
+ mResolveMergeButton.setEnabled(true);
+ mSignOutButton.setEnabled(true);
+ }
+ }
+
+ private void setStatus(String message) {
+ mStatus.setText(message);
+ }
+
+ private String getUserIdentifier(FirebaseUser user) {
+ if (user.isAnonymous()) {
+ return user.getUid();
+ } else if (!TextUtils.isEmpty(user.getEmail())) {
+ return user.getEmail();
+ } else if (!TextUtils.isEmpty(user.getPhoneNumber())) {
+ return user.getPhoneNumber();
+ } else {
+ return "unknown";
+ }
+ }
+}
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 f98a4d7fa..c1aeb0632 100644
--- a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java
+++ b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java
@@ -38,6 +38,7 @@
import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.IdpResponse;
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;
@@ -45,7 +46,6 @@
import com.google.firebase.auth.FirebaseAuth;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import butterknife.BindView;
@@ -67,13 +67,14 @@ public class AuthUiActivity extends AppCompatActivity {
@BindView(R.id.google_provider) CheckBox mUseGoogleProvider;
@BindView(R.id.facebook_provider) CheckBox mUseFacebookProvider;
@BindView(R.id.twitter_provider) CheckBox mUseTwitterProvider;
+ @BindView(R.id.github_provider) CheckBox mUseGitHubProvider;
@BindView(R.id.email_provider) CheckBox mUseEmailProvider;
@BindView(R.id.phone_provider) CheckBox mUsePhoneProvider;
- @BindView(R.id.default_theme) RadioButton mUseDefaultTheme;
- @BindView(R.id.green_theme) RadioButton mUseGreenTheme;
- @BindView(R.id.purple_theme) RadioButton mUsePurpleTheme;
- @BindView(R.id.dark_theme) RadioButton mUseDarkTheme;
+ @BindView(R.id.default_theme) RadioButton mDefaultTheme;
+ @BindView(R.id.green_theme) RadioButton mGreenTheme;
+ @BindView(R.id.purple_theme) RadioButton mPurpleTheme;
+ @BindView(R.id.dark_theme) RadioButton mDarkTheme;
@BindView(R.id.firebase_logo) RadioButton mFirebaseLogo;
@BindView(R.id.google_logo) RadioButton mGoogleLogo;
@@ -85,13 +86,17 @@ public class AuthUiActivity extends AppCompatActivity {
@BindView(R.id.google_privacy) RadioButton mUseGooglePrivacyPolicy;
@BindView(R.id.firebase_privacy) RadioButton mUseFirebasePrivacyPolicy;
- @BindView(R.id.google_scopes_header) TextView mGoogleScopesLabel;
+ @BindView(R.id.google_scopes_header) TextView mGoogleScopesHeader;
@BindView(R.id.google_scope_drive_file) CheckBox mGoogleScopeDriveFile;
@BindView(R.id.google_scope_youtube_data) CheckBox mGoogleScopeYoutubeData;
- @BindView(R.id.facebook_permissions_header) TextView mFacebookScopesLabel;
- @BindView(R.id.facebook_permission_friends) CheckBox mFacebookScopeFriends;
- @BindView(R.id.facebook_permission_photos) CheckBox mFacebookScopePhotos;
+ @BindView(R.id.facebook_permissions_header) TextView mFacebookPermissionsHeader;
+ @BindView(R.id.facebook_permission_friends) CheckBox mFacebookPermissionFriends;
+ @BindView(R.id.facebook_permission_photos) CheckBox mFacebookPermissionPhotos;
+
+ @BindView(R.id.github_permissions_header) TextView mGitHubPermissionsHeader;
+ @BindView(R.id.github_permission_repo) CheckBox mGitHubPermissionRepo;
+ @BindView(R.id.github_permission_gist) CheckBox mGitHubPermissionGist;
@BindView(R.id.credential_selector_enabled) CheckBox mEnableCredentialSelector;
@BindView(R.id.hint_selector_enabled) CheckBox mEnableHintSelector;
@@ -108,7 +113,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(R.layout.auth_ui_layout);
ButterKnife.bind(this);
- if (isGoogleMisconfigured()) {
+ if (ConfigurationUtils.isGoogleMisconfigured(this)) {
mUseGoogleProvider.setChecked(false);
mUseGoogleProvider.setEnabled(false);
mUseGoogleProvider.setText(R.string.google_label_missing_config);
@@ -123,33 +128,51 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
});
}
- if (isFacebookMisconfigured()) {
+ if (ConfigurationUtils.isFacebookMisconfigured(this)) {
mUseFacebookProvider.setChecked(false);
mUseFacebookProvider.setEnabled(false);
mUseFacebookProvider.setText(R.string.facebook_label_missing_config);
- setFacebookScopesEnabled(false);
+ setFacebookPermissionsEnabled(false);
} else {
- setFacebookScopesEnabled(mUseFacebookProvider.isChecked());
+ setFacebookPermissionsEnabled(mUseFacebookProvider.isChecked());
mUseFacebookProvider.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
- setFacebookScopesEnabled(checked);
+ setFacebookPermissionsEnabled(checked);
}
});
}
- if (isTwitterMisconfigured()) {
+ if (ConfigurationUtils.isTwitterMisconfigured(this)) {
mUseTwitterProvider.setChecked(false);
mUseTwitterProvider.setEnabled(false);
mUseTwitterProvider.setText(R.string.twitter_label_missing_config);
}
- if (isGoogleMisconfigured() || isFacebookMisconfigured() || isTwitterMisconfigured()) {
+ if (ConfigurationUtils.isGitHubMisconfigured(this)) {
+ mUseGitHubProvider.setChecked(false);
+ mUseGitHubProvider.setEnabled(false);
+ mUseGitHubProvider.setText(R.string.github_label_missing_config);
+ setGitHubPermissionsEnabled(false);
+ } else {
+ setGitHubPermissionsEnabled(mUseGitHubProvider.isChecked());
+ mUseGitHubProvider.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ setGitHubPermissionsEnabled(checked);
+ }
+ });
+ }
+
+ if (ConfigurationUtils.isGoogleMisconfigured(this)
+ || ConfigurationUtils.isFacebookMisconfigured(this)
+ || ConfigurationUtils.isTwitterMisconfigured(this)
+ || ConfigurationUtils.isGitHubMisconfigured(this)) {
showSnackbar(R.string.configuration_required);
}
if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
- mUseDarkTheme.setChecked(true);
+ mDarkTheme.setChecked(true);
}
}
@@ -160,8 +183,8 @@ public void signIn(View view) {
.setTheme(getSelectedTheme())
.setLogo(getSelectedLogo())
.setAvailableProviders(getSelectedProviders())
- .setTosUrl(getSelectedTosUrl())
- .setPrivacyPolicyUrl(getSelectedPrivacyPolicyUrl())
+ .setTosAndPrivacyPolicyUrls(getSelectedTosUrl(),
+ getSelectedPrivacyPolicyUrl())
.setIsSmartLockEnabled(mEnableCredentialSelector.isChecked(),
mEnableHintSelector.isChecked())
.build(),
@@ -202,7 +225,7 @@ protected void onResume() {
}
private void handleSignInResponse(int resultCode, Intent data) {
- IdpResponse response = IdpResponse.fromResultIntent(data);
+ final IdpResponse response = IdpResponse.fromResultIntent(data);
// Successfully signed in
if (resultCode == RESULT_OK) {
@@ -232,7 +255,7 @@ private void startSignedInActivity(IdpResponse response) {
@OnClick({R.id.default_theme, R.id.purple_theme, R.id.green_theme, R.id.dark_theme})
public void toggleDarkTheme() {
- int mode = mUseDarkTheme.isChecked() ?
+ int mode = mDarkTheme.isChecked() ?
AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_AUTO;
AppCompatDelegate.setDefaultNightMode(mode);
getDelegate().setLocalNightMode(mode);
@@ -240,11 +263,11 @@ public void toggleDarkTheme() {
@StyleRes
private int getSelectedTheme() {
- if (mUseGreenTheme.isChecked()) {
+ if (mGreenTheme.isChecked()) {
return R.style.GreenTheme;
}
- if (mUsePurpleTheme.isChecked()) {
+ if (mPurpleTheme.isChecked()) {
return R.style.PurpleTheme;
}
@@ -279,6 +302,12 @@ private List getSelectedProviders() {
selectedProviders.add(new IdpConfig.TwitterBuilder().build());
}
+ if (mUseGitHubProvider.isChecked()) {
+ selectedProviders.add(new IdpConfig.GitHubBuilder()
+ .setPermissions(getGitHubPermissions())
+ .build());
+ }
+
if (mUseEmailProvider.isChecked()) {
selectedProviders.add(new IdpConfig.EmailBuilder()
.setRequireName(mRequireName.isChecked())
@@ -309,33 +338,22 @@ private String getSelectedPrivacyPolicyUrl() {
return FIREBASE_PRIVACY_POLICY_URL;
}
- private boolean isGoogleMisconfigured() {
- return AuthUI.UNCONFIGURED_CONFIG_VALUE.equals(getString(R.string.default_web_client_id));
- }
-
- private boolean isFacebookMisconfigured() {
- return AuthUI.UNCONFIGURED_CONFIG_VALUE.equals(getString(R.string.facebook_application_id));
- }
-
- private boolean isTwitterMisconfigured() {
- List twitterConfigs = Arrays.asList(
- getString(R.string.twitter_consumer_key),
- getString(R.string.twitter_consumer_secret)
- );
-
- return twitterConfigs.contains(AuthUI.UNCONFIGURED_CONFIG_VALUE);
- }
-
private void setGoogleScopesEnabled(boolean enabled) {
- mGoogleScopesLabel.setEnabled(enabled);
+ mGoogleScopesHeader.setEnabled(enabled);
mGoogleScopeDriveFile.setEnabled(enabled);
mGoogleScopeYoutubeData.setEnabled(enabled);
}
- private void setFacebookScopesEnabled(boolean enabled) {
- mFacebookScopesLabel.setEnabled(enabled);
- mFacebookScopeFriends.setEnabled(enabled);
- mFacebookScopePhotos.setEnabled(enabled);
+ private void setFacebookPermissionsEnabled(boolean enabled) {
+ mFacebookPermissionsHeader.setEnabled(enabled);
+ mFacebookPermissionFriends.setEnabled(enabled);
+ mFacebookPermissionPhotos.setEnabled(enabled);
+ }
+
+ private void setGitHubPermissionsEnabled(boolean enabled) {
+ mGitHubPermissionsHeader.setEnabled(enabled);
+ mGitHubPermissionRepo.setEnabled(enabled);
+ mGitHubPermissionGist.setEnabled(enabled);
}
private List getGoogleScopes() {
@@ -351,15 +369,26 @@ private List getGoogleScopes() {
private List getFacebookPermissions() {
List result = new ArrayList<>();
- if (mFacebookScopeFriends.isChecked()) {
+ if (mFacebookPermissionFriends.isChecked()) {
result.add("user_friends");
}
- if (mFacebookScopePhotos.isChecked()) {
+ if (mFacebookPermissionPhotos.isChecked()) {
result.add("user_photos");
}
return result;
}
+ private List getGitHubPermissions() {
+ List result = new ArrayList<>();
+ if (mGitHubPermissionRepo.isChecked()) {
+ result.add("repo");
+ }
+ if (mGitHubPermissionGist.isChecked()) {
+ result.add("gist");
+ }
+ return result;
+ }
+
private void showSnackbar(@StringRes int errorMessageRes) {
Snackbar.make(mRootView, errorMessageRes, Snackbar.LENGTH_LONG).show();
}
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 6917ea8e5..f921f310c 100644
--- a/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java
+++ b/app/src/main/java/com/firebase/uidemo/auth/SignedInActivity.java
@@ -42,6 +42,7 @@
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthProvider;
import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
@@ -64,6 +65,7 @@ public class SignedInActivity extends AppCompatActivity {
@BindView(R.id.user_display_name) TextView mUserDisplayName;
@BindView(R.id.user_phone_number) TextView mUserPhoneNumber;
@BindView(R.id.user_enabled_providers) TextView mEnabledProviders;
+ @BindView(R.id.user_is_new) TextView mIsNewUser;
public static Intent createIntent(Context context, IdpResponse idpResponse) {
return new Intent().setClass(context, SignedInActivity.class)
@@ -85,7 +87,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(R.layout.signed_in_layout);
ButterKnife.bind(this);
- populateProfile();
+ populateProfile(response);
populateIdpToken(response);
}
@@ -137,7 +139,7 @@ public void onComplete(@NonNull Task task) {
});
}
- private void populateProfile() {
+ private void populateProfile(@Nullable IdpResponse response) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user.getPhotoUrl() != null) {
GlideApp.with(this)
@@ -153,6 +155,13 @@ private void populateProfile() {
mUserDisplayName.setText(
TextUtils.isEmpty(user.getDisplayName()) ? "No display name" : user.getDisplayName());
+ if (response == null) {
+ mIsNewUser.setVisibility(View.GONE);
+ } else {
+ mIsNewUser.setVisibility(View.VISIBLE);
+ mIsNewUser.setText(response.isNewUser() ? "New user" : "Existing user");
+ }
+
List providers = new ArrayList<>();
if (user.getProviderData().isEmpty()) {
providers.add("Anonymous");
@@ -168,6 +177,9 @@ private void populateProfile() {
case TwitterAuthProvider.PROVIDER_ID:
providers.add(getString(R.string.providers_twitter));
break;
+ case GithubAuthProvider.PROVIDER_ID:
+ providers.add(getString(R.string.providers_github));
+ break;
case EmailAuthProvider.PROVIDER_ID:
providers.add(getString(R.string.providers_email));
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
new file mode 100644
index 000000000..18f3f7d0b
--- /dev/null
+++ b/app/src/main/java/com/firebase/uidemo/util/ConfigurationUtils.java
@@ -0,0 +1,68 @@
+package com.firebase.uidemo.util;
+
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import com.firebase.ui.auth.AuthUI;
+import com.firebase.uidemo.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ConfigurationUtils {
+
+ public static boolean isGoogleMisconfigured(Context context) {
+ return AuthUI.UNCONFIGURED_CONFIG_VALUE.equals(
+ context.getString(R.string.default_web_client_id));
+ }
+
+ public static boolean isFacebookMisconfigured(Context context) {
+ return AuthUI.UNCONFIGURED_CONFIG_VALUE.equals(
+ context.getString(R.string.facebook_application_id));
+ }
+
+ public static boolean isTwitterMisconfigured(Context context) {
+ List twitterConfigs = Arrays.asList(
+ context.getString(R.string.twitter_consumer_key),
+ context.getString(R.string.twitter_consumer_secret)
+ );
+
+ return twitterConfigs.contains(AuthUI.UNCONFIGURED_CONFIG_VALUE);
+ }
+
+ public static boolean isGitHubMisconfigured(Context context) {
+ List gitHubConfigs = Arrays.asList(
+ context.getString(R.string.firebase_web_host),
+ context.getString(R.string.github_client_id),
+ context.getString(R.string.github_client_secret)
+ );
+
+ return gitHubConfigs.contains(AuthUI.UNCONFIGURED_CONFIG_VALUE);
+ }
+
+ public static List getConfiguredProviders(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());
+ }
+
+ if (!isFacebookMisconfigured(context)) {
+ providers.add(new AuthUI.IdpConfig.FacebookBuilder().build());
+ }
+
+ if (!isTwitterMisconfigured(context)) {
+ providers.add(new AuthUI.IdpConfig.TwitterBuilder().build());
+ }
+
+ if (!isGitHubMisconfigured(context)) {
+ providers.add(new AuthUI.IdpConfig.GitHubBuilder().build());
+ }
+
+ return providers;
+ }
+}
diff --git a/app/src/main/res/layout/activity_anonymous_upgrade.xml b/app/src/main/res/layout/activity_anonymous_upgrade.xml
new file mode 100644
index 000000000..6ac9537e0
--- /dev/null
+++ b/app/src/main/res/layout/activity_anonymous_upgrade.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/auth_ui_layout.xml b/app/src/main/res/layout/auth_ui_layout.xml
index 18e092837..913a58d38 100644
--- a/app/src/main/res/layout/auth_ui_layout.xml
+++ b/app/src/main/res/layout/auth_ui_layout.xml
@@ -75,6 +75,13 @@
android:checked="true"
android:text="@string/providers_twitter" />
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/config.xml b/app/src/main/res/values/config.xml
index bda3df118..376bc405f 100644
--- a/app/src/main/res/values/config.xml
+++ b/app/src/main/res/values/config.xml
@@ -1,4 +1,7 @@
+
+ CHANGE-ME
+
CHANGE-ME
-
+
fbYOUR_APP_ID
@@ -19,11 +20,27 @@
CHANGE-MECHANGE-ME
+
+
+
+ CHANGE-ME
+
+
+ CHANGE-ME
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c8ad6e691..21f8093f3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -9,6 +9,7 @@
Storage Image DemoDemonstrates the Firebase Auth UI flow, with customization options.
+ Demonstrates upgrading an anonymous account using FirebaseUI.Demonstrates using a FirestoreRecyclerAdapter to load data from Cloud Firestore into a RecyclerView for a basic chat app.Demonstrates using a FirestorePagingAdapter to load/infinite scroll paged data from Cloud Firestore.Demonstrates using a FirebaseRecyclerAdapter to load data from Firebase Database into a RecyclerView for a basic chat app.
@@ -22,6 +23,7 @@
Auth providersGoogleFacebook
+ GitHubTwitterEmailPhone
@@ -53,6 +55,10 @@
FriendsPhotos
+ Example extra GitHub permissions
+ Repo
+ Gist
+
Other OptionsEnable Smart Lock\'s credential selectorEnable Smart Lock\'s hint selector
@@ -63,11 +69,17 @@
Google configuration missingFacebook configuration missingTwitter configuration missing
+ GitHub configuration missingSign in cancelledNo internet connectionAn unknown error occurred
+ FirebaseUI Anonymous Account Linking
+ Anonymous Sign In
+ Launch Auth UI
+ Resolve Merge Conflict
+
You are signed in!Sign out
diff --git a/auth/README.md b/auth/README.md
index 9ed1f100a..366635065 100644
--- a/auth/README.md
+++ b/auth/README.md
@@ -38,6 +38,7 @@ and [Web](https://github.com/firebase/firebaseui-web/).
1. [Silent sign-in](#silent-sign-in)
1. [Sign out](#sign-out)
1. [Account deletion](#deleting-accounts)
+ 1. [Upgrading Anonymous Users](#upgrading-anonymous-users)
1. [Auth flow chart](#authentication-flow-chart)
1. [Customization](#ui-customization)
1. [Required setup](#required-setup)
@@ -47,6 +48,7 @@ and [Web](https://github.com/firebase/firebaseui-web/).
1. [Google](#google-1)
1. [Facebook](#facebook-1)
1. [Twitter](#twitter-1)
+ 1. [GitHub](#github-1)
## Demo
@@ -63,7 +65,7 @@ Gradle, add the dependency:
```groovy
dependencies {
// ...
- implementation 'com.firebaseui:firebase-ui-auth:4.0.1'
+ implementation 'com.firebaseui:firebase-ui-auth:4.1.0'
// Required only if Facebook login support is required
// Find the latest Facebook SDK releases here: https://goo.gl/Ce5L94
@@ -127,8 +129,8 @@ Twitter app as reported by the [Twitter application manager](https://apps.twitte
```xml
- YOURCONSUMERKEY
- YOURCONSUMERSECRET
+ YOUR_CONSUMER_KEY
+ YOUR_CONSUMER_SECRET
```
@@ -146,6 +148,107 @@ allprojects {
}
```
+#### GitHub
+
+WARNING: GitHub OAuth is not for the faint of heart. Getting it setup correctly is an invested
+process and may take a half-hour or two. Ready? Let's begin.
+
+##### Wait, but _why_?
+
+GitHub requires that override redirect URIs only extend the base URI configured in the dashboard for
+[security reasons](https://tools.ietf.org/html/rfc6749#section-10.6). What does this mean? For
+GitHub auth to work on the web, the full `https://project-id.firebaseapp.com/__/auth/handler`
+redirect URI must be specified, thus preventing us Android devs from using a custom scheme (since we
+can only extend the base URI with extra path elements).
+
+As a side note, if you don't care about Web or iOS support, you can
+simply override our `GitHubLoginActivity`'s intent filters with your custom scheme to skip all these
+steps... However, this will make adding support for Web or iOS difficult should you decided to do so
+in the future—hence us not officially support this method.
+
+##### Adding secrets
+
+Hop over to your [GitHub app](https://github.com/settings/developers) and grab its client ID and
+Secret to put them in your resources:
+
+```xml
+
+ YOUR_CLIENT_ID
+ YOUR_CLIENT_SECRET
+
+```
+
+##### Adding your Firebase web host
+
+Next, find your project id in the Firebase Console's project settings and add it to your resources
+in the form `project-id.firebaseapp.com`:
+
+```xml
+
+ project-id.firebaseapp.com
+
+```
+
+##### Getting a SHA-256 hash of your keystore
+
+[Run the `keytool` utility](https://developers.google.com/android/guides/client-auth) found in your
+JDK's installation folder to get a SHA-256 hash of your release keystore. The command should look
+something like this (but for your release keystore):
+
+```sh
+keytool -list -v \
+ -keystore ~/.android/debug.keystore \
+ -alias androiddebugkey \
+ -storepass android \
+ -keypass android
+```
+
+Protip: you might as well also grab the release SHA-1 hash and the debug hashes to add them to the
+Firebase Console since they're useful in other contexts. Also, adding debug hashes will let you test
+all this without having to use a release build.
+
+##### Deploying a Firebase Hosting solution
+
+If you're already using Firebase Hosting, give yourself a pat on the back and move on. Otherwise,
+read on! Go through [this tutorial](https://firebase.google.com/docs/hosting/quickstart) and make
+sure to say no when asked to
+[redirect](https://firebase.google.com/docs/hosting/url-redirects-rewrites) everything to a single
+page. If you're already doing that, exclude `.well-known/assetlinks.json`.
+
+##### Adding asset links
+
+So close, you're almost there! Follow step 1 of
+[this tutorial](https://developers.google.com/digital-asset-links/v1/getting-started#quick-usage-example)
+with your own package name and SHA-256 hash gathered earlier. Now add the resulting JSON to
+`.well-known/assetlinks.json` on your Firebase Hosting website and re-deploy it. Your JSON should
+look something like this:
+
+```js
+[{
+ "relation": ["delegate_permission/common.handle_all_urls"],
+ "target" : {
+ "namespace": "android_app",
+ "package_name": "com.your.package.name",
+ "sha256_cert_fingerprints": ["your_sha_256_fingerprint"]
+ }
+}]
+```
+
+##### Putting it all together
+
+You should now have:
+- String resources with your secrets and Firebase web host
+- SHA hashes in the Firebase Console
+- A Firebase Hosting website with asset links
+
+Congrats, you did it! All that's left to do is [kick off the sign-in flow](#authui-sign-in).
+
+##### Help, I'm stuck!
+
+In all likelihood, your [asset links](#adding-asset-links) aren't configured correctly. Make sure
+that `https://project-id.firebaseapp.com/.well-known/assetlinks.json` resolves without redirects. If
+all else fails, FUI team members will help you out on StackOverflow with the `FirebaseUI` tag.
+
## Using FirebaseUI for authentication
Before invoking the FirebaseUI authentication flow, your app should check
@@ -220,26 +323,27 @@ startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(Arrays.asList(
- new AuthUI.IdpConfig.EmailBuilder().build(),
- new AuthUI.IdpConfig.PhoneBuilder().build(),
new AuthUI.IdpConfig.GoogleBuilder().build(),
new AuthUI.IdpConfig.FacebookBuilder().build(),
- new AuthUI.IdpConfig.TwitterBuilder().build()))
+ new AuthUI.IdpConfig.TwitterBuilder().build(),
+ new AuthUI.IdpConfig.GitHubBuilder().build(),
+ new AuthUI.IdpConfig.EmailBuilder().build(),
+ new AuthUI.IdpConfig.PhoneBuilder().build()))
.build(),
RC_SIGN_IN);
```
##### Adding a ToS and privacy policy
-If a terms of service URL and privacy policy URL are required:
+A terms of service URL and privacy policy URL are generally required:
```java
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(...)
- .setTosUrl("https://superapp.example.com/terms-of-service.html")
- .setPrivacyPolicyUrl("https://superapp.example.com/privacy-policy.html")
+ .setTosAndPrivacyPolicyUrls("https://superapp.example.com/terms-of-service.html",
+ "https://superapp.example.com/privacy-policy.html")
.build(),
RC_SIGN_IN);
```
@@ -291,6 +395,7 @@ startActivityForResult(
##### Phone number authentication customization
+###### Setting a default phone number
When using the phone verification provider and the number is known in advance, it is possible to
provide a default phone number (in international format) that will be used to prepopulate the
country code and phone number input fields. The user is still able to edit the number if desired.
@@ -301,7 +406,7 @@ IdpConfig phoneConfigWithDefaultNumber = new IdpConfig.PhoneBuilder()
.build();
```
-Alternatively, you can set only the default phone number country.
+Alternatively, you can set the default country (alpha-2 format) to be shown in the country selector.
```java
IdpConfig phoneConfigWithDefaultNumber = new IdpConfig.PhoneBuilder()
@@ -319,6 +424,50 @@ IdpConfig phoneConfigWithDefaultNumber = new IdpConfig.PhoneBuilder()
.build();
```
+###### Limiting the list of available countries in the country selector
+
+You can limit the countries shown in the country selector list. By default, all countries are shown.
+
+You can provide a list of countries to whitelist or blacklist. You can populate these lists with
+ISO (alpha-2) and E164 formatted country codes.
+
+```java
+List whitelistedCountries = new ArrayList();
+whitelistedCountries.add("+1");
+whitelistedCountries.add("gr");
+
+IdpConfig phoneConfigWithWhitelistedCountries = new IdpConfig.PhoneBuilder()
+ .setWhitelistedCountries(whitelistedCountries)
+ .build();
+```
+All countries with the country code +1 will be present in the selector as well as Greece ('gr').
+
+You may want to exclude a few countries from the list and avoid creating a whitelist with
+many countries. You can instead provide a list of countries to blacklist. By doing so, all countries
+excluding the ones you provide will be in the selector.
+
+```java
+List blacklistedCountries = new ArrayList();
+blacklistedCountries.add("+1");
+blacklistedCountries.add("gr");
+
+IdpConfig phoneConfigWithBlacklistedCountries = new IdpConfig.PhoneBuilder()
+ .setBlacklistedCountries(blacklistedCountries)
+ .build();
+```
+
+The country code selector will exclude all countries with a country code of +1 and Greece ('gr').
+
+Note: You can't provide both a list of countries to whitelist and blacklist. If you do, a runtime
+exception will be thrown.
+
+This change is purely UI based. We do not restrict users from signing in with their phone number.
+They will simply be unable to choose their country in the selector, but there may be another country
+sharing the same country code (e.g. US and CA are +1).
+
+
+#####
+
### Handling the sign-in response
#### Response codes
@@ -499,6 +648,87 @@ AuthUI.getInstance()
});
```
+### Upgrading anonymous users
+
+#### Enabling anonymous user upgrade
+
+When an anonymous user signs in or signs up with a permanent account, you want
+to be sure that the user can continue with what they were doing before signing up.
+For example, an anonymous user might have items in their shopping cart.
+At check-out, you prompt the user to sign in or sign up. After the user is
+signed in, the user's shopping cart should contain any items the user added
+while signed in anonymously.
+
+To support this behavior, FirebaseUI makes it easy to "upgrade" an anonymous
+account to a permanent account. To do so, simply call `enableAnonymousUsersAutoUpgrade()`
+when you configure the sign-in UI (this option is disabled by default).
+
+For example:
+```java
+startActivityForResult(
+ AuthUI.getInstance()
+ .createSignInIntentBuilder()
+ enableAnonymousUsersAutoUpgrade()
+ ...
+ .build(),
+ RC_SIGN_IN);
+```
+
+With this enabled, FirebaseUI will link the credential on sign-in with the anonymous account
+using Firebase Auth's `linkWithCredential` method:
+```java
+FirebaseAuth.getInstance().getCurrentUser().linkWithCredential(permanentCredential);
+```
+
+#### Handling anonymous user upgrade merge conflicts
+
+There is an issue when an anonymous user tries to upgrade to an existing Firebase user.
+
+For example, a user may have previously signed up with a Google credential on a different device.
+If they are signed in anonymously and they attempt to upgrade with the existing Google account,
+a `FirebaseAuthUserCollisionException` will be thrown by Firebase Auth as an existing user
+cannot be linked to another existing user. No two users can share the same credential. In this case,
+we need to merge the data from both users before we can upgrade the anonymous user.
+
+The process of storing the anonymous users data, signing in with the credential, and copying the
+data over to the existing account is left to the developer.
+
+When linking is unsuccessful due to user collision, an error with code
+`ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT` will be returned to `onActivityResult()`. A valid
+non-anonymous credential can be obtained from the `IdpResponse` via `getCredentialForLinking()`.
+
+**Example:**
+```java
+@Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == RC_SIGN_IN) {
+ IdpResponse response = IdpResponse.fromResultIntent(data);
+ if (resultCode == RESULT_OK) {
+ // Successful sign in
+ } else {
+ // Sign in failed
+ if (response.getError().getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
+ // Store relevant anonymous user data
+ ...
+ // Get the non-anoymous credential from the response
+ AuthCredential nonAnonymousCredential = response.getCredentialForLinking();
+ // Sign in with credential
+ FirebaseAuth.getInstance().signInWithCredential(nonAnonymousCredential);
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ // Copy over anonymous user data to signed in user
+ ...
+ }
+ });
+ }
+ }
+ updateUI();
+ }
+}
+```
+
### Authentication flow chart
The authentication flow implemented on Android is more complex than on other
@@ -600,7 +830,6 @@ By default, FirebaseUI requests the `email` and `profile` scopes when using Goog
would like to request additional scopes from the user, call `setScopes` on the
`AuthUI.IdpConfig.GoogleBuilder` when initializing FirebaseUI.
-
```java
// For a list of all scopes, see:
// https://developers.google.com/identity/protocols/googlescopes
@@ -616,7 +845,6 @@ startActivityForResult(
RC_SIGN_IN);
```
-
### Facebook
By default, FirebaseUI requests the `email` and `public_profile` permissions when initiating
@@ -642,3 +870,25 @@ startActivityForResult(
### Twitter
Twitter permissions can only be configured through [Twitter's developer console](https://apps.twitter.com/).
+
+### GitHub
+
+By default, FirebaseUI requests the `user:email` permission when performing OAuth. If you would like
+to request additional permissions from the user, call `setPermissions` on the
+`AuthUI.IdpConfig.GitHubBuilder` when initializing FirebaseUI.
+
+```java
+// For a list of permissions, see:
+// https://developer.github.com/apps/building-oauth-apps/scopes-for-oauth-apps/#available-scopes
+
+AuthUI.IdpConfig gitHubIdp = new AuthUI.IdpConfig.GitHubBuilder()
+ .setPermissions(Arrays.asList("gist"))
+ .build();
+
+startActivityForResult(
+ AuthUI.getInstance()
+ .createSignInIntentBuilder()
+ .setAvailableProviders(Arrays.asList(gitHubIdp, ...))
+ .build(),
+ RC_SIGN_IN);
+```
diff --git a/auth/auth-proguard.pro b/auth/auth-proguard.pro
index b358de6c6..5c8003466 100644
--- a/auth/auth-proguard.pro
+++ b/auth/auth-proguard.pro
@@ -19,5 +19,6 @@
# Retrofit config
-dontnote retrofit2.Platform
-dontwarn retrofit2.** # Also keeps Twitter at bay as long as they keep using Retrofit
+-dontwarn okhttp3.**
-dontwarn okio.**
-keepattributes Exceptions
diff --git a/auth/build.gradle.kts b/auth/build.gradle.kts
index aabc3d007..59b960bb3 100644
--- a/auth/build.gradle.kts
+++ b/auth/build.gradle.kts
@@ -1,3 +1,4 @@
+
import com.android.build.gradle.internal.dsl.TestOptions
android {
@@ -11,6 +12,7 @@ android {
lintOptions {
disable("UnusedQuantity")
+ disable("MissingTranslation") // TODO: Translate fui_auto_verified
}
testOptions {
@@ -38,7 +40,11 @@ dependencies {
implementation(Config.Libs.Support.customTabs)
compileOnly(Config.Libs.Provider.twitter) { isTransitive = true }
+ implementation(Config.Libs.Misc.retrofit)
+ implementation(Config.Libs.Misc.retrofitGson)
+
testImplementation(Config.Libs.Test.junit)
+ testImplementation(Config.Libs.Test.truth)
testImplementation(Config.Libs.Test.mockito)
testImplementation(Config.Libs.Test.robolectric)
testImplementation(Config.Libs.Provider.facebook)
diff --git a/auth/src/main/AndroidManifest.xml b/auth/src/main/AndroidManifest.xml
index 841702f93..a7db40d29 100644
--- a/auth/src/main/AndroidManifest.xml
+++ b/auth/src/main/AndroidManifest.xml
@@ -29,6 +29,36 @@
android:exported="false"
android:theme="@style/FirebaseUI.Transparent" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
(Arrays.asList(
GoogleAuthProvider.PROVIDER_ID,
FacebookAuthProvider.PROVIDER_ID,
- TwitterAuthProvider.PROVIDER_ID)));
+ TwitterAuthProvider.PROVIDER_ID,
+ GithubAuthProvider.PROVIDER_ID)));
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final String UNCONFIGURED_CONFIG_VALUE = "CHANGE-ME";
@@ -146,13 +147,7 @@ public final class AuthUI {
private AuthUI(FirebaseApp app) {
mApp = app;
-
- // TODO: This is a bad testing hack
- if (sDefaultAuth != null) {
- mAuth = sDefaultAuth;
- } else {
- mAuth = FirebaseAuth.getInstance(mApp);
- }
+ mAuth = FirebaseAuth.getInstance(mApp);
try {
mAuth.setFirebaseUIVersion(BuildConfig.VERSION_NAME);
@@ -214,9 +209,9 @@ public static int getDefaultTheme() {
* 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 configs to use for silent sign in. Only Google and email are currently
- * supported, the rest will be ignored.
+ * @param context requesting the user be signed in
+ * @param configs 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
@@ -593,6 +588,7 @@ public PhoneBuilder() {
public PhoneBuilder setDefaultNumber(@NonNull String number) {
Preconditions.checkUnset(getParams(),
"Cannot overwrite previously set phone number",
+ ExtraConstants.PHONE,
ExtraConstants.COUNTRY_ISO,
ExtraConstants.NATIONAL_NUMBER);
if (!PhoneNumberUtils.isValid(number)) {
@@ -615,7 +611,9 @@ public PhoneBuilder setDefaultNumber(@NonNull String number) {
public PhoneBuilder setDefaultNumber(@NonNull String iso, @NonNull String number) {
Preconditions.checkUnset(getParams(),
"Cannot overwrite previously set phone number",
- ExtraConstants.PHONE);
+ ExtraConstants.PHONE,
+ ExtraConstants.COUNTRY_ISO,
+ ExtraConstants.NATIONAL_NUMBER);
if (!PhoneNumberUtils.isValidIso(iso)) {
throw new IllegalStateException("Invalid country iso: " + iso);
}
@@ -643,10 +641,206 @@ public PhoneBuilder setDefaultCountryIso(@NonNull String iso) {
throw new IllegalStateException("Invalid country iso: " + iso);
}
- getParams().putString(ExtraConstants.COUNTRY_ISO, iso);
+ getParams().putString(ExtraConstants.COUNTRY_ISO,
+ iso.toUpperCase(Locale.getDefault()));
+
+ return this;
+ }
+
+
+ /**
+ * Sets the country codes available in the country code selector for phone
+ * authentication. Takes as input a List of both country isos and codes.
+ * This is not to be called with
+ * {@link #setBlacklistedCountries(List)}.
+ * If both are called, an exception will be thrown.
+ *
+ * Inputting an e-164 country code (e.g. '+1') will include all countries with
+ * +1 as its code.
+ * Example input: {'+52', 'us'}
+ * For a list of country iso or codes, see Alpha-2 isos here:
+ * https://en.wikipedia.org/wiki/ISO_3166-1
+ * and e-164 codes here: https://en.wikipedia.org/wiki/List_of_country_calling_codes
+ *
+ * @param whitelistedCountries a non empty case insensitive list of country codes
+ * and/or isos to be whitelisted
+ * @throws IllegalArgumentException if an empty whitelist is provided.
+ * @throws NullPointerException if a null whitelist is provided.
+ */
+ public PhoneBuilder setWhitelistedCountries(
+ @NonNull List whitelistedCountries) {
+ if (getParams().containsKey(ExtraConstants.BLACKLISTED_COUNTRIES)) {
+ throw new IllegalStateException(
+ "You can either whitelist or blacklist country codes for phone " +
+ "authentication.");
+ }
+
+ String message = "Invalid argument: Only non-%s whitelists are valid. " +
+ "To specify no whitelist, do not call this method.";
+ Preconditions.checkNotNull(whitelistedCountries, String.format(message, "null"));
+ Preconditions.checkArgument(!whitelistedCountries.isEmpty(), String.format(message, "empty"));
+
+ addCountriesToBundle(whitelistedCountries, ExtraConstants.WHITELISTED_COUNTRIES);
+ return this;
+ }
+
+ /**
+ * Sets the countries to be removed from the country code selector for phone
+ * authentication. Takes as input a List of both country isos and codes.
+ * This is not to be called with
+ * {@link #setWhitelistedCountries(List)}.
+ * If both are called, an exception will be thrown.
+ *
+ * Inputting an e-164 country code (e.g. '+1') will include all countries with
+ * +1 as its code.
+ * Example input: {'+52', 'us'}
+ * For a list of country iso or codes, see Alpha-2 codes here:
+ * https://en.wikipedia.org/wiki/ISO_3166-1
+ * and e-164 codes here: https://en.wikipedia.org/wiki/List_of_country_calling_codes
+ *
+ * @param blacklistedCountries a non empty case insensitive list of country codes
+ * and/or isos to be blacklisted
+ * @throws IllegalArgumentException if an empty blacklist is provided.
+ * @throws NullPointerException if a null blacklist is provided.
+ */
+ public PhoneBuilder setBlacklistedCountries(
+ @NonNull List blacklistedCountries) {
+ if (getParams().containsKey(ExtraConstants.WHITELISTED_COUNTRIES)) {
+ throw new IllegalStateException(
+ "You can either whitelist or blacklist country codes for phone " +
+ "authentication.");
+ }
+
+ String message = "Invalid argument: Only non-%s blacklists are valid. " +
+ "To specify no blacklist, do not call this method.";
+ Preconditions.checkNotNull(blacklistedCountries, String.format(message, "null"));
+ Preconditions.checkArgument(!blacklistedCountries.isEmpty(), String.format(message, "empty"));
+ addCountriesToBundle(blacklistedCountries, ExtraConstants.BLACKLISTED_COUNTRIES);
return this;
}
+
+ @Override
+ public IdpConfig build() {
+ validateInputs();
+ return super.build();
+ }
+
+ private void addCountriesToBundle(List CountryIsos, String CountryIsoType) {
+ ArrayList uppercaseCodes = new ArrayList<>();
+ for (String code : CountryIsos) {
+ uppercaseCodes.add(code.toUpperCase(Locale.getDefault()));
+ }
+
+ getParams().putStringArrayList(CountryIsoType, uppercaseCodes);
+ }
+
+ private void validateInputs() {
+ List whitelistedCountries = getParams().getStringArrayList(
+ ExtraConstants.WHITELISTED_COUNTRIES);
+ List blacklistedCountries = getParams().getStringArrayList(
+ ExtraConstants.BLACKLISTED_COUNTRIES);
+
+ if (whitelistedCountries != null &&
+ blacklistedCountries != null) {
+ throw new IllegalStateException(
+ "You can either whitelist or blacklist country codes for phone " +
+ "authentication.");
+ } else if (whitelistedCountries != null) {
+ validateInputs(whitelistedCountries, true);
+
+ } else if (blacklistedCountries != null) {
+ validateInputs(blacklistedCountries, false);
+ }
+ }
+
+ private void validateInputs(List countries, boolean whitelisted) {
+ validateCountryInput(countries);
+ validateDefaultCountryInput(countries, whitelisted);
+ }
+
+ private void validateCountryInput(List codes) {
+ for (String code : codes) {
+ if (!PhoneNumberUtils.isValidIso(code) && !PhoneNumberUtils.isValid(code)) {
+ throw new IllegalArgumentException("Invalid input: You must provide a " +
+ "valid country iso (alpha-2) or code (e-164). e.g. 'us' or '+1'.");
+ }
+ }
+ }
+
+ private void validateDefaultCountryInput(List codes, boolean whitelisted) {
+ // A default iso/code can be set via #setDefaultCountryIso() or #setDefaultNumber()
+ if (getParams().containsKey(ExtraConstants.COUNTRY_ISO) ||
+ getParams().containsKey(ExtraConstants.PHONE)) {
+
+ if (!validateDefaultCountryIso(codes, whitelisted)
+ || !validateDefaultPhoneIsos(codes, whitelisted)) {
+ throw new IllegalArgumentException("Invalid default country iso. Make " +
+ "sure it is either part of the whitelisted list or that you "
+ + "haven't blacklisted it.");
+ }
+ }
+
+ }
+
+ private boolean validateDefaultCountryIso(List codes, boolean whitelisted) {
+ String defaultIso = getDefaultIso();
+ return isValidDefaultIso(codes, defaultIso, whitelisted);
+ }
+
+ private boolean validateDefaultPhoneIsos(List codes, boolean whitelisted) {
+ List phoneIsos = getPhoneIsosFromCode();
+ for (String iso : phoneIsos) {
+ if (isValidDefaultIso(codes, iso, whitelisted)) {
+ return true;
+ }
+ }
+ return phoneIsos.isEmpty();
+ }
+
+ private boolean isValidDefaultIso(List codes, String iso, boolean whitelisted) {
+ if (iso == null) return true;
+ boolean containsIso = containsCountryIso(codes, iso);
+ return containsIso && whitelisted || !containsIso && !whitelisted;
+
+ }
+
+ private boolean containsCountryIso(List codes, String iso) {
+ iso = iso.toUpperCase(Locale.getDefault());
+ for (String code : codes) {
+ if (PhoneNumberUtils.isValidIso(code)) {
+ if (code.equals(iso)) {
+ return true;
+ }
+ } else {
+ List isos = PhoneNumberUtils.getCountryIsosFromCountryCode(code);
+ if (isos.contains(iso)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private List getPhoneIsosFromCode() {
+ List isos = new ArrayList<>();
+ String phone = getParams().getString(ExtraConstants.PHONE);
+ if (phone != null && phone.startsWith("+")) {
+ String countryCode = "+" + PhoneNumberUtils.getPhoneNumber(phone)
+ .getCountryCode();
+ List isosToAdd = PhoneNumberUtils.
+ getCountryIsosFromCountryCode(countryCode);
+ if (isosToAdd != null) {
+ isos.addAll(isosToAdd);
+ }
+ }
+ return isos;
+ }
+
+ private String getDefaultIso() {
+ return getParams().containsKey(ExtraConstants.COUNTRY_ISO) ?
+ getParams().getString(ExtraConstants.COUNTRY_ISO) : null;
+ }
}
/**
@@ -679,8 +873,8 @@ public GoogleBuilder setScopes(@NonNull List scopes) {
}
/**
- * Set the {@link GoogleSignInOptions} to be used for Google sign-in. Standard options
- * like requesting the user's email will automatically be added.
+ * Set the {@link GoogleSignInOptions} to be used for Google sign-in. Standard
+ * options like requesting the user's email will automatically be added.
*
* @param options sign-in options
*/
@@ -768,6 +962,34 @@ public TwitterBuilder() {
R.string.twitter_consumer_secret);
}
}
+
+ /**
+ * {@link IdpConfig} builder for the GitHub provider.
+ */
+ public static final class GitHubBuilder extends Builder {
+ public GitHubBuilder() {
+ //noinspection deprecation taking a hit for the backcompat team
+ super(GithubAuthProvider.PROVIDER_ID);
+ Preconditions.checkConfigured(getApplicationContext(),
+ "GitHub provider unconfigured. Make sure to add your client id and secret." +
+ " See the docs for more info:" +
+ " https://github.com/firebase/FirebaseUI-Android/blob/master/auth/README.md#github",
+ R.string.firebase_web_host,
+ R.string.github_client_id,
+ R.string.github_client_secret);
+ }
+
+ /**
+ * Specifies the additional permissions to be requested. Available permissions can be
+ * found here.
+ */
+ @NonNull
+ public GitHubBuilder setPermissions(@NonNull List permissions) {
+ getParams().putStringArrayList(
+ ExtraConstants.GITHUB_PERMISSIONS, new ArrayList<>(permissions));
+ return this;
+ }
+ }
}
/**
@@ -784,8 +1006,8 @@ private abstract class AuthIntentBuilder {
boolean mEnableHints = true;
/**
- * Specifies the theme to use for the application flow. If no theme is specified, a default
- * theme will be used.
+ * Specifies the theme to use for the application flow. If no theme is specified, a
+ * default theme will be used.
*/
@NonNull
public T setTheme(@StyleRes int theme) {
@@ -808,8 +1030,12 @@ public T setLogo(@DrawableRes int logo) {
/**
* Specifies the terms-of-service URL for the application.
+ *
+ * @deprecated Please use {@link #setTosAndPrivacyPolicyUrls(String, String)} For the Tos
+ * link to be displayed a Privacy Policy url must also be provided.
*/
@NonNull
+ @Deprecated
public T setTosUrl(@Nullable String tosUrl) {
mTosUrl = tosUrl;
return (T) this;
@@ -817,16 +1043,30 @@ public T setTosUrl(@Nullable String tosUrl) {
/**
* Specifies the privacy policy URL for the application.
+ *
+ * @deprecated Please use {@link #setTosAndPrivacyPolicyUrls(String, String)} For the
+ * Privacy Policy link to be displayed a Tos url must also be provided.
*/
@NonNull
+ @Deprecated
public T setPrivacyPolicyUrl(@Nullable String privacyPolicyUrl) {
mPrivacyPolicyUrl = privacyPolicyUrl;
return (T) this;
}
+ @NonNull
+ public T setTosAndPrivacyPolicyUrls(@NonNull String tosUrl,
+ @NonNull String privacyPolicyUrl) {
+ Preconditions.checkNotNull(tosUrl, "tosUrl cannot be null");
+ Preconditions.checkNotNull(privacyPolicyUrl, "privacyPolicyUrl cannot be null");
+ mTosUrl = tosUrl;
+ mPrivacyPolicyUrl = privacyPolicyUrl;
+ return (T) this;
+ }
+
/**
- * Specified the set of supported authentication providers. At least one provider must be
- * specified. There may only be one instance of each provider.
+ * Specified the set of supported authentication providers. At least one provider must
+ * be specified. There may only be one instance of each provider.
*
*
If no providers are explicitly specified by calling this method, then the email
* provider is the default supported provider.
@@ -899,10 +1139,23 @@ public Intent build() {
* Builder for the intent to start the user authentication flow.
*/
public final class SignInIntentBuilder extends AuthIntentBuilder {
+
+ private boolean mEnableAnonymousUpgrade;
+
private SignInIntentBuilder() {
super();
}
+ /**
+ * Enables upgrading anonymous accounts to full accounts during the sign-in flow.
+ * This is disabled by default.
+ */
+ @NonNull
+ public SignInIntentBuilder enableAnonymousUsersAutoUpgrade() {
+ mEnableAnonymousUpgrade = true;
+ return this;
+ }
+
@Override
protected FlowParameters getFlowParams() {
return new FlowParameters(
@@ -913,7 +1166,8 @@ protected FlowParameters getFlowParams() {
mTosUrl,
mPrivacyPolicyUrl,
mEnableCredentials,
- mEnableHints);
+ mEnableHints,
+ mEnableAnonymousUpgrade);
}
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java b/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java
index f49a714bd..fca246ac4 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ErrorCodes.java
@@ -19,7 +19,9 @@ public final class ErrorCodes {
NO_NETWORK,
PLAY_SERVICES_UPDATE_CANCELLED,
DEVELOPER_ERROR,
- PROVIDER_ERROR
+ PROVIDER_ERROR,
+ ANONYMOUS_UPGRADE_MERGE_CONFLICT,
+ EMAIL_MISMATCH_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface Code {}
@@ -49,6 +51,17 @@ public final class ErrorCodes {
*/
public static final int PROVIDER_ERROR = 4;
+ /**
+ * Anonymous account linking failed.
+ */
+ public static final int ANONYMOUS_UPGRADE_MERGE_CONFLICT = 5;
+
+ /**
+ * Signing in with a different email in the WelcomeBackIdp flow.
+ */
+ public static final int EMAIL_MISMATCH_ERROR = 6;
+
+
private ErrorCodes() {
throw new AssertionError("No instance for you!");
}
@@ -67,6 +80,11 @@ public static String toFriendlyMessage(@Code int code) {
return "Developer error";
case PROVIDER_ERROR:
return "Provider error";
+ case ANONYMOUS_UPGRADE_MERGE_CONFLICT:
+ return "User account merge conflict";
+ case EMAIL_MISMATCH_ERROR:
+ return "You are are attempting to sign in a different email than previously " +
+ "provided";
default:
throw new IllegalArgumentException("Unknown code: " + code);
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java
new file mode 100644
index 000000000..7f859f4a8
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthAnonymousUpgradeException.java
@@ -0,0 +1,21 @@
+package com.firebase.ui.auth;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class FirebaseAuthAnonymousUpgradeException extends Exception {
+
+ private IdpResponse mResponse;
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public FirebaseAuthAnonymousUpgradeException(@ErrorCodes.Code int code,
+ @NonNull IdpResponse response) {
+ super(ErrorCodes.toFriendlyMessage(code));
+ mResponse = response;
+ }
+
+ public IdpResponse getResponse() {
+ return mResponse;
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java b/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java
index 509eed06e..18157aa5b 100644
--- a/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java
+++ b/auth/src/main/java/com/firebase/ui/auth/IdpResponse.java
@@ -24,6 +24,8 @@
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.util.ExtraConstants;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
@@ -42,7 +44,9 @@ public IdpResponse createFromParcel(Parcel in) {
in.readParcelable(User.class.getClassLoader()),
in.readString(),
in.readString(),
- (FirebaseUiException) in.readSerializable()
+ in.readInt() == 1,
+ (FirebaseUiException) in.readSerializable(),
+ in.readParcelable(AuthCredential.class.getClassLoader())
);
}
@@ -53,32 +57,43 @@ public IdpResponse[] newArray(int size) {
};
private final User mUser;
+ private final AuthCredential mPendingCredential;
private final String mToken;
private final String mSecret;
+ private final boolean mIsNewUser;
private final FirebaseUiException mException;
private IdpResponse(@NonNull FirebaseUiException e) {
- this(null, null, null, e);
+ this(null, null, null, false, e, null);
}
private IdpResponse(
@NonNull User user,
@Nullable String token,
- @Nullable String secret) {
- this(user, token, secret, null);
+ @Nullable String secret,
+ boolean isNewUser) {
+ this(user, token, secret, isNewUser, null, null);
+ }
+
+ private IdpResponse(AuthCredential credential, FirebaseUiException e) {
+ this(null, null, null, false, e, credential);
}
private IdpResponse(
User user,
String token,
String secret,
- FirebaseUiException e) {
+ boolean isNewUser,
+ FirebaseUiException e,
+ AuthCredential credential) {
mUser = user;
mToken = token;
mSecret = secret;
+ mIsNewUser = isNewUser;
mException = e;
+ mPendingCredential = credential;
}
/**
@@ -96,6 +111,12 @@ public static IdpResponse fromResultIntent(@Nullable Intent resultIntent) {
}
}
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public IdpResponse withResult(AuthResult result) {
+ return mutate().setNewUser(result.getAdditionalUserInfo().isNewUser()).build();
+ }
+
@NonNull
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static IdpResponse from(@NonNull Exception e) {
@@ -120,6 +141,15 @@ public Intent toIntent() {
return new Intent().putExtra(ExtraConstants.IDP_RESPONSE, this);
}
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public Builder mutate() {
+ if (!isSuccessful()) {
+ throw new IllegalStateException("Cannot mutate an unsuccessful response.");
+ }
+ return new Builder(this);
+ }
+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public boolean isSuccessful() {
return mException == null;
@@ -139,6 +169,13 @@ public String getProviderType() {
return mUser.getProviderId();
}
+ /**
+ * Returns true if this user has just signed up, false otherwise.
+ */
+ public boolean isNewUser() {
+ return mIsNewUser;
+ }
+
/**
* Get the email used to sign in.
*/
@@ -179,6 +216,11 @@ public FirebaseUiException getError() {
return mException;
}
+ @Nullable
+ public AuthCredential getCredentialForLinking() {
+ return mPendingCredential;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -189,6 +231,7 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mUser, flags);
dest.writeString(mToken);
dest.writeString(mSecret);
+ dest.writeInt(mIsNewUser ? 1 : 0);
ObjectOutputStream oos = null;
try {
@@ -212,6 +255,8 @@ public void writeToParcel(Parcel dest, int flags) {
} catch (IOException ignored) {}
}
}
+
+ dest.writeParcelable(mPendingCredential, 0);
}
@Override
@@ -224,7 +269,10 @@ public boolean equals(Object o) {
return (mUser == null ? response.mUser == null : mUser.equals(response.mUser))
&& (mToken == null ? response.mToken == null : mToken.equals(response.mToken))
&& (mSecret == null ? response.mSecret == null : mSecret.equals(response.mSecret))
- && (mException == null ? response.mException == null : mException.equals(response.mException));
+ && (mIsNewUser == response.mIsNewUser)
+ && (mException == null ? response.mException == null : mException.equals(response.mException))
+ && (mPendingCredential == null ? response.mPendingCredential == null :
+ mPendingCredential.getProvider().equals(response.mPendingCredential.getProvider()));
}
@Override
@@ -232,7 +280,9 @@ public int hashCode() {
int result = mUser == null ? 0 : mUser.hashCode();
result = 31 * result + (mToken == null ? 0 : mToken.hashCode());
result = 31 * result + (mSecret == null ? 0 : mSecret.hashCode());
+ result = 31 * result + (mIsNewUser ? 1 : 0);
result = 31 * result + (mException == null ? 0 : mException.hashCode());
+ result = 31 * result + (mPendingCredential == null ? 0 : mPendingCredential.getProvider().hashCode());
return result;
}
@@ -242,19 +292,42 @@ public String toString() {
"mUser=" + mUser +
", mToken='" + mToken + '\'' +
", mSecret='" + mSecret + '\'' +
+ ", mIsNewUser='" + mIsNewUser + '\'' +
", mException=" + mException +
+ ", mPendingCredential=" + mPendingCredential +
'}';
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static class Builder {
private final User mUser;
+ private final AuthCredential mPendingCredential;
private String mToken;
private String mSecret;
+ private boolean mIsNewUser;
public Builder(@NonNull User user) {
mUser = user;
+ mPendingCredential = null;
+ }
+
+ public Builder(@NonNull AuthCredential pendingCredential) {
+ mUser = null;
+ mPendingCredential = pendingCredential;
+ }
+
+ public Builder(@NonNull IdpResponse response) {
+ mUser = response.mUser;
+ mToken = response.mToken;
+ mSecret = response.mSecret;
+ mIsNewUser = response.mIsNewUser;
+ mPendingCredential = response.mPendingCredential;
+ }
+
+ public Builder setNewUser(boolean newUser) {
+ mIsNewUser = newUser;
+ return this;
}
public Builder setToken(String token) {
@@ -268,6 +341,10 @@ public Builder setSecret(String secret) {
}
public IdpResponse build() {
+ if (mPendingCredential != null) {
+ return new IdpResponse(mPendingCredential, new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT));
+ }
+
String providerId = mUser.getProviderId();
if (!AuthUI.SUPPORTED_PROVIDERS.contains(providerId)) {
throw new IllegalStateException("Unknown provider: " + providerId);
@@ -281,8 +358,7 @@ public IdpResponse build() {
throw new IllegalStateException(
"Secret cannot be null when using the Twitter provider.");
}
-
- return new IdpResponse(mUser, mToken, mSecret);
+ return new IdpResponse(mUser, mToken, mSecret, mIsNewUser);
}
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java b/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java
index 27438e7c3..e1ad3104d 100644
--- a/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/KickoffActivity.java
@@ -13,6 +13,7 @@
import com.firebase.ui.auth.data.model.UserCancellationException;
import com.firebase.ui.auth.data.remote.SignInKickstarter;
import com.firebase.ui.auth.ui.InvisibleActivityBase;
+import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.viewmodel.ResourceObserver;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.tasks.OnFailureListener;
@@ -41,6 +42,9 @@ protected void onSuccess(@NonNull IdpResponse response) {
protected void onFailure(@NonNull Exception e) {
if (e instanceof UserCancellationException) {
finish(RESULT_CANCELED, null);
+ } else if (e instanceof FirebaseAuthAnonymousUpgradeException) {
+ IdpResponse res = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
+ finish(RESULT_CANCELED, new Intent().putExtra(ExtraConstants.IDP_RESPONSE, res));
} else {
finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e));
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/client/CountryListLoadTask.java b/auth/src/main/java/com/firebase/ui/auth/data/client/CountryListLoadTask.java
deleted file mode 100644
index d2c20589f..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/data/client/CountryListLoadTask.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2015 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Modifications copyright (C) 2017 Google Inc
- */
-
-package com.firebase.ui.auth.data.client;
-
-import android.os.AsyncTask;
-import android.support.annotation.RestrictTo;
-
-import com.firebase.ui.auth.data.model.CountryInfo;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
-// TODO We need to move away from ListView and AsyncTask in the future and use (say)
-// RecyclerView and Task/ThreadPoolExecutor .
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public final class CountryListLoadTask extends AsyncTask> {
-
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- public interface Listener {
- void onLoadComplete(List result);
- }
-
- private static final int MAX_COUNTRIES = 291;
-
- private final Listener mListener;
-
- public CountryListLoadTask(Listener listener) {
- mListener = listener;
- }
-
- @Override
- protected List doInBackground(Void... params) {
- final List countryInfoList = new ArrayList<>(MAX_COUNTRIES);
- countryInfoList.add(new CountryInfo(new Locale("", "AF"), 93));
- countryInfoList.add(new CountryInfo(new Locale("", "AX"), 358));
- countryInfoList.add(new CountryInfo(new Locale("", "AL"), 355));
- countryInfoList.add(new CountryInfo(new Locale("", "DZ"), 213));
- countryInfoList.add(new CountryInfo(new Locale("", "AS"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "AD"), 376));
- countryInfoList.add(new CountryInfo(new Locale("", "AO"), 244));
- countryInfoList.add(new CountryInfo(new Locale("", "AI"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "AG"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "AR"), 54));
- countryInfoList.add(new CountryInfo(new Locale("", "AM"), 374));
- countryInfoList.add(new CountryInfo(new Locale("", "AW"), 297));
- countryInfoList.add(new CountryInfo(new Locale("", "AC"), 247));
- countryInfoList.add(new CountryInfo(new Locale("", "AU"), 61));
- countryInfoList.add(new CountryInfo(new Locale("", "AT"), 43));
- countryInfoList.add(new CountryInfo(new Locale("", "AZ"), 994));
- countryInfoList.add(new CountryInfo(new Locale("", "BS"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "BH"), 973));
- countryInfoList.add(new CountryInfo(new Locale("", "BD"), 880));
- countryInfoList.add(new CountryInfo(new Locale("", "BB"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "BY"), 375));
- countryInfoList.add(new CountryInfo(new Locale("", "BE"), 32));
- countryInfoList.add(new CountryInfo(new Locale("", "BZ"), 501));
- countryInfoList.add(new CountryInfo(new Locale("", "BJ"), 229));
- countryInfoList.add(new CountryInfo(new Locale("", "BM"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "BT"), 975));
- countryInfoList.add(new CountryInfo(new Locale("", "BO"), 591));
- countryInfoList.add(new CountryInfo(new Locale("", "BA"), 387));
- countryInfoList.add(new CountryInfo(new Locale("", "BW"), 267));
- countryInfoList.add(new CountryInfo(new Locale("", "BR"), 55));
- countryInfoList.add(new CountryInfo(new Locale("", "IO"), 246));
- countryInfoList.add(new CountryInfo(new Locale("", "VG"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "BN"), 673));
- countryInfoList.add(new CountryInfo(new Locale("", "BG"), 359));
- countryInfoList.add(new CountryInfo(new Locale("", "BF"), 226));
- countryInfoList.add(new CountryInfo(new Locale("", "BI"), 257));
- countryInfoList.add(new CountryInfo(new Locale("", "KH"), 855));
- countryInfoList.add(new CountryInfo(new Locale("", "CM"), 237));
- countryInfoList.add(new CountryInfo(new Locale("", "CA"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "CV"), 238));
- countryInfoList.add(new CountryInfo(new Locale("", "BQ"), 599));
- countryInfoList.add(new CountryInfo(new Locale("", "KY"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "CF"), 236));
- countryInfoList.add(new CountryInfo(new Locale("", "TD"), 235));
- countryInfoList.add(new CountryInfo(new Locale("", "CL"), 56));
- countryInfoList.add(new CountryInfo(new Locale("", "CN"), 86));
- countryInfoList.add(new CountryInfo(new Locale("", "CX"), 61));
- countryInfoList.add(new CountryInfo(new Locale("", "CC"), 61));
- countryInfoList.add(new CountryInfo(new Locale("", "CO"), 57));
- countryInfoList.add(new CountryInfo(new Locale("", "KM"), 269));
- countryInfoList.add(new CountryInfo(new Locale("", "CD"), 243));
- countryInfoList.add(new CountryInfo(new Locale("", "CG"), 242));
- countryInfoList.add(new CountryInfo(new Locale("", "CK"), 682));
- countryInfoList.add(new CountryInfo(new Locale("", "CR"), 506));
- countryInfoList.add(new CountryInfo(new Locale("", "CI"), 225));
- countryInfoList.add(new CountryInfo(new Locale("", "HR"), 385));
- countryInfoList.add(new CountryInfo(new Locale("", "CU"), 53));
- countryInfoList.add(new CountryInfo(new Locale("", "CW"), 599));
- countryInfoList.add(new CountryInfo(new Locale("", "CY"), 357));
- countryInfoList.add(new CountryInfo(new Locale("", "CZ"), 420));
- countryInfoList.add(new CountryInfo(new Locale("", "DK"), 45));
- countryInfoList.add(new CountryInfo(new Locale("", "DJ"), 253));
- countryInfoList.add(new CountryInfo(new Locale("", "DM"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "DO"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "TL"), 670));
- countryInfoList.add(new CountryInfo(new Locale("", "EC"), 593));
- countryInfoList.add(new CountryInfo(new Locale("", "EG"), 20));
- countryInfoList.add(new CountryInfo(new Locale("", "SV"), 503));
- countryInfoList.add(new CountryInfo(new Locale("", "GQ"), 240));
- countryInfoList.add(new CountryInfo(new Locale("", "ER"), 291));
- countryInfoList.add(new CountryInfo(new Locale("", "EE"), 372));
- countryInfoList.add(new CountryInfo(new Locale("", "ET"), 251));
- countryInfoList.add(new CountryInfo(new Locale("", "FK"), 500));
- countryInfoList.add(new CountryInfo(new Locale("", "FO"), 298));
- countryInfoList.add(new CountryInfo(new Locale("", "FJ"), 679));
- countryInfoList.add(new CountryInfo(new Locale("", "FI"), 358));
- countryInfoList.add(new CountryInfo(new Locale("", "FR"), 33));
- countryInfoList.add(new CountryInfo(new Locale("", "GF"), 594));
- countryInfoList.add(new CountryInfo(new Locale("", "PF"), 689));
- countryInfoList.add(new CountryInfo(new Locale("", "GA"), 241));
- countryInfoList.add(new CountryInfo(new Locale("", "GM"), 220));
- countryInfoList.add(new CountryInfo(new Locale("", "GE"), 995));
- countryInfoList.add(new CountryInfo(new Locale("", "DE"), 49));
- countryInfoList.add(new CountryInfo(new Locale("", "GH"), 233));
- countryInfoList.add(new CountryInfo(new Locale("", "GI"), 350));
- countryInfoList.add(new CountryInfo(new Locale("", "GR"), 30));
- countryInfoList.add(new CountryInfo(new Locale("", "GL"), 299));
- countryInfoList.add(new CountryInfo(new Locale("", "GD"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "GP"), 590));
- countryInfoList.add(new CountryInfo(new Locale("", "GU"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "GT"), 502));
- countryInfoList.add(new CountryInfo(new Locale("", "GG"), 44));
- countryInfoList.add(new CountryInfo(new Locale("", "GN"), 224));
- countryInfoList.add(new CountryInfo(new Locale("", "GW"), 245));
- countryInfoList.add(new CountryInfo(new Locale("", "GY"), 592));
- countryInfoList.add(new CountryInfo(new Locale("", "HT"), 509));
- countryInfoList.add(new CountryInfo(new Locale("", "HM"), 672));
- countryInfoList.add(new CountryInfo(new Locale("", "HN"), 504));
- countryInfoList.add(new CountryInfo(new Locale("", "HK"), 852));
- countryInfoList.add(new CountryInfo(new Locale("", "HU"), 36));
- countryInfoList.add(new CountryInfo(new Locale("", "IS"), 354));
- countryInfoList.add(new CountryInfo(new Locale("", "IN"), 91));
- countryInfoList.add(new CountryInfo(new Locale("", "ID"), 62));
- countryInfoList.add(new CountryInfo(new Locale("", "IR"), 98));
- countryInfoList.add(new CountryInfo(new Locale("", "IQ"), 964));
- countryInfoList.add(new CountryInfo(new Locale("", "IE"), 353));
- countryInfoList.add(new CountryInfo(new Locale("", "IM"), 44));
- countryInfoList.add(new CountryInfo(new Locale("", "IL"), 972));
- countryInfoList.add(new CountryInfo(new Locale("", "IT"), 39));
- countryInfoList.add(new CountryInfo(new Locale("", "JM"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "JP"), 81));
- countryInfoList.add(new CountryInfo(new Locale("", "JE"), 44));
- countryInfoList.add(new CountryInfo(new Locale("", "JO"), 962));
- countryInfoList.add(new CountryInfo(new Locale("", "KZ"), 7));
- countryInfoList.add(new CountryInfo(new Locale("", "KE"), 254));
- countryInfoList.add(new CountryInfo(new Locale("", "KI"), 686));
- countryInfoList.add(new CountryInfo(new Locale("", "XK"), 381));
- countryInfoList.add(new CountryInfo(new Locale("", "KW"), 965));
- countryInfoList.add(new CountryInfo(new Locale("", "KG"), 996));
- countryInfoList.add(new CountryInfo(new Locale("", "LA"), 856));
- countryInfoList.add(new CountryInfo(new Locale("", "LV"), 371));
- countryInfoList.add(new CountryInfo(new Locale("", "LB"), 961));
- countryInfoList.add(new CountryInfo(new Locale("", "LS"), 266));
- countryInfoList.add(new CountryInfo(new Locale("", "LR"), 231));
- countryInfoList.add(new CountryInfo(new Locale("", "LY"), 218));
- countryInfoList.add(new CountryInfo(new Locale("", "LI"), 423));
- countryInfoList.add(new CountryInfo(new Locale("", "LT"), 370));
- countryInfoList.add(new CountryInfo(new Locale("", "LU"), 352));
- countryInfoList.add(new CountryInfo(new Locale("", "MO"), 853));
- countryInfoList.add(new CountryInfo(new Locale("", "MK"), 389));
- countryInfoList.add(new CountryInfo(new Locale("", "MG"), 261));
- countryInfoList.add(new CountryInfo(new Locale("", "MW"), 265));
- countryInfoList.add(new CountryInfo(new Locale("", "MY"), 60));
- countryInfoList.add(new CountryInfo(new Locale("", "MV"), 960));
- countryInfoList.add(new CountryInfo(new Locale("", "ML"), 223));
- countryInfoList.add(new CountryInfo(new Locale("", "MT"), 356));
- countryInfoList.add(new CountryInfo(new Locale("", "MH"), 692));
- countryInfoList.add(new CountryInfo(new Locale("", "MQ"), 596));
- countryInfoList.add(new CountryInfo(new Locale("", "MR"), 222));
- countryInfoList.add(new CountryInfo(new Locale("", "MU"), 230));
- countryInfoList.add(new CountryInfo(new Locale("", "YT"), 262));
- countryInfoList.add(new CountryInfo(new Locale("", "MX"), 52));
- countryInfoList.add(new CountryInfo(new Locale("", "FM"), 691));
- countryInfoList.add(new CountryInfo(new Locale("", "MD"), 373));
- countryInfoList.add(new CountryInfo(new Locale("", "MC"), 377));
- countryInfoList.add(new CountryInfo(new Locale("", "MN"), 976));
- countryInfoList.add(new CountryInfo(new Locale("", "ME"), 382));
- countryInfoList.add(new CountryInfo(new Locale("", "MS"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "MA"), 212));
- countryInfoList.add(new CountryInfo(new Locale("", "MZ"), 258));
- countryInfoList.add(new CountryInfo(new Locale("", "MM"), 95));
- countryInfoList.add(new CountryInfo(new Locale("", "NA"), 264));
- countryInfoList.add(new CountryInfo(new Locale("", "NR"), 674));
- countryInfoList.add(new CountryInfo(new Locale("", "NP"), 977));
- countryInfoList.add(new CountryInfo(new Locale("", "NL"), 31));
- countryInfoList.add(new CountryInfo(new Locale("", "NC"), 687));
- countryInfoList.add(new CountryInfo(new Locale("", "NZ"), 64));
- countryInfoList.add(new CountryInfo(new Locale("", "NI"), 505));
- countryInfoList.add(new CountryInfo(new Locale("", "NE"), 227));
- countryInfoList.add(new CountryInfo(new Locale("", "NG"), 234));
- countryInfoList.add(new CountryInfo(new Locale("", "NU"), 683));
- countryInfoList.add(new CountryInfo(new Locale("", "NF"), 672));
- countryInfoList.add(new CountryInfo(new Locale("", "KP"), 850));
- countryInfoList.add(new CountryInfo(new Locale("", "MP"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "NO"), 47));
- countryInfoList.add(new CountryInfo(new Locale("", "OM"), 968));
- countryInfoList.add(new CountryInfo(new Locale("", "PK"), 92));
- countryInfoList.add(new CountryInfo(new Locale("", "PW"), 680));
- countryInfoList.add(new CountryInfo(new Locale("", "PS"), 970));
- countryInfoList.add(new CountryInfo(new Locale("", "PA"), 507));
- countryInfoList.add(new CountryInfo(new Locale("", "PG"), 675));
- countryInfoList.add(new CountryInfo(new Locale("", "PY"), 595));
- countryInfoList.add(new CountryInfo(new Locale("", "PE"), 51));
- countryInfoList.add(new CountryInfo(new Locale("", "PH"), 63));
- countryInfoList.add(new CountryInfo(new Locale("", "PL"), 48));
- countryInfoList.add(new CountryInfo(new Locale("", "PT"), 351));
- countryInfoList.add(new CountryInfo(new Locale("", "PR"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "QA"), 974));
- countryInfoList.add(new CountryInfo(new Locale("", "RE"), 262));
- countryInfoList.add(new CountryInfo(new Locale("", "RO"), 40));
- countryInfoList.add(new CountryInfo(new Locale("", "RU"), 7));
- countryInfoList.add(new CountryInfo(new Locale("", "RW"), 250));
- countryInfoList.add(new CountryInfo(new Locale("", "BL"), 590));
- countryInfoList.add(new CountryInfo(new Locale("", "SH"), 290));
- countryInfoList.add(new CountryInfo(new Locale("", "KN"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "LC"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "MF"), 590));
- countryInfoList.add(new CountryInfo(new Locale("", "PM"), 508));
- countryInfoList.add(new CountryInfo(new Locale("", "VC"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "WS"), 685));
- countryInfoList.add(new CountryInfo(new Locale("", "SM"), 378));
- countryInfoList.add(new CountryInfo(new Locale("", "ST"), 239));
- countryInfoList.add(new CountryInfo(new Locale("", "SA"), 966));
- countryInfoList.add(new CountryInfo(new Locale("", "SN"), 221));
- countryInfoList.add(new CountryInfo(new Locale("", "RS"), 381));
- countryInfoList.add(new CountryInfo(new Locale("", "SC"), 248));
- countryInfoList.add(new CountryInfo(new Locale("", "SL"), 232));
- countryInfoList.add(new CountryInfo(new Locale("", "SG"), 65));
- countryInfoList.add(new CountryInfo(new Locale("", "SX"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "SK"), 421));
- countryInfoList.add(new CountryInfo(new Locale("", "SI"), 386));
- countryInfoList.add(new CountryInfo(new Locale("", "SB"), 677));
- countryInfoList.add(new CountryInfo(new Locale("", "SO"), 252));
- countryInfoList.add(new CountryInfo(new Locale("", "ZA"), 27));
- countryInfoList.add(new CountryInfo(new Locale("", "GS"), 500));
- countryInfoList.add(new CountryInfo(new Locale("", "KR"), 82));
- countryInfoList.add(new CountryInfo(new Locale("", "SS"), 211));
- countryInfoList.add(new CountryInfo(new Locale("", "ES"), 34));
- countryInfoList.add(new CountryInfo(new Locale("", "LK"), 94));
- countryInfoList.add(new CountryInfo(new Locale("", "SD"), 249));
- countryInfoList.add(new CountryInfo(new Locale("", "SR"), 597));
- countryInfoList.add(new CountryInfo(new Locale("", "SJ"), 47));
- countryInfoList.add(new CountryInfo(new Locale("", "SZ"), 268));
- countryInfoList.add(new CountryInfo(new Locale("", "SE"), 46));
- countryInfoList.add(new CountryInfo(new Locale("", "CH"), 41));
- countryInfoList.add(new CountryInfo(new Locale("", "SY"), 963));
- countryInfoList.add(new CountryInfo(new Locale("", "TW"), 886));
- countryInfoList.add(new CountryInfo(new Locale("", "TJ"), 992));
- countryInfoList.add(new CountryInfo(new Locale("", "TZ"), 255));
- countryInfoList.add(new CountryInfo(new Locale("", "TH"), 66));
- countryInfoList.add(new CountryInfo(new Locale("", "TG"), 228));
- countryInfoList.add(new CountryInfo(new Locale("", "TK"), 690));
- countryInfoList.add(new CountryInfo(new Locale("", "TO"), 676));
- countryInfoList.add(new CountryInfo(new Locale("", "TT"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "TN"), 216));
- countryInfoList.add(new CountryInfo(new Locale("", "TR"), 90));
- countryInfoList.add(new CountryInfo(new Locale("", "TM"), 993));
- countryInfoList.add(new CountryInfo(new Locale("", "TC"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "TV"), 688));
- countryInfoList.add(new CountryInfo(new Locale("", "VI"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "UG"), 256));
- countryInfoList.add(new CountryInfo(new Locale("", "UA"), 380));
- countryInfoList.add(new CountryInfo(new Locale("", "AE"), 971));
- countryInfoList.add(new CountryInfo(new Locale("", "GB"), 44));
- countryInfoList.add(new CountryInfo(new Locale("", "US"), 1));
- countryInfoList.add(new CountryInfo(new Locale("", "UY"), 598));
- countryInfoList.add(new CountryInfo(new Locale("", "UZ"), 998));
- countryInfoList.add(new CountryInfo(new Locale("", "VU"), 678));
- countryInfoList.add(new CountryInfo(new Locale("", "VA"), 379));
- countryInfoList.add(new CountryInfo(new Locale("", "VE"), 58));
- countryInfoList.add(new CountryInfo(new Locale("", "VN"), 84));
- countryInfoList.add(new CountryInfo(new Locale("", "WF"), 681));
- countryInfoList.add(new CountryInfo(new Locale("", "EH"), 212));
- countryInfoList.add(new CountryInfo(new Locale("", "YE"), 967));
- countryInfoList.add(new CountryInfo(new Locale("", "ZM"), 260));
- countryInfoList.add(new CountryInfo(new Locale("", "ZW"), 263));
- Collections.sort(countryInfoList);
- return countryInfoList;
- }
-
- @Override
- public void onPostExecute(List result) {
- if (mListener != null) {
- mListener.onLoadComplete(result);
- }
- }
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java b/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java
index be4063b69..4cde51957 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/model/FlowParameters.java
@@ -56,6 +56,7 @@ public class FlowParameters implements Parcelable {
public final boolean enableCredentials;
public final boolean enableHints;
+ public final boolean enableAnonymousUpgrade;
public FlowParameters(
@NonNull String appName,
@@ -65,7 +66,8 @@ public FlowParameters(
@Nullable String termsOfServiceUrl,
@Nullable String privacyPolicyUrl,
boolean enableCredentials,
- boolean enableHints) {
+ boolean enableHints,
+ boolean enableAnonymousUpgrade) {
this.appName = Preconditions.checkNotNull(appName, "appName cannot be null");
this.providerInfo = Collections.unmodifiableList(
Preconditions.checkNotNull(providerInfo, "providerInfo cannot be null"));
@@ -75,6 +77,7 @@ public FlowParameters(
this.privacyPolicyUrl = privacyPolicyUrl;
this.enableCredentials = enableCredentials;
this.enableHints = enableHints;
+ this.enableAnonymousUpgrade = enableAnonymousUpgrade;
}
/**
@@ -94,6 +97,7 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeString(privacyPolicyUrl);
dest.writeInt(enableCredentials ? 1 : 0);
dest.writeInt(enableHints ? 1 : 0);
+ dest.writeInt(enableAnonymousUpgrade ? 1 : 0);
}
@Override
@@ -112,6 +116,7 @@ public FlowParameters createFromParcel(Parcel in) {
String privacyPolicyUrl = in.readString();
boolean enableCredentials = in.readInt() != 0;
boolean enableHints = in.readInt() != 0;
+ boolean enableAnonymousUpgrade = in.readInt() != 0;
return new FlowParameters(
appName,
@@ -121,7 +126,8 @@ public FlowParameters createFromParcel(Parcel in) {
termsOfServiceUrl,
privacyPolicyUrl,
enableCredentials,
- enableHints);
+ enableHints,
+ enableAnonymousUpgrade);
}
@Override
@@ -141,4 +147,8 @@ public boolean isTermsOfServiceUrlProvided() {
public boolean isPrivacyPolicyUrlProvided() {
return !TextUtils.isEmpty(privacyPolicyUrl);
}
+
+ public boolean isAnonymousUpgradeEnabled() {
+ return enableAnonymousUpgrade;
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/model/GitHubProfile.java b/auth/src/main/java/com/firebase/ui/auth/data/model/GitHubProfile.java
new file mode 100644
index 000000000..5723533e5
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/data/model/GitHubProfile.java
@@ -0,0 +1,76 @@
+package com.firebase.ui.auth.data.model;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import com.google.gson.annotations.SerializedName;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class GitHubProfile {
+ @SerializedName("email") private String mEmail;
+ @SerializedName("name") private String mName;
+ @SerializedName("avatar_url") private String mAvatarUrl;
+
+ @NonNull
+ public String getEmail() {
+ return mEmail;
+ }
+
+ public void setEmail(@NonNull String email) {
+ mEmail = email;
+ }
+
+ @Nullable
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(@Nullable String name) {
+ mName = name;
+ }
+
+ @Nullable
+ public String getAvatarUrl() {
+ return mAvatarUrl;
+ }
+
+ @Nullable
+ public Uri getAvatarUri() {
+ return mAvatarUrl == null ? null : Uri.parse(mAvatarUrl);
+ }
+
+ public void setAvatarUrl(@Nullable String avatarUrl) {
+ mAvatarUrl = avatarUrl;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ GitHubProfile profile = (GitHubProfile) o;
+
+ return mEmail.equals(profile.mEmail)
+ && (mName == null ? profile.mName == null : mName.equals(profile.mName))
+ && (mAvatarUrl == null ? profile.mAvatarUrl == null : mAvatarUrl.equals(profile.mAvatarUrl));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mEmail.hashCode();
+ result = 31 * result + (mName == null ? 0 : mName.hashCode());
+ result = 31 * result + (mAvatarUrl == null ? 0 : mAvatarUrl.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "GitHubProfile{" +
+ "mEmail='" + mEmail + '\'' +
+ ", mName='" + mName + '\'' +
+ ", mAvatarUrl='" + mAvatarUrl + '\'' +
+ '}';
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/model/GitHubTokenResponse.java b/auth/src/main/java/com/firebase/ui/auth/data/model/GitHubTokenResponse.java
new file mode 100644
index 000000000..a50ebc612
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/data/model/GitHubTokenResponse.java
@@ -0,0 +1,70 @@
+package com.firebase.ui.auth.data.model;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import com.google.gson.annotations.SerializedName;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class GitHubTokenResponse {
+ @SerializedName("access_token") private String mToken;
+ @SerializedName("token_type") private String mType;
+ @SerializedName("scope") private String mScope;
+
+ @NonNull
+ public String getToken() {
+ return mToken;
+ }
+
+ public void setToken(@NonNull String token) {
+ mToken = token;
+ }
+
+ @NonNull
+ public String getType() {
+ return mType;
+ }
+
+ public void setType(@NonNull String type) {
+ mType = type;
+ }
+
+ @Nullable
+ public String getScope() {
+ return mScope;
+ }
+
+ public void setScope(@Nullable String scope) {
+ mScope = scope;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ GitHubTokenResponse response = (GitHubTokenResponse) o;
+
+ return mToken.equals(response.mToken)
+ && (mType == null ? response.mType == null : mType.equals(response.mType))
+ && (mScope == null ? response.mScope == null : mScope.equals(response.mScope));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mToken.hashCode();
+ result = 31 * result + (mType == null ? 0 : mType.hashCode());
+ result = 31 * result + (mScope == null ? 0 : mScope.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "GitHubTokenResponse{" +
+ "mToken='" + mToken + '\'' +
+ ", mType='" + mType + '\'' +
+ ", mScope='" + mScope + '\'' +
+ '}';
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/model/PhoneNumberVerificationRequiredException.java b/auth/src/main/java/com/firebase/ui/auth/data/model/PhoneNumberVerificationRequiredException.java
new file mode 100644
index 000000000..7138df24f
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/data/model/PhoneNumberVerificationRequiredException.java
@@ -0,0 +1,32 @@
+package com.firebase.ui.auth.data.model;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseUiException;
+
+/**
+ * Represents an error in which the phone number couldn't be automatically verified and must
+ * therefore be manually verified by the client by sending an SMS code.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class PhoneNumberVerificationRequiredException extends FirebaseUiException {
+ private final String mPhoneNumber;
+
+ /**
+ * @param number the phone number requiring verification, formatted with a country code prefix
+ */
+ public PhoneNumberVerificationRequiredException(@NonNull String number) {
+ super(ErrorCodes.PROVIDER_ERROR, "Phone number requires verification.");
+ mPhoneNumber = number;
+ }
+
+ /**
+ * @return the phone number requiring verification
+ */
+ @NonNull
+ public String getPhoneNumber() {
+ return mPhoneNumber;
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java
index 8d1511380..67c8d5fd3 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/EmailSignInHandler.java
@@ -6,13 +6,14 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
+import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.Resource;
import com.firebase.ui.auth.data.model.UserCancellationException;
import com.firebase.ui.auth.ui.HelperActivityBase;
import com.firebase.ui.auth.ui.email.EmailActivity;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.RequestCodes;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class EmailSignInHandler extends ProviderSignInBase {
@@ -29,7 +30,9 @@ public void startSignIn(@NonNull HelperActivityBase activity) {
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
- if (requestCode == RequestCodes.EMAIL_FLOW) {
+ if (resultCode == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
+ // The activity deals with this case. This conflict is handled by the developer.
+ } else if (requestCode == RequestCodes.EMAIL_FLOW) {
IdpResponse response = IdpResponse.fromResultIntent(data);
if (response == null) {
setResult(Resource.forFailure(new UserCancellationException()));
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/FacebookSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/FacebookSignInHandler.java
index 5e2d0f366..92ee04327 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/FacebookSignInHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/FacebookSignInHandler.java
@@ -25,7 +25,7 @@
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.ui.HelperActivityBase;
import com.firebase.ui.auth.util.ExtraConstants;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.google.firebase.auth.FacebookAuthProvider;
import org.json.JSONException;
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/GitHubSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/GitHubSignInHandler.java
new file mode 100644
index 000000000..8498f5b49
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/GitHubSignInHandler.java
@@ -0,0 +1,179 @@
+package com.firebase.ui.auth.data.remote;
+
+import android.app.Application;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
+
+import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseUiException;
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.R;
+import com.firebase.ui.auth.data.model.GitHubProfile;
+import com.firebase.ui.auth.data.model.GitHubTokenResponse;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.data.model.User;
+import com.firebase.ui.auth.data.model.UserCancellationException;
+import com.firebase.ui.auth.ui.HelperActivityBase;
+import com.firebase.ui.auth.ui.provider.GitHubLoginActivity;
+import com.firebase.ui.auth.util.ExtraConstants;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
+import com.firebase.ui.auth.viewmodel.RequestCodes;
+import com.google.firebase.auth.GithubAuthProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class GitHubSignInHandler extends ProviderSignInBase
+ implements Callback {
+ public static final String RESULT_CODE = "result_code";
+ public static final String KEY_GITHUB_CODE = "github_code";
+
+ private static final String SCHEME = "https";
+ private static final String AUTHORITY = "github.com";
+ private static final String OAUTH = "login/oauth";
+ private static final GitHubOAuth RETROFIT_GITHUB_OAUTH = new Retrofit.Builder()
+ .baseUrl(SCHEME + "://" + AUTHORITY + "/" + OAUTH + "/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(GitHubOAuth.class);
+ private static final GitHubApi RETROFIT_GITHUB = new Retrofit.Builder()
+ .baseUrl(SCHEME + "://api." + AUTHORITY + "/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(GitHubApi.class);
+
+ private static final String EMAIL_PERMISSION = "user:email";
+
+ private List mPermissions;
+
+ public GitHubSignInHandler(Application application) {
+ super(application);
+ }
+
+ private static IdpResponse createIdpResponse(
+ @NonNull String token,
+ @NonNull GitHubProfile profile) {
+ return new IdpResponse.Builder(
+ new User.Builder(GithubAuthProvider.PROVIDER_ID, profile.getEmail())
+ .setName(profile.getName())
+ .setPhotoUri(profile.getAvatarUri())
+ .build())
+ .setToken(token)
+ .build();
+ }
+
+ @Override
+ protected void onCreate() {
+ List permissions = new ArrayList<>(getArguments().getParams()
+ .getStringArrayList(ExtraConstants.GITHUB_PERMISSIONS));
+ if (!permissions.contains(EMAIL_PERMISSION)) {
+ permissions.add(EMAIL_PERMISSION);
+ }
+ mPermissions = permissions;
+ }
+
+ @Override
+ public void startSignIn(@NonNull HelperActivityBase activity) {
+ activity.startActivityForResult(GitHubLoginActivity.createIntent(activity,
+ new Uri.Builder().scheme(SCHEME)
+ .authority(AUTHORITY)
+ .path(OAUTH + "/authorize")
+ .appendQueryParameter("client_id",
+ getApplication().getString(R.string.github_client_id))
+ .appendQueryParameter("scope", TextUtils.join(",", mPermissions))
+ .build()),
+ RequestCodes.GITHUB_PROVIDER);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (requestCode != RequestCodes.GITHUB_PROVIDER) { return; }
+
+ if (data == null) {
+ setResult(Resource.forFailure(new UserCancellationException()));
+ return;
+ }
+
+ if (data.hasExtra(KEY_GITHUB_CODE)) {
+ setResult(Resource.forLoading());
+ RETROFIT_GITHUB_OAUTH.getAuthToken(
+ "application/json",
+ getApplication().getString(R.string.github_client_id),
+ getApplication().getString(R.string.github_client_secret),
+ data.getStringExtra(KEY_GITHUB_CODE)
+ ).enqueue(this);
+ } else {
+ setResult(Resource.forFailure(new FirebaseUiException(ErrorCodes.PROVIDER_ERROR)));
+ }
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful()) {
+ String token = response.body().getToken();
+ RETROFIT_GITHUB.getUser("token " + token).enqueue(new ProfileRequest(token));
+ } else {
+ setResult(Resource.forFailure(new FirebaseUiException(
+ ErrorCodes.PROVIDER_ERROR, response.message())));
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable throwable) {
+ setResult(Resource.forFailure(
+ new FirebaseUiException(ErrorCodes.PROVIDER_ERROR, throwable)));
+ }
+
+ private final class ProfileRequest implements Callback {
+ private final String mToken;
+
+ public ProfileRequest(String token) {
+ mToken = token;
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful()) {
+ setResult(Resource.forSuccess(createIdpResponse(mToken, response.body())));
+ } else {
+ onFailure(call, new FirebaseUiException(
+ ErrorCodes.PROVIDER_ERROR, response.message()));
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable throwable) {
+ // Ignore profile request failures since we can still sign in
+ setResult(Resource.forSuccess(createIdpResponse(mToken, new GitHubProfile())));
+ }
+ }
+
+ private interface GitHubOAuth {
+ @POST("access_token")
+ Call getAuthToken(@Header("Accept") String header,
+ @Query("client_id") String id,
+ @Query("client_secret") String secret,
+ @Query("code") String code);
+ }
+
+ private interface GitHubApi {
+ @GET("user")
+ Call getUser(@Header("Authorization") String token);
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/GoogleSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/GoogleSignInHandler.java
index 8b11a39c3..bc8f62cfe 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/GoogleSignInHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/GoogleSignInHandler.java
@@ -17,8 +17,8 @@
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.ui.HelperActivityBase;
import com.firebase.ui.auth.util.ExtraConstants;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.RequestCodes;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
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;
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/PhoneSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/PhoneSignInHandler.java
index 13ed4b254..b7fddc851 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/PhoneSignInHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/PhoneSignInHandler.java
@@ -12,8 +12,8 @@
import com.firebase.ui.auth.data.model.UserCancellationException;
import com.firebase.ui.auth.ui.HelperActivityBase;
import com.firebase.ui.auth.ui.phone.PhoneActivity;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.RequestCodes;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class PhoneSignInHandler extends ProviderSignInBase {
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java
index e8925c76a..5a6826576 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/SignInKickstarter.java
@@ -3,11 +3,13 @@
import android.app.Activity;
import android.app.Application;
import android.content.Intent;
+import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.IntentRequiredException;
import com.firebase.ui.auth.data.model.PendingIntentRequiredException;
@@ -18,10 +20,11 @@
import com.firebase.ui.auth.ui.idp.AuthMethodPickerActivity;
import com.firebase.ui.auth.ui.idp.SingleSignInActivity;
import com.firebase.ui.auth.ui.phone.PhoneActivity;
+import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.GoogleApiUtils;
import com.firebase.ui.auth.util.data.ProviderUtils;
-import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
import com.firebase.ui.auth.viewmodel.RequestCodes;
+import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
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;
@@ -37,6 +40,7 @@
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseAuthInvalidUserException;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
@@ -44,7 +48,7 @@
import java.util.ArrayList;
import java.util.List;
-public class SignInKickstarter extends AuthViewModelBase {
+public class SignInKickstarter extends SignInViewModelBase {
public SignInKickstarter(Application application) {
super(application);
}
@@ -118,21 +122,32 @@ private void startAuthMethodChoice() {
}
}
- private void redirectSignIn(String provider, String email) {
+ private void redirectSignIn(String provider, String id) {
switch (provider) {
case EmailAuthProvider.PROVIDER_ID:
setResult(Resource.forFailure(new IntentRequiredException(
- EmailActivity.createIntent(getApplication(), getArguments(), email),
+ EmailActivity.createIntent(getApplication(), getArguments(), id),
RequestCodes.EMAIL_FLOW)));
break;
+ case PhoneAuthProvider.PROVIDER_ID:
+ Bundle args = new Bundle();
+ args.putString(ExtraConstants.PHONE, id);
+ setResult(Resource.forFailure(new IntentRequiredException(
+ PhoneActivity.createIntent(
+ getApplication(),
+ getArguments(),
+ args),
+ RequestCodes.PHONE_FLOW)));
+ break;
case GoogleAuthProvider.PROVIDER_ID:
case FacebookAuthProvider.PROVIDER_ID:
case TwitterAuthProvider.PROVIDER_ID:
+ case GithubAuthProvider.PROVIDER_ID:
setResult(Resource.forFailure(new IntentRequiredException(
SingleSignInActivity.createIntent(
getApplication(),
getArguments(),
- new User.Builder(provider, email).build()),
+ new User.Builder(provider, id).build()),
RequestCodes.PROVIDER_FLOW)));
break;
default:
@@ -169,6 +184,9 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
setResult(Resource.forFailure(new UserCancellationException()));
} else if (response.isSuccessful()) {
setResult(Resource.forSuccess(response));
+ } else if (response.getError().getErrorCode() ==
+ ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
+ handleMergeFailure(response);
} else {
setResult(Resource.forFailure(response.getError()));
}
@@ -195,7 +213,7 @@ private void handleCredential(final Credential credential) {
.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(AuthResult result) {
- setResult(Resource.forSuccess(response));
+ handleSuccess(response, result);
}
})
.addOnFailureListener(new OnFailureListener() {
diff --git a/auth/src/main/java/com/firebase/ui/auth/data/remote/TwitterSignInHandler.java b/auth/src/main/java/com/firebase/ui/auth/data/remote/TwitterSignInHandler.java
index b64e09c5f..1ff36ffe3 100644
--- a/auth/src/main/java/com/firebase/ui/auth/data/remote/TwitterSignInHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/data/remote/TwitterSignInHandler.java
@@ -17,7 +17,7 @@
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.ui.HelperActivityBase;
import com.firebase.ui.auth.util.data.ProviderAvailability;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.google.firebase.auth.TwitterAuthProvider;
import com.twitter.sdk.android.core.Callback;
import com.twitter.sdk.android.core.Result;
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java b/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java
index 3450092d6..7e73da13f 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/AppCompatBase.java
@@ -20,9 +20,8 @@
import com.firebase.ui.auth.R;
-@SuppressWarnings("Registered")
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class AppCompatBase extends HelperActivityBase {
+public abstract class AppCompatBase extends HelperActivityBase {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/FragmentBase.java b/auth/src/main/java/com/firebase/ui/auth/ui/FragmentBase.java
index 3247b66df..aa156e86b 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/FragmentBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/FragmentBase.java
@@ -4,34 +4,24 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.app.Fragment;
-import android.view.ContextThemeWrapper;
+import android.support.v4.app.FragmentActivity;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.google.firebase.auth.FirebaseUser;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class FragmentBase extends Fragment implements ProgressView {
+public abstract class FragmentBase extends Fragment implements ProgressView {
private HelperActivityBase mActivity;
- private ProgressDialogHolder mProgressDialogHolder;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- if (!(getActivity() instanceof HelperActivityBase)) {
+ FragmentActivity activity = getActivity();
+ if (!(activity instanceof HelperActivityBase)) {
throw new IllegalStateException("Cannot use this fragment without the helper activity");
}
- mActivity = (HelperActivityBase) getActivity();
-
- mProgressDialogHolder = new ProgressDialogHolder(new ContextThemeWrapper(
- getContext(), getFlowParams().themeId));
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mProgressDialogHolder.dismissDialog();
+ mActivity = (HelperActivityBase) activity;
}
public FlowParameters getFlowParams() {
@@ -44,14 +34,4 @@ public void startSaveCredentials(
@Nullable String password) {
mActivity.startSaveCredentials(firebaseUser, response, password);
}
-
- @Override
- public void showProgress(int message) {
- mActivity.showProgress(message);
- }
-
- @Override
- public void hideProgress() {
- mActivity.hideProgress();
- }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java b/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java
index f87a0153e..3a017d0bb 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/HelperActivityBase.java
@@ -3,17 +3,15 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
-import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
-import android.support.annotation.StringRes;
import android.support.v7.app.AppCompatActivity;
+import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.ui.credentials.CredentialSaveActivity;
-import com.firebase.ui.auth.util.AuthHelper;
import com.firebase.ui.auth.util.CredentialUtils;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.data.ProviderUtils;
@@ -23,14 +21,10 @@
import static com.firebase.ui.auth.util.Preconditions.checkNotNull;
-@SuppressWarnings("Registered")
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class HelperActivityBase extends AppCompatActivity implements ProgressView {
+public abstract class HelperActivityBase extends AppCompatActivity implements ProgressView {
private FlowParameters mParams;
- private AuthHelper mAuthHelper;
- private ProgressDialogHolder mProgressDialogHolder;
-
protected static Intent createBaseIntent(
@NonNull Context context,
@NonNull Class extends Activity> target,
@@ -42,24 +36,12 @@ protected static Intent createBaseIntent(
checkNotNull(flowParams, "flowParams cannot be null"));
}
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mAuthHelper = new AuthHelper(getFlowParams());
- mProgressDialogHolder = new ProgressDialogHolder(this);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mProgressDialogHolder.dismissDialog();
- }
-
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Forward the results of Smart Lock saving
- if (requestCode == RequestCodes.CRED_SAVE_FLOW) {
+ if (requestCode == RequestCodes.CRED_SAVE_FLOW
+ || resultCode == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
finish(resultCode, data);
}
}
@@ -71,10 +53,6 @@ public FlowParameters getFlowParams() {
return mParams;
}
- public AuthHelper getAuthHelper() {
- return mAuthHelper;
- }
-
public void finish(int resultCode, @Nullable Intent intent) {
setResult(resultCode, intent);
finish();
@@ -94,18 +72,4 @@ public void startSaveCredentials(
this, getFlowParams(), credential, response);
startActivityForResult(intent, RequestCodes.CRED_SAVE_FLOW);
}
-
- @Override
- public void showProgress(@StringRes int message) {
- getDialogHolder().showLoadingDialog(message);
- }
-
- @Override
- public void hideProgress() {
- getDialogHolder().dismissDialog();
- }
-
- protected ProgressDialogHolder getDialogHolder() {
- return mProgressDialogHolder;
- }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/ProgressDialogHolder.java b/auth/src/main/java/com/firebase/ui/auth/ui/ProgressDialogHolder.java
deleted file mode 100644
index c4d7d4e83..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/ui/ProgressDialogHolder.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.firebase.ui.auth.ui;
-
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.support.annotation.StringRes;
-
-/**
- * Helper class to manage a ProgressDialog.
- */
-public class ProgressDialogHolder {
-
- private Context mContext;
- private ProgressDialog mProgressDialog;
-
- public ProgressDialogHolder(Context context) {
- mContext = context;
- }
-
- private void showLoadingDialog(String message) {
- dismissDialog();
- if (mProgressDialog == null) {
- mProgressDialog = new ProgressDialog(mContext);
- mProgressDialog.setIndeterminate(true);
- mProgressDialog.setTitle("");
- }
-
- mProgressDialog.setMessage(message);
- mProgressDialog.show();
- }
-
- public void showLoadingDialog(@StringRes int stringResource) {
- showLoadingDialog(mContext.getString(stringResource));
- }
-
- public void dismissDialog() {
- if (isProgressDialogShowing()) {
- mProgressDialog.dismiss();
- }
-
- mProgressDialog = null;
- }
-
- public boolean isProgressDialogShowing() {
- return mProgressDialog != null && mProgressDialog.isShowing();
- }
-
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java
index 3002f7be5..80930de72 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailFragment.java
@@ -8,6 +8,7 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.design.widget.TextInputLayout;
+import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -113,12 +114,12 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
FlowParameters flowParameters = getFlowParams();
if (flowParameters.isSingleProviderFlow()) {
- PrivacyDisclosureUtils.setupTermsOfServiceAndPrivacyPolicyText(getContext(),
+ PrivacyDisclosureUtils.setupTermsOfServiceAndPrivacyPolicyText(requireContext(),
flowParameters,
termsText);
} else {
termsText.setVisibility(View.GONE);
- PrivacyDisclosureUtils.setupTermsOfServiceFooter(getContext(),
+ PrivacyDisclosureUtils.setupTermsOfServiceFooter(requireContext(),
flowParameters,
footerText);
}
@@ -130,10 +131,11 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
mHandler = ViewModelProviders.of(this).get(CheckEmailHandler.class);
mHandler.init(getFlowParams());
- if (!(getActivity() instanceof CheckEmailListener)) {
+ FragmentActivity activity = getActivity();
+ if (!(activity instanceof CheckEmailListener)) {
throw new IllegalStateException("Activity must implement CheckEmailListener");
}
- mListener = (CheckEmailListener) getActivity();
+ mListener = (CheckEmailListener) activity;
mHandler.getOperation().observe(this, new ResourceObserver(
this, R.string.fui_progress_dialog_checking_accounts) {
@@ -210,7 +212,7 @@ public void showProgress(int message) {
@Override
public void hideProgress() {
- mNextButton.setEnabled(true);
- mProgressBar.setVisibility(View.INVISIBLE);
+ mNextButton.setEnabled(true);
+ mProgressBar.setVisibility(View.INVISIBLE);
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailHandler.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailHandler.java
index 1a28a951f..0b0df0e1c 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/CheckEmailHandler.java
@@ -18,7 +18,6 @@
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
-@SuppressWarnings("WrongConstant")
public class CheckEmailHandler extends AuthViewModelBase {
public CheckEmailHandler(Application application) {
super(application);
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java
index b019959dd..2b21c2f94 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/EmailActivity.java
@@ -19,11 +19,13 @@
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
+import android.support.annotation.StringRes;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewCompat;
import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
@@ -41,7 +43,8 @@
* WelcomeBackIdpPrompt}.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class EmailActivity extends AppCompatBase implements CheckEmailFragment.CheckEmailListener {
+public class EmailActivity extends AppCompatBase implements CheckEmailFragment.CheckEmailListener,
+ RegisterEmailFragment.AnonymousUpgradeListener {
public static Intent createIntent(Context context, FlowParameters flowParams) {
return createIntent(context, flowParams, null);
}
@@ -130,4 +133,19 @@ private void setSlideAnimation() {
// Make the next activity slide in
overridePendingTransition(R.anim.fui_slide_in_right, R.anim.fui_slide_out_left);
}
+
+ @Override
+ public void showProgress(@StringRes int message) {
+ throw new UnsupportedOperationException("Email fragments must handle progress updates.");
+ }
+
+ @Override
+ public void hideProgress() {
+ throw new UnsupportedOperationException("Email fragments must handle progress updates.");
+ }
+
+ @Override
+ public void onMergeFailure(IdpResponse response) {
+ finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java
index 590ca1928..1a4c7a809 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/RecoverPasswordActivity.java
@@ -25,7 +25,9 @@
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.view.View;
+import android.widget.Button;
import android.widget.EditText;
+import android.widget.ProgressBar;
import android.widget.TextView;
import com.firebase.ui.auth.R;
@@ -48,6 +50,8 @@ public class RecoverPasswordActivity extends AppCompatBase implements View.OnCli
ImeHelper.DonePressedListener {
private RecoverPasswordHandler mHandler;
+ private ProgressBar mProgressBar;
+ private Button mSubmitButton;
private TextInputLayout mEmailInputLayout;
private EditText mEmailEditText;
private EmailFieldValidator mEmailFieldValidator;
@@ -85,6 +89,8 @@ protected void onFailure(@NonNull Exception e) {
}
});
+ mProgressBar = findViewById(R.id.top_progress_bar);
+ mSubmitButton = findViewById(R.id.button_done);
mEmailInputLayout = findViewById(R.id.email_layout);
mEmailEditText = findViewById(R.id.email);
mEmailFieldValidator = new EmailFieldValidator(mEmailInputLayout);
@@ -95,7 +101,7 @@ protected void onFailure(@NonNull Exception e) {
}
ImeHelper.setImeOnDoneListener(mEmailEditText, this);
- findViewById(R.id.button_done).setOnClickListener(this);
+ mSubmitButton.setOnClickListener(this);
TextView footerText = findViewById(R.id.email_footer_tos_and_pp_text);
PrivacyDisclosureUtils.setupTermsOfServiceFooter(this, getFlowParams(), footerText);
@@ -127,4 +133,16 @@ public void onDismiss(DialogInterface dialog) {
.setPositiveButton(android.R.string.ok, null)
.show();
}
+
+ @Override
+ public void showProgress(int message) {
+ mSubmitButton.setEnabled(false);
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void hideProgress() {
+ mSubmitButton.setEnabled(true);
+ mProgressBar.setVisibility(View.INVISIBLE);
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java
index 03188f2b0..2dd7d6938 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/RegisterEmailFragment.java
@@ -7,6 +7,7 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.design.widget.TextInputLayout;
+import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -17,6 +18,7 @@
import android.widget.TextView;
import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.User;
@@ -31,7 +33,7 @@
import com.firebase.ui.auth.util.ui.fieldvalidators.PasswordFieldValidator;
import com.firebase.ui.auth.util.ui.fieldvalidators.RequiredFieldValidator;
import com.firebase.ui.auth.viewmodel.ResourceObserver;
-import com.firebase.ui.auth.viewmodel.idp.EmailProviderResponseHandler;
+import com.firebase.ui.auth.viewmodel.email.EmailProviderResponseHandler;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseAuthWeakPasswordException;
@@ -59,8 +61,21 @@ public class RegisterEmailFragment extends FragmentBase implements
private PasswordFieldValidator mPasswordFieldValidator;
private BaseValidator mNameValidator;
+ private AnonymousUpgradeListener mListener;
private User mUser;
+ /**
+ * Interface to be implemented by Activities hosting this Fragment.
+ */
+ interface AnonymousUpgradeListener {
+
+ /**
+ * Email belongs to an existing user - failed to merge anonymous user.
+ */
+ void onMergeFailure(IdpResponse response);
+
+ }
+
public static RegisterEmailFragment newInstance(User user) {
RegisterEmailFragment fragment = new RegisterEmailFragment();
Bundle args = new Bundle();
@@ -98,6 +113,9 @@ protected void onFailure(@NonNull Exception e) {
R.integer.fui_min_password_length));
} else if (e instanceof FirebaseAuthInvalidCredentialsException) {
mEmailInput.setError(getString(R.string.fui_invalid_email_address));
+ } else if (e instanceof FirebaseAuthAnonymousUpgradeException) {
+ IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
+ mListener.onMergeFailure(response);
} else {
// General error message, this branch should not be invoked but
// covers future API changes
@@ -155,7 +173,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
}
TextView footerText = view.findViewById(R.id.email_footer_tos_and_pp_text);
- PrivacyDisclosureUtils.setupTermsOfServiceFooter(getContext(), getFlowParams(), footerText);
+ PrivacyDisclosureUtils.setupTermsOfServiceFooter(
+ requireContext(), getFlowParams(), footerText);
// WARNING: Nothing below this line will be executed on rotation
if (savedInstanceState != null) {
@@ -196,7 +215,13 @@ public void run() {
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- getActivity().setTitle(R.string.fui_title_register_email);
+ FragmentActivity activity = requireActivity();
+ activity.setTitle(R.string.fui_title_register_email);
+ if (!(activity instanceof AnonymousUpgradeListener)) {
+ throw new IllegalStateException("Activity must implement CheckEmailListener");
+ }
+ mListener = (AnonymousUpgradeListener) activity;
+
}
@Override
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java b/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java
index 2c2ace31e..45218c32d 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java
@@ -35,6 +35,8 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
@@ -120,7 +122,12 @@ protected void onSuccess(@NonNull IdpResponse response) {
@Override
protected void onFailure(@NonNull Exception e) {
- mPasswordLayout.setError(getString(getErrorMessage(e)));
+ if (e instanceof FirebaseAuthAnonymousUpgradeException) {
+ IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
+ finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
+ } else {
+ mPasswordLayout.setError(getString(getErrorMessage(e)));
+ }
}
});
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java
index 48e15cfe2..f0d35c160 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.java
@@ -34,22 +34,27 @@
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.AuthUI.IdpConfig;
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
+import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.data.model.UserCancellationException;
import com.firebase.ui.auth.data.remote.EmailSignInHandler;
import com.firebase.ui.auth.data.remote.FacebookSignInHandler;
+import com.firebase.ui.auth.data.remote.GitHubSignInHandler;
import com.firebase.ui.auth.data.remote.GoogleSignInHandler;
import com.firebase.ui.auth.data.remote.PhoneSignInHandler;
import com.firebase.ui.auth.data.remote.TwitterSignInHandler;
import com.firebase.ui.auth.ui.AppCompatBase;
import com.firebase.ui.auth.util.data.PrivacyDisclosureUtils;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.ResourceObserver;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.idp.SocialProviderResponseHandler;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FacebookAuthProvider;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
@@ -109,9 +114,14 @@ protected void onSuccess(@NonNull IdpResponse response) {
@Override
protected void onFailure(@NonNull Exception e) {
- if (!(e instanceof UserCancellationException)) {
+ if (e instanceof FirebaseAuthAnonymousUpgradeException) {
+ finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT,
+ ((FirebaseAuthAnonymousUpgradeException) e).getResponse().toIntent());
+ } else if ( (!(e instanceof UserCancellationException))) {
+ String text = e instanceof FirebaseUiException ? e.getMessage() :
+ getString(R.string.fui_error_unknown);
Toast.makeText(AuthMethodPickerActivity.this,
- R.string.fui_error_unknown,
+ text,
Toast.LENGTH_SHORT).show();
}
}
@@ -155,6 +165,13 @@ private void populateIdpList(List providerConfigs,
buttonLayout = R.layout.fui_idp_button_twitter;
break;
+ case GithubAuthProvider.PROVIDER_ID:
+ GitHubSignInHandler github = supplier.get(GitHubSignInHandler.class);
+ github.init(idpConfig);
+ provider = github;
+
+ buttonLayout = R.layout.fui_idp_button_github;
+ break;
case EmailAuthProvider.PROVIDER_ID:
EmailSignInHandler email = supplier.get(EmailSignInHandler.class);
email.init(null);
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/SingleSignInActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/idp/SingleSignInActivity.java
index 8f97b0e9a..e5f35f2d6 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/SingleSignInActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/SingleSignInActivity.java
@@ -13,19 +13,20 @@
import com.firebase.ui.auth.ErrorCodes;
import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
-import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.data.remote.FacebookSignInHandler;
+import com.firebase.ui.auth.data.remote.GitHubSignInHandler;
import com.firebase.ui.auth.data.remote.GoogleSignInHandler;
import com.firebase.ui.auth.data.remote.TwitterSignInHandler;
import com.firebase.ui.auth.ui.InvisibleActivityBase;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.data.ProviderUtils;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.ResourceObserver;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.idp.SocialProviderResponseHandler;
import com.google.firebase.auth.FacebookAuthProvider;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
@@ -75,6 +76,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
twitter.init(null);
mProvider = twitter;
break;
+ case GithubAuthProvider.PROVIDER_ID:
+ GitHubSignInHandler github = supplier.get(GitHubSignInHandler.class);
+ github.init(providerConfig);
+ mProvider = github;
+ break;
default:
throw new IllegalStateException("Invalid provider id: " + provider);
}
@@ -91,8 +97,7 @@ protected void onFailure(@NonNull Exception e) {
}
});
- mHandler.getOperation().observe(this, new ResourceObserver(
- this, R.string.fui_progress_dialog_loading) {
+ mHandler.getOperation().observe(this, new ResourceObserver(this) {
@Override
protected void onSuccess(@NonNull IdpResponse response) {
startSaveCredentials(mHandler.getCurrentUser(), response, null);
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java b/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java
index 5128496cd..ae5634026 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/WelcomeBackIdpPrompt.java
@@ -31,22 +31,25 @@
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.data.remote.FacebookSignInHandler;
+import com.firebase.ui.auth.data.remote.GitHubSignInHandler;
import com.firebase.ui.auth.data.remote.GoogleSignInHandler;
import com.firebase.ui.auth.data.remote.TwitterSignInHandler;
import com.firebase.ui.auth.ui.AppCompatBase;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.data.PrivacyDisclosureUtils;
import com.firebase.ui.auth.util.data.ProviderUtils;
+import com.firebase.ui.auth.viewmodel.ProviderSignInBase;
import com.firebase.ui.auth.viewmodel.ResourceObserver;
import com.firebase.ui.auth.viewmodel.idp.LinkingSocialProviderResponseHandler;
-import com.firebase.ui.auth.viewmodel.idp.ProviderSignInBase;
import com.google.firebase.auth.FacebookAuthProvider;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
@@ -88,8 +91,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
supplier.get(LinkingSocialProviderResponseHandler.class);
handler.init(getFlowParams());
if (requestedUserResponse != null) {
- handler.setRequestedSignInCredential(
- ProviderUtils.getAuthCredential(requestedUserResponse));
+ handler.setRequestedSignInCredentialForEmail(
+ ProviderUtils.getAuthCredential(requestedUserResponse),
+ existingUser.getEmail());
}
String providerId = existingUser.getProviderId();
@@ -127,6 +131,13 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
providerName = R.string.fui_idp_name_twitter;
break;
+ case GithubAuthProvider.PROVIDER_ID:
+ GitHubSignInHandler github = supplier.get(GitHubSignInHandler.class);
+ github.init(config);
+ mProvider = github;
+
+ providerName = R.string.fui_idp_name_github;
+ break;
default:
throw new IllegalStateException("Invalid provider id: " + providerId);
}
@@ -163,7 +174,12 @@ protected void onSuccess(@NonNull IdpResponse response) {
@Override
protected void onFailure(@NonNull Exception e) {
- finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e));
+ if (e instanceof FirebaseAuthAnonymousUpgradeException) {
+ IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
+ finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
+ } else {
+ finish(RESULT_CANCELED, IdpResponse.getErrorIntent(e));
+ }
}
});
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/CheckPhoneHandler.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CheckPhoneHandler.java
new file mode 100644
index 000000000..4301fb904
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CheckPhoneHandler.java
@@ -0,0 +1,43 @@
+package com.firebase.ui.auth.ui.phone;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Intent;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import com.firebase.ui.auth.data.model.PendingIntentRequiredException;
+import com.firebase.ui.auth.data.model.PhoneNumber;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.util.data.PhoneNumberUtils;
+import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
+import com.firebase.ui.auth.viewmodel.RequestCodes;
+import com.google.android.gms.auth.api.credentials.Credential;
+import com.google.android.gms.auth.api.credentials.Credentials;
+import com.google.android.gms.auth.api.credentials.HintRequest;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class CheckPhoneHandler extends AuthViewModelBase {
+ public CheckPhoneHandler(Application application) {
+ super(application);
+ }
+
+ public void fetchCredential() {
+ setResult(Resource.forFailure(new PendingIntentRequiredException(
+ Credentials.getClient(getApplication()).getHintPickerIntent(
+ new HintRequest.Builder().setPhoneNumberIdentifierSupported(true).build()),
+ RequestCodes.CRED_HINT
+ )));
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (requestCode != RequestCodes.CRED_HINT || resultCode != Activity.RESULT_OK) { return; }
+
+ Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
+ String formattedPhone = PhoneNumberUtils.formatUsingCurrentCountry(
+ credential.getId(), getApplication());
+ if (formattedPhone != null) {
+ setResult(Resource.forSuccess(PhoneNumberUtils.getPhoneNumber(formattedPhone)));
+ }
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/CheckPhoneNumberFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CheckPhoneNumberFragment.java
new file mode 100644
index 000000000..93ed3a9fc
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CheckPhoneNumberFragment.java
@@ -0,0 +1,253 @@
+package com.firebase.ui.auth.ui.phone;
+
+import android.arch.lifecycle.ViewModelProviders;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.design.widget.TextInputLayout;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.firebase.ui.auth.R;
+import com.firebase.ui.auth.data.model.FlowParameters;
+import com.firebase.ui.auth.data.model.PhoneNumber;
+import com.firebase.ui.auth.ui.FragmentBase;
+import com.firebase.ui.auth.util.ExtraConstants;
+import com.firebase.ui.auth.util.data.PhoneNumberUtils;
+import com.firebase.ui.auth.util.data.PrivacyDisclosureUtils;
+import com.firebase.ui.auth.util.ui.ImeHelper;
+import com.firebase.ui.auth.viewmodel.ResourceObserver;
+
+import java.util.Locale;
+
+/**
+ * Displays country selector and phone number input form for users
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class CheckPhoneNumberFragment extends FragmentBase implements View.OnClickListener {
+ public static final String TAG = "VerifyPhoneFragment";
+
+ private PhoneNumberVerificationHandler mVerificationHandler;
+ private CheckPhoneHandler mCheckPhoneHandler;
+ private boolean mCalled;
+
+ private ProgressBar mProgressBar;
+ private Button mSubmitButton;
+ private CountryListSpinner mCountryListSpinner;
+ private TextInputLayout mPhoneInputLayout;
+ private EditText mPhoneEditText;
+ private TextView mSmsTermsText;
+
+
+ public static CheckPhoneNumberFragment newInstance(Bundle params) {
+ CheckPhoneNumberFragment fragment = new CheckPhoneNumberFragment();
+ Bundle args = new Bundle();
+ args.putBundle(ExtraConstants.PARAMS, params);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mVerificationHandler = ViewModelProviders.of(requireActivity())
+ .get(PhoneNumberVerificationHandler.class);
+ mCheckPhoneHandler = ViewModelProviders.of(requireActivity())
+ .get(CheckPhoneHandler.class);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fui_phone_layout, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ mProgressBar = view.findViewById(R.id.top_progress_bar);
+ mSubmitButton = view.findViewById(R.id.send_code);
+ mCountryListSpinner = view.findViewById(R.id.country_list);
+ mPhoneInputLayout = view.findViewById(R.id.phone_layout);
+ mPhoneEditText = view.findViewById(R.id.phone_number);
+ mSmsTermsText = view.findViewById(R.id.send_sms_tos);
+
+ mSmsTermsText.setText(getString(R.string.fui_sms_terms_of_service,
+ getString(R.string.fui_verify_phone_number)));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && getFlowParams().enableHints) {
+ mPhoneEditText.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);
+ }
+ requireActivity().setTitle(getString(R.string.fui_verify_phone_number_title));
+
+ ImeHelper.setImeOnDoneListener(mPhoneEditText, new ImeHelper.DonePressedListener() {
+ @Override
+ public void onDonePressed() {
+ onNext();
+ }
+ });
+ mSubmitButton.setOnClickListener(this);
+
+ setupPrivacyDisclosures(view.findViewById(R.id.email_footer_tos_and_pp_text));
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mCheckPhoneHandler.getOperation().observe(this, new ResourceObserver(this) {
+ @Override
+ protected void onSuccess(@NonNull PhoneNumber number) {
+ start(number);
+ }
+
+ @Override
+ protected void onFailure(@NonNull Exception e) {
+ // Just let the user enter their data
+ }
+ });
+
+ if (savedInstanceState != null || mCalled) { return; }
+ // Fragment back stacks are the stuff of nightmares (what's new?): the fragment isn't
+ // destroyed so its state isn't saved and we have to rely on an instance field. Sigh.
+ mCalled = true;
+
+ setupCountrySpinner();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ mCheckPhoneHandler.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ public void onClick(View v) {
+ onNext();
+ }
+
+ private void start(PhoneNumber number) {
+ if (!PhoneNumber.isValid(number)) {
+ mPhoneInputLayout.setError(getString(R.string.fui_invalid_phone_number));
+ return;
+ }
+ mPhoneEditText.setText(number.getPhoneNumber());
+ mPhoneEditText.setSelection(number.getPhoneNumber().length());
+
+ String iso = number.getCountryIso();
+
+ if (PhoneNumber.isCountryValid(number) && mCountryListSpinner.isValidIso(iso)) {
+ setCountryCode(number);
+ onNext();
+ }
+ }
+
+ private void onNext() {
+ String phoneNumber = getPseudoValidPhoneNumber();
+ if (phoneNumber == null) {
+ mPhoneInputLayout.setError(getString(R.string.fui_invalid_phone_number));
+ } else {
+ mVerificationHandler.verifyPhoneNumber(phoneNumber, false);
+ }
+ }
+
+ @Nullable
+ private String getPseudoValidPhoneNumber() {
+ String everythingElse = mPhoneEditText.getText().toString();
+
+ if (TextUtils.isEmpty(everythingElse)) {
+ return null;
+ }
+
+ return PhoneNumberUtils.format(
+ everythingElse, mCountryListSpinner.getSelectedCountryInfo());
+ }
+
+ private void setupPrivacyDisclosures(TextView footerText) {
+ FlowParameters params = getFlowParams();
+
+ if (params.isSingleProviderFlow()) {
+ PrivacyDisclosureUtils.setupTermsOfServiceAndPrivacyPolicySmsText(requireContext(),
+ params,
+ mSmsTermsText);
+ } else {
+ PrivacyDisclosureUtils.setupTermsOfServiceFooter(requireContext(),
+ params,
+ footerText);
+
+ String verifyText = getString(R.string.fui_verify_phone_number);
+ mSmsTermsText.setText(getString(R.string.fui_sms_terms_of_service, verifyText));
+ }
+ }
+
+ private void setCountryCode(PhoneNumber number) {
+ mCountryListSpinner.setSelectedForCountry(
+ new Locale("", number.getCountryIso()), number.getCountryCode());
+ }
+
+ private void setupCountrySpinner() {
+ Bundle params = getArguments().getBundle(ExtraConstants.PARAMS);
+ mCountryListSpinner.init(params);
+
+ setDefaultCountryForSpinner();
+
+ // Clear error when spinner is clicked on
+ mCountryListSpinner.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPhoneInputLayout.setError(null);
+ }
+ });
+ }
+
+ private void setDefaultCountryForSpinner() {
+ // Check for phone
+ // It is assumed that the phone number that are being wired in via Credential Selector
+ // are e164 since we store it.
+ Bundle params = getArguments().getBundle(ExtraConstants.PARAMS);
+ String phone = null;
+ String countryIso = null;
+ String nationalNumber = null;
+ if (params != null) {
+ phone = params.getString(ExtraConstants.PHONE);
+ countryIso = params.getString(ExtraConstants.COUNTRY_ISO);
+ nationalNumber = params.getString(ExtraConstants.NATIONAL_NUMBER);
+ }
+
+ // We can receive the phone number in one of two formats: split between the ISO or fully
+ // processed. If it's complete, we use it directly. Otherwise, we parse the ISO and national
+ // number combination or we just set the default ISO if there's no default number. If there
+ // are no defaults at all, we prompt the user for a phone number through Smart Lock.
+ if (!TextUtils.isEmpty(phone)) {
+ start(PhoneNumberUtils.getPhoneNumber(phone));
+ } else if (!TextUtils.isEmpty(countryIso) && !TextUtils.isEmpty(nationalNumber)) {
+ start(PhoneNumberUtils.getPhoneNumber(countryIso, nationalNumber));
+ } else if (!TextUtils.isEmpty(countryIso)) {
+ setCountryCode(new PhoneNumber(
+ "",
+ countryIso,
+ String.valueOf(PhoneNumberUtils.getCountryCode(countryIso))));
+ } else if (getFlowParams().enableHints) {
+ mCheckPhoneHandler.fetchCredential();
+ }
+ }
+
+ @Override
+ public void showProgress(int message) {
+ mSubmitButton.setEnabled(false);
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void hideProgress() {
+ mSubmitButton.setEnabled(true);
+ mProgressBar.setVisibility(View.INVISIBLE);
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/CompletableProgressDialog.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CompletableProgressDialog.java
deleted file mode 100644
index 26d347de5..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/CompletableProgressDialog.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.firebase.ui.auth.ui.phone;
-
-import android.app.Dialog;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.firebase.ui.auth.R;
-
-public final class CompletableProgressDialog extends DialogFragment {
- private static final String TAG = "ComProgressDialog";
-
- private ProgressBar mProgress;
- @VisibleForTesting TextView mMessageView;
- private CharSequence mMessage;
- private ImageView mSuccessImage;
-
- public static CompletableProgressDialog show(FragmentManager manager) {
- CompletableProgressDialog dialog = new CompletableProgressDialog();
- dialog.showAllowingStateLoss(manager, TAG);
- return dialog;
- }
-
- /**
- * This method is adapted from {@link #show(FragmentManager, String)}
- */
- public void showAllowingStateLoss(FragmentManager manager, String tag) {
- // This prevents us from hitting FragmentManager.checkStateLoss() which
- // throws a runtime exception if state has already been saved.
- if (manager.isStateSaved()) {
- return;
- }
-
- show(manager, tag);
- }
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- View rootView = View.inflate(getContext(), R.layout.fui_phone_progress_dialog, null);
-
- mProgress = rootView.findViewById(R.id.top_progress_bar);
- mMessageView = rootView.findViewById(R.id.progress_msg);
- mSuccessImage = rootView.findViewById(R.id.progress_success_imaage);
-
- if (mMessage != null) {
- setMessage(mMessage);
- }
-
- return new AlertDialog.Builder(getContext()).setView(rootView).create();
- }
-
- public void onComplete(String msg) {
- setMessage(msg);
-
- if (mProgress != null) {
- mProgress.setVisibility(View.GONE);
- }
-
- if (mSuccessImage != null) {
- mSuccessImage.setVisibility(View.VISIBLE);
- }
- }
-
- public void setMessage(CharSequence message) {
- if (mProgress != null && mMessageView != null) {
- mMessageView.setText(message);
- } else {
- mMessage = message;
- }
- }
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/CountryListSpinner.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CountryListSpinner.java
index 5d80c5de1..20c69ade4 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/CountryListSpinner.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/CountryListSpinner.java
@@ -20,9 +20,9 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
import android.support.v7.widget.AppCompatEditText;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -30,15 +30,19 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.ListView;
-import com.firebase.ui.auth.data.client.CountryListLoadTask;
import com.firebase.ui.auth.data.model.CountryInfo;
+import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.data.PhoneNumberUtils;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
-public final class CountryListSpinner extends AppCompatEditText implements
- View.OnClickListener, CountryListLoadTask.Listener {
+public final class CountryListSpinner extends AppCompatEditText implements View.OnClickListener {
private static final String KEY_SUPER_STATE = "KEY_SUPER_STATE";
private static final String KEY_COUNTRY_INFO = "KEY_COUNTRY_INFO";
@@ -50,6 +54,9 @@ public final class CountryListSpinner extends AppCompatEditText implements
private String mSelectedCountryName;
private CountryInfo mSelectedCountryInfo;
+ private Set mWhitelistedCountryIsos;
+ private Set mBlacklistedCountryIsos;
+
public CountryListSpinner(Context context) {
this(context, null, android.R.attr.spinnerStyle);
}
@@ -66,8 +73,99 @@ public CountryListSpinner(Context context, AttributeSet attrs, int defStyle) {
mDialogPopup = new DialogPopup(mCountryListAdapter);
mTextFormat = "%1$s +%2$d";
mSelectedCountryName = "";
+ }
+
+ public void init(Bundle params) {
+ if (params != null) {
+ List countries = getCountriesToDisplayInSpinner(params);
+ setCountriesToDisplay(countries);
+ setDefaultCountryForSpinner(countries);
+ }
+ }
+
+ private List getCountriesToDisplayInSpinner(Bundle params) {
+ initCountrySpinnerIsosFromParams(params);
+
+ Map countryInfoMap = PhoneNumberUtils.getImmutableCountryIsoMap();
+ // We consider all countries to be whitelisted if there are no whitelisted
+ // or blacklisted countries given as input.
+ if (mWhitelistedCountryIsos == null && mBlacklistedCountryIsos == null) {
+ this.mWhitelistedCountryIsos = new HashSet<>(countryInfoMap.keySet());
+ }
+
+ List countryInfoList = new ArrayList<>();
+
+ // At this point either mWhitelistedCountryIsos or mBlacklistedCountryIsos is null.
+ // We assume no countries are to be excluded. Here, we correct this assumption based on the
+ // contents of either lists.
+ Set excludedCountries = new HashSet<>();
+ if (mWhitelistedCountryIsos == null) {
+ // Exclude all countries in the mBlacklistedCountryIsos list.
+ excludedCountries.addAll(mBlacklistedCountryIsos);
+ } else {
+ // Exclude all countries that are not present in the mWhitelistedCountryIsos list.
+ excludedCountries.addAll(countryInfoMap.keySet());
+ excludedCountries.removeAll(mWhitelistedCountryIsos);
+ }
+
+ // Once we know which countries need to be excluded, we loop through the country isos,
+ // skipping those that have been excluded.
+ for (String countryIso : countryInfoMap.keySet()) {
+ if (!excludedCountries.contains(countryIso)) {
+ countryInfoList.add(new CountryInfo(new Locale("", countryIso),
+ countryInfoMap.get(countryIso)));
+ }
+ }
+ Collections.sort(countryInfoList);
+ return countryInfoList;
+ }
+
+ private void initCountrySpinnerIsosFromParams(@NonNull Bundle params) {
+ List whitelistedCountries =
+ params.getStringArrayList(ExtraConstants.WHITELISTED_COUNTRIES);
+ List blacklistedCountries =
+ params.getStringArrayList(ExtraConstants.BLACKLISTED_COUNTRIES);
+
+ if (whitelistedCountries != null) {
+ mWhitelistedCountryIsos = convertCodesToIsos(whitelistedCountries);
+ } else if (blacklistedCountries != null) {
+ mBlacklistedCountryIsos = convertCodesToIsos(blacklistedCountries);
+ }
+ }
+
+ private Set convertCodesToIsos(@NonNull List codes) {
+ Set isos = new HashSet<>();
+ for (String code : codes) {
+ if (PhoneNumberUtils.isValid(code)) {
+ isos.addAll(PhoneNumberUtils.getCountryIsosFromCountryCode(code));
+ } else {
+ isos.add(code);
+ }
+ }
+ return isos;
+ }
+
+ public void setCountriesToDisplay(List countries) {
+ mCountryListAdapter.setData(countries);
+ }
+
+ private void setDefaultCountryForSpinner(List countries) {
CountryInfo countryInfo = PhoneNumberUtils.getCurrentCountryInfo(getContext());
- setSelectedForCountry(countryInfo.getCountryCode(), countryInfo.getLocale());
+ if (isValidIso(countryInfo.getLocale().getCountry())) {
+ setSelectedForCountry(countryInfo.getCountryCode(),
+ countryInfo.getLocale());
+ } else if (countries.iterator().hasNext()) {
+ countryInfo = countries.iterator().next();
+ setSelectedForCountry(countryInfo.getCountryCode(),
+ countryInfo.getLocale());
+ }
+ }
+
+ public boolean isValidIso(String iso) {
+ iso = iso.toUpperCase(Locale.getDefault());
+ return ((mWhitelistedCountryIsos == null && mBlacklistedCountryIsos == null)
+ || (mWhitelistedCountryIsos != null && mWhitelistedCountryIsos.contains(iso))
+ || (mBlacklistedCountryIsos != null && !mBlacklistedCountryIsos.contains(iso)));
}
@Override
@@ -102,21 +200,23 @@ private static void hideKeyboard(Context context, View view) {
}
}
- private void setSelectedForCountry(int countryCode, Locale locale) {
+ public void setSelectedForCountry(int countryCode, Locale locale) {
setText(String.format(mTextFormat, CountryInfo.localeToEmoji(locale), countryCode));
mSelectedCountryInfo = new CountryInfo(locale, countryCode);
}
public void setSelectedForCountry(final Locale locale, String countryCode) {
- final String countryName = locale.getDisplayName();
- if (!TextUtils.isEmpty(countryName) && !TextUtils.isEmpty(countryCode)) {
- mSelectedCountryName = countryName;
- setSelectedForCountry(Integer.parseInt(countryCode), locale);
+ if (isValidIso(locale.getCountry())) {
+ final String countryName = locale.getDisplayName();
+ if (!TextUtils.isEmpty(countryName) && !TextUtils.isEmpty(countryCode)) {
+ mSelectedCountryName = countryName;
+ setSelectedForCountry(Integer.parseInt(countryCode), locale);
+ }
}
}
public CountryInfo getSelectedCountryInfo() {
- return mSelectedCountryInfo;
+ return mSelectedCountryInfo;
}
@Override
@@ -135,31 +235,17 @@ public void setOnClickListener(OnClickListener l) {
@Override
public void onClick(View view) {
- if (mCountryListAdapter.getCount() == 0) {
- loadCountryList();
- } else {
- mDialogPopup.show(mCountryListAdapter.getPositionForCountry(mSelectedCountryName));
- }
+ mDialogPopup.show(mCountryListAdapter.getPositionForCountry(mSelectedCountryName));
hideKeyboard(getContext(), this);
executeUserClickListener(view);
}
- private void loadCountryList() {
- new CountryListLoadTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
private void executeUserClickListener(View view) {
if (mListener != null) {
mListener.onClick(view);
}
}
- @Override
- public void onLoadComplete(List result) {
- mCountryListAdapter.setData(result);
- mDialogPopup.show(mCountryListAdapter.getPositionForCountry(mSelectedCountryName));
- }
-
public class DialogPopup implements DialogInterface.OnClickListener {
//Delay for postDelayed to set selection without showing the scroll animation
private static final long DELAY_MILLIS = 10L;
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java
index 774936122..2dccd14ff 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneActivity.java
@@ -14,70 +14,41 @@
package com.firebase.ui.auth.ui.phone;
+import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
-import android.support.annotation.StringRes;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.AlertDialog;
-import android.text.TextUtils;
-import android.util.Log;
+import android.support.design.widget.TextInputLayout;
+import android.widget.Toast;
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
+import com.firebase.ui.auth.data.model.PhoneNumberVerificationRequiredException;
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.ui.AppCompatBase;
+import com.firebase.ui.auth.ui.FragmentBase;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.FirebaseAuthError;
-import com.google.android.gms.tasks.OnFailureListener;
-import com.google.android.gms.tasks.OnSuccessListener;
-import com.google.firebase.FirebaseException;
-import com.google.firebase.auth.AuthResult;
+import com.firebase.ui.auth.viewmodel.ResourceObserver;
+import com.firebase.ui.auth.viewmodel.phone.PhoneProviderResponseHandler;
import com.google.firebase.auth.FirebaseAuthException;
-import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
-import com.google.firebase.auth.FirebaseUser;
-import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;
-import java.util.concurrent.TimeUnit;
-
/**
* Activity to control the entire phone verification flow. Plays host to {@link
- * VerifyPhoneNumberFragment} and {@link SubmitConfirmationCodeFragment}
+ * CheckPhoneNumberFragment} and {@link SubmitConfirmationCodeFragment}
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class PhoneActivity extends AppCompatBase {
- private enum VerificationState {
- VERIFICATION_NOT_STARTED, VERIFICATION_STARTED, VERIFIED
- }
-
- private static final String PHONE_VERIFICATION_LOG_TAG = "PhoneVerification";
-
- private static final long SHORT_DELAY_MILLIS = 750;
- @VisibleForTesting static final long AUTO_RETRIEVAL_TIMEOUT_MILLIS = 120000;
-
- private static final String KEY_VERIFICATION_PHONE = "KEY_VERIFICATION_PHONE";
- private static final String KEY_STATE = "KEY_STATE";
-
- private AlertDialog mAlertDialog;
- @VisibleForTesting CompletableProgressDialog mProgressDialog;
- private Handler mHandler;
- private String mPhoneNumber;
- private String mVerificationId;
- private Boolean mIsDestroyed = false;
- private PhoneAuthProvider.ForceResendingToken mForceResendingToken;
- private VerificationState mVerificationState;
-
- public static Intent createIntent(Context context, FlowParameters flowParams, Bundle params) {
- return createBaseIntent(context, PhoneActivity.class, flowParams)
- .putExtra(ExtraConstants.PARAMS, params);
+ public static Intent createIntent(Context context, FlowParameters params, Bundle args) {
+ return createBaseIntent(context, PhoneActivity.class, params)
+ .putExtra(ExtraConstants.PARAMS, args);
}
@Override
@@ -85,330 +56,163 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fui_activity_register_phone);
- mHandler = new Handler();
- mVerificationState = VerificationState.VERIFICATION_NOT_STARTED;
- if (savedInstanceState != null && !savedInstanceState.isEmpty()) {
- mPhoneNumber = savedInstanceState.getString(KEY_VERIFICATION_PHONE);
+ final PhoneProviderResponseHandler handler =
+ ViewModelProviders.of(this).get(PhoneProviderResponseHandler.class);
+ handler.init(getFlowParams());
+ handler.getOperation().observe(this, new ResourceObserver(
+ this, R.string.fui_progress_dialog_signing_in) {
+ @Override
+ protected void onSuccess(@NonNull IdpResponse response) {
+ startSaveCredentials(handler.getCurrentUser(), response, null);
+ }
+
+ @Override
+ protected void onFailure(@NonNull Exception e) {
+ handleError(e);
+ }
+ });
- if (savedInstanceState.getSerializable(KEY_STATE) != null) {
- mVerificationState = (VerificationState) savedInstanceState.getSerializable(
- KEY_STATE);
+ final PhoneNumberVerificationHandler phoneVerifier =
+ ViewModelProviders.of(this).get(PhoneNumberVerificationHandler.class);
+ phoneVerifier.init(getFlowParams());
+ phoneVerifier.getOperation().observe(this, new ResourceObserver(
+ this, R.string.fui_verifying) {
+ @Override
+ protected void onSuccess(@NonNull PhoneVerification verification) {
+ if (verification.isAutoVerified()) {
+ Toast.makeText(
+ PhoneActivity.this, R.string.fui_auto_verified, Toast.LENGTH_LONG).show();
+ }
+
+ handler.startSignIn(verification.getCredential(), new IdpResponse.Builder(
+ new User.Builder(PhoneAuthProvider.PROVIDER_ID, null)
+ .setPhoneNumber(verification.getNumber())
+ .build())
+ .build());
}
- return;
- }
+
+ @Override
+ protected void onFailure(@NonNull Exception e) {
+ if (e instanceof PhoneNumberVerificationRequiredException) {
+ // Only boot up the submit code fragment if it isn't already being shown to the
+ // user. If the user requests another verification code, the fragment will
+ // already be visible so we have nothing to do.
+ if (getSupportFragmentManager()
+ .findFragmentByTag(SubmitConfirmationCodeFragment.TAG) == null) {
+ showSubmitCodeFragment(
+ ((PhoneNumberVerificationRequiredException) e).getPhoneNumber());
+ }
+
+ // Clear existing errors
+ handleError(null);
+ } else {
+ handleError(e);
+ }
+ }
+ });
+
+ if (savedInstanceState != null) { return; }
Bundle params = getIntent().getExtras().getBundle(ExtraConstants.PARAMS);
- VerifyPhoneNumberFragment fragment = VerifyPhoneNumberFragment.newInstance
- (getFlowParams(), params);
+ CheckPhoneNumberFragment fragment = CheckPhoneNumberFragment.newInstance(params);
getSupportFragmentManager().beginTransaction()
- .replace(R.id.fragment_verify_phone, fragment, VerifyPhoneNumberFragment.TAG)
+ .replace(R.id.fragment_phone, fragment, CheckPhoneNumberFragment.TAG)
.disallowAddToBackStack()
.commit();
}
- @Override
- protected void onStart() {
- super.onStart();
- // Activity can be restarted in any of the following states
- // 1) VERIFICATION_STARTED
- // 2) SMS_RETRIEVED
- // 3) INSTANT_VERIFIED
- // 4) VERIFIED
- // For the first three cases, we can simply resubscribe to the
- // OnVerificationStateChangedCallbacks
- // For 4, we simply finish the activity
- if (mVerificationState.equals(VerificationState.VERIFICATION_STARTED)) {
- sendCode(mPhoneNumber, false);
- } else if (mVerificationState == VerificationState.VERIFIED) {
- // activity was recreated when verified dialog was displayed
- finish(getAuthHelper().getCurrentUser());
- }
- }
-
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
- mVerificationState = VerificationState.VERIFICATION_NOT_STARTED;
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- outState.putSerializable(KEY_STATE, mVerificationState);
- outState.putString(KEY_VERIFICATION_PHONE, mPhoneNumber);
- super.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onDestroy() {
- mIsDestroyed = true;
- mHandler.removeCallbacksAndMessages(null);
- dismissLoadingDialog();
- super.onDestroy();
- }
+ private void handleError(@Nullable Exception e) {
+ TextInputLayout errorView = getErrorView();
+ if (errorView == null) { return; }
- void verifyPhoneNumber(String phoneNumber, boolean forceResend) {
- sendCode(phoneNumber, forceResend);
- if (forceResend) {
- showLoadingDialog(getString(R.string.fui_resending));
+ if (e instanceof FirebaseAuthAnonymousUpgradeException) {
+ IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
+ finish(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT, response.toIntent());
+ } else if (e instanceof FirebaseAuthException) {
+ errorView.setError(getErrorMessage(
+ FirebaseAuthError.fromException((FirebaseAuthException) e)));
+ } else if (e != null) {
+ errorView.setError(e.getLocalizedMessage());
} else {
- showLoadingDialog(getString(R.string.fui_verifying));
- }
- }
-
- public void submitConfirmationCode(@NonNull String confirmationCode) {
- if (TextUtils.isEmpty(mVerificationId) || TextUtils.isEmpty(confirmationCode)) {
- // This situation should never happen except in the case of an extreme race
- // condition, so we will just ignore the submission.
- // See: https://github.com/firebase/FirebaseUI-Android/issues/922
- Log.w(PHONE_VERIFICATION_LOG_TAG,
- String.format("submitConfirmationCode: mVerificationId is %s ; " +
- "confirmationCode is %s",
- TextUtils.isEmpty(mVerificationId) ? "empty" : "not empty",
- TextUtils.isEmpty(confirmationCode) ? "empty" : "not empty"));
- return;
- }
-
- showLoadingDialog(getString(R.string.fui_verifying));
- signIn(PhoneAuthProvider.getCredential(mVerificationId, confirmationCode));
- }
-
- private void onVerificationSuccess(@NonNull final PhoneAuthCredential phoneAuthCredential) {
- if (TextUtils.isEmpty(phoneAuthCredential.getSmsCode())) {
- signIn(phoneAuthCredential);
- } else {
- //Show Fragment if it is not already visible
- showSubmitCodeFragment();
- SubmitConfirmationCodeFragment submitConfirmationCodeFragment =
- getSubmitConfirmationCodeFragment();
-
-
- showLoadingDialog(getString(R.string.fui_retrieving_sms));
- if (submitConfirmationCodeFragment != null) {
- submitConfirmationCodeFragment.setConfirmationCode(String.valueOf
- (phoneAuthCredential.getSmsCode()));
- }
- signIn(phoneAuthCredential);
+ errorView.setError(null);
}
}
- private void onCodeSent() {
- completeLoadingDialog(getString(R.string.fui_code_sent));
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- dismissLoadingDialog();
- showSubmitCodeFragment();
- }
- }, SHORT_DELAY_MILLIS);
- }
-
- private void onVerificationFailed(@NonNull FirebaseException ex) {
- dismissLoadingDialog();
+ @Nullable
+ private TextInputLayout getErrorView() {
+ CheckPhoneNumberFragment checkFragment = (CheckPhoneNumberFragment)
+ getSupportFragmentManager().findFragmentByTag(CheckPhoneNumberFragment.TAG);
+ SubmitConfirmationCodeFragment submitFragment = (SubmitConfirmationCodeFragment)
+ getSupportFragmentManager().findFragmentByTag(SubmitConfirmationCodeFragment.TAG);
- if (ex instanceof FirebaseAuthException) {
- FirebaseAuthError error = FirebaseAuthError.fromException((FirebaseAuthException) ex);
-
- switch (error) {
- case ERROR_INVALID_PHONE_NUMBER:
- VerifyPhoneNumberFragment verifyPhoneNumberFragment = (VerifyPhoneNumberFragment)
- getSupportFragmentManager().findFragmentByTag(VerifyPhoneNumberFragment.TAG);
-
- if (verifyPhoneNumberFragment != null) {
- verifyPhoneNumberFragment.showError(
- getString(R.string.fui_invalid_phone_number));
- }
- break;
- case ERROR_TOO_MANY_REQUESTS:
- showAlertDialog(R.string.fui_error_too_many_attempts, null);
- break;
- case ERROR_QUOTA_EXCEEDED:
- showAlertDialog(R.string.fui_error_quota_exceeded, null);
- break;
- default:
- Log.w(PHONE_VERIFICATION_LOG_TAG, error.getDescription(), ex);
- showAlertDialog(R.string.fui_error_unknown, null);
- }
+ if (checkFragment != null && checkFragment.getView() != null) {
+ return checkFragment.getView().findViewById(R.id.phone_layout);
+ } else if (submitFragment != null && submitFragment.getView() != null) {
+ return submitFragment.getView().findViewById(R.id.confirmation_code_layout);
} else {
- Log.w(PHONE_VERIFICATION_LOG_TAG, "Unknown error", ex);
- showAlertDialog(R.string.fui_error_unknown, null);
+ return null;
}
}
- private void sendCode(String phoneNumber, boolean forceResend) {
- mPhoneNumber = phoneNumber;
- mVerificationState = VerificationState.VERIFICATION_STARTED;
-
- getAuthHelper().getPhoneAuthProvider().verifyPhoneNumber(
- phoneNumber,
- AUTO_RETRIEVAL_TIMEOUT_MILLIS,
- TimeUnit.MILLISECONDS,
- this,
- new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
- @Override
- public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
- if (!mIsDestroyed) {
- PhoneActivity.this.onVerificationSuccess(phoneAuthCredential);
- }
- }
-
- @Override
- public void onVerificationFailed(FirebaseException ex) {
- if (!mIsDestroyed) {
- PhoneActivity.this.onVerificationFailed(ex);
- }
- }
-
- @Override
- public void onCodeSent(@NonNull String verificationId,
- @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
- mVerificationId = verificationId;
- mForceResendingToken = forceResendingToken;
- if (!mIsDestroyed) {
- PhoneActivity.this.onCodeSent();
- }
- }
- },
- forceResend ? mForceResendingToken : null);
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- protected AlertDialog getAlertDialog() {
- // It is hard to test AlertDialogs currently with robo electric. See:
- // https://github.com/robolectric/robolectric/issues/1944
- // We just test that the error was not displayed inline
- return mAlertDialog;
- }
-
- private void showSubmitCodeFragment() {
- // idempotent function
- if (getSubmitConfirmationCodeFragment() == null) {
- SubmitConfirmationCodeFragment f = SubmitConfirmationCodeFragment.newInstance(
- getFlowParams(), mPhoneNumber);
- FragmentTransaction t = getSupportFragmentManager().beginTransaction()
- .replace(R.id.fragment_verify_phone, f, SubmitConfirmationCodeFragment.TAG)
- .addToBackStack(null);
-
- if (!isFinishing() && !mIsDestroyed) {
- t.commitAllowingStateLoss();
- }
+ private String getErrorMessage(FirebaseAuthError error) {
+ switch (error) {
+ case ERROR_INVALID_PHONE_NUMBER:
+ return getString(R.string.fui_invalid_phone_number);
+ case ERROR_TOO_MANY_REQUESTS:
+ return getString(R.string.fui_error_too_many_attempts);
+ case ERROR_QUOTA_EXCEEDED:
+ return getString(R.string.fui_error_quota_exceeded);
+ case ERROR_INVALID_VERIFICATION_CODE:
+ return getString(R.string.fui_incorrect_code_dialog_body);
+ case ERROR_SESSION_EXPIRED:
+ return getString(R.string.fui_error_session_expired);
+ default:
+ return error.getDescription();
}
}
- private void finish(FirebaseUser user) {
- IdpResponse response = new IdpResponse.Builder(
- new User.Builder(PhoneAuthProvider.PROVIDER_ID, null)
- .setPhoneNumber(user.getPhoneNumber())
- .build())
- .build();
- finish(RESULT_OK, response.toIntent());
- }
-
- private void showAlertDialog(@StringRes int messageId,
- DialogInterface.OnClickListener onClickListener) {
-
- String s = getString(messageId);
- mAlertDialog = new AlertDialog.Builder(this)
- .setMessage(s)
- .setPositiveButton(R.string.fui_incorrect_code_dialog_positive_button_text,
- onClickListener)
- .show();
+ private void showSubmitCodeFragment(String number) {
+ getSupportFragmentManager().beginTransaction()
+ .replace(
+ R.id.fragment_phone,
+ SubmitConfirmationCodeFragment.newInstance(number),
+ SubmitConfirmationCodeFragment.TAG)
+ .addToBackStack(null)
+ .commit();
}
- private void signIn(@NonNull PhoneAuthCredential credential) {
- getAuthHelper().getFirebaseAuth()
- .signInWithCredential(credential)
- .addOnSuccessListener(this, new OnSuccessListener() {
- @Override
- public void onSuccess(final AuthResult authResult) {
- mVerificationState = VerificationState.VERIFIED;
- completeLoadingDialog(getString(R.string.fui_verified));
-
- // Activity can be recreated before this message is handled
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (!mIsDestroyed) {
- dismissLoadingDialog();
- finish(authResult.getUser());
- }
- }
- }, SHORT_DELAY_MILLIS);
- }
- })
- .addOnFailureListener(this, new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- dismissLoadingDialog();
- //incorrect confirmation code
- if (e instanceof FirebaseAuthInvalidCredentialsException) {
- FirebaseAuthError error = FirebaseAuthError.fromException(
- (FirebaseAuthInvalidCredentialsException) e);
-
- switch (error) {
- case ERROR_INVALID_VERIFICATION_CODE:
- showAlertDialog(
- R.string.fui_incorrect_code_dialog_body,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- getSubmitConfirmationCodeFragment()
- .setConfirmationCode("");
- }
- });
- break;
- case ERROR_SESSION_EXPIRED:
- showAlertDialog(
- R.string.fui_error_session_expired,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- getSubmitConfirmationCodeFragment()
- .setConfirmationCode("");
- }
- });
- break;
- default:
- Log.w(PHONE_VERIFICATION_LOG_TAG, error.getDescription(), e);
- showAlertDialog(R.string.fui_error_unknown, null);
- }
- } else {
- showAlertDialog(R.string.fui_error_unknown, null);
- }
- }
- });
+ @Override
+ public void showProgress(int message) {
+ getActiveFragment().showProgress(message);
}
- private void completeLoadingDialog(String content) {
- if (mProgressDialog != null) {
- mProgressDialog.onComplete(content);
- }
+ @Override
+ public void hideProgress() {
+ getActiveFragment().hideProgress();
}
- private void showLoadingDialog(String message) {
- dismissLoadingDialog();
-
- if (mProgressDialog == null) {
- mProgressDialog = CompletableProgressDialog.show(getSupportFragmentManager());
+ @NonNull
+ private FragmentBase getActiveFragment() {
+ FragmentBase fragment = (CheckPhoneNumberFragment)
+ getSupportFragmentManager().findFragmentByTag(CheckPhoneNumberFragment.TAG);
+ if (fragment == null || fragment.getView() == null) {
+ fragment = (SubmitConfirmationCodeFragment)
+ getSupportFragmentManager().findFragmentByTag(SubmitConfirmationCodeFragment.TAG);
}
- mProgressDialog.setMessage(message);
- }
-
- private void dismissLoadingDialog() {
- if (mProgressDialog != null && !isFinishing()) {
- mProgressDialog.dismissAllowingStateLoss();
- mProgressDialog = null;
+ if (fragment == null || fragment.getView() == null) {
+ throw new IllegalStateException("No fragments added");
+ } else {
+ return fragment;
}
}
-
- private SubmitConfirmationCodeFragment getSubmitConfirmationCodeFragment() {
- return (SubmitConfirmationCodeFragment) getSupportFragmentManager().findFragmentByTag
- (SubmitConfirmationCodeFragment.TAG);
- }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java
new file mode 100644
index 000000000..ee1ffe53b
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneNumberVerificationHandler.java
@@ -0,0 +1,63 @@
+package com.firebase.ui.auth.ui.phone;
+
+import android.app.Application;
+import android.support.annotation.NonNull;
+
+import com.firebase.ui.auth.data.model.PhoneNumberVerificationRequiredException;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
+import com.google.android.gms.tasks.TaskExecutors;
+import com.google.firebase.FirebaseException;
+import com.google.firebase.auth.PhoneAuthCredential;
+import com.google.firebase.auth.PhoneAuthProvider;
+
+import java.util.concurrent.TimeUnit;
+
+public class PhoneNumberVerificationHandler extends AuthViewModelBase {
+ private static final long AUTO_RETRIEVAL_TIMEOUT_SECONDS = 120;
+
+ private String mVerificationId;
+ private PhoneAuthProvider.ForceResendingToken mForceResendingToken;
+
+ public PhoneNumberVerificationHandler(Application application) {
+ super(application);
+ }
+
+ public void verifyPhoneNumber(final String number, boolean force) {
+ setResult(Resource.forLoading());
+ getPhoneAuth().verifyPhoneNumber(
+ number,
+ AUTO_RETRIEVAL_TIMEOUT_SECONDS,
+ TimeUnit.SECONDS,
+ TaskExecutors.MAIN_THREAD,
+ new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
+ @Override
+ public void onVerificationCompleted(@NonNull PhoneAuthCredential credential) {
+ setResult(Resource.forSuccess(new PhoneVerification(
+ number, credential, true)));
+ }
+
+ @Override
+ public void onVerificationFailed(FirebaseException e) {
+ setResult(Resource.forFailure(e));
+ }
+
+ @Override
+ public void onCodeSent(@NonNull String verificationId,
+ @NonNull PhoneAuthProvider.ForceResendingToken token) {
+ mVerificationId = verificationId;
+ mForceResendingToken = token;
+ setResult(Resource.forFailure(
+ new PhoneNumberVerificationRequiredException(number)));
+ }
+ },
+ force ? mForceResendingToken : null);
+ }
+
+ public void submitVerificationCode(String number, String code) {
+ setResult(Resource.forSuccess(new PhoneVerification(
+ number,
+ PhoneAuthProvider.getCredential(mVerificationId, code),
+ false)));
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerification.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerification.java
new file mode 100644
index 000000000..ee73e7b6a
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerification.java
@@ -0,0 +1,63 @@
+package com.firebase.ui.auth.ui.phone;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import com.google.firebase.auth.PhoneAuthCredential;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class PhoneVerification {
+ private final String mNumber;
+ private final PhoneAuthCredential mCredential;
+ private final boolean mIsAutoVerified;
+
+ public PhoneVerification(@NonNull String number,
+ @NonNull PhoneAuthCredential credential,
+ boolean verified) {
+ mNumber = number;
+ mCredential = credential;
+ mIsAutoVerified = verified;
+ }
+
+ @NonNull
+ public String getNumber() {
+ return mNumber;
+ }
+
+ @NonNull
+ public PhoneAuthCredential getCredential() {
+ return mCredential;
+ }
+
+ public boolean isAutoVerified() {
+ return mIsAutoVerified;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PhoneVerification that = (PhoneVerification) o;
+
+ return mIsAutoVerified == that.mIsAutoVerified
+ && mNumber.equals(that.mNumber)
+ && mCredential.equals(that.mCredential);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mNumber.hashCode();
+ result = 31 * result + mCredential.hashCode();
+ result = 31 * result + (mIsAutoVerified ? 1 : 0);
+ return result;
+ }
+
+ public String toString() {
+ return "PhoneVerification{" +
+ "mNumber='" + mNumber + '\'' +
+ ", mCredential=" + mCredential +
+ ", mIsAutoVerified=" + mIsAutoVerified +
+ '}';
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/SubmitConfirmationCodeFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/SubmitConfirmationCodeFragment.java
index 4b0e20f25..314486e7c 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/SubmitConfirmationCodeFragment.java
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/SubmitConfirmationCodeFragment.java
@@ -14,32 +14,32 @@
package com.firebase.ui.auth.ui.phone;
+import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.os.Bundle;
+import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.app.FragmentActivity;
-import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
+import android.widget.ProgressBar;
import android.widget.TextView;
import com.firebase.ui.auth.R;
-import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.ui.FragmentBase;
-import com.firebase.ui.auth.util.CustomCountDownTimer;
import com.firebase.ui.auth.util.ExtraConstants;
import com.firebase.ui.auth.util.data.PrivacyDisclosureUtils;
import com.firebase.ui.auth.util.ui.BucketedTextChangeListener;
import com.firebase.ui.auth.util.ui.ImeHelper;
+import java.util.concurrent.TimeUnit;
+
/**
- * Display confirmation code to verify phone numbers input in {{@link VerifyPhoneNumberFragment}}
+ * Display confirmation code to verify phone numbers input in {{@link CheckPhoneNumberFragment}}
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class SubmitConfirmationCodeFragment extends FragmentBase {
@@ -47,228 +47,188 @@ public class SubmitConfirmationCodeFragment extends FragmentBase {
public static final String TAG = "SubmitConfirmationCodeFragment";
private static final long RESEND_WAIT_MILLIS = 15000;
- private static final String EXTRA_MILLIS_UNTIL_FINISHED = "EXTRA_MILLIS_UNTIL_FINISHED";
+ private static final long TICK_INTERVAL_MILLIS = 500;
+ private static final String EXTRA_MILLIS_UNTIL_FINISHED = "millis_until_finished";
+
+ private final Handler mLooper = new Handler();
+ private final Runnable mCountdown = new Runnable() {
+ @Override
+ public void run() {
+ processCountdownTick();
+ }
+ };
+
+ private PhoneNumberVerificationHandler mHandler;
+ private String mPhoneNumber;
- private TextView mEditPhoneTextView;
+ private ProgressBar mProgressBar;
+ private TextView mPhoneTextView;
private TextView mResendCodeTextView;
private TextView mCountDownTextView;
private SpacedEditText mConfirmationCodeEditText;
private Button mSubmitConfirmationButton;
- private CustomCountDownTimer mCountdownTimer;
- private PhoneActivity mVerifier;
- private long mMillisUntilFinished;
+ private long mMillisUntilFinished = RESEND_WAIT_MILLIS;
- public static SubmitConfirmationCodeFragment newInstance(FlowParameters flowParameters,
- String phoneNumber) {
+ public static SubmitConfirmationCodeFragment newInstance(String phoneNumber) {
SubmitConfirmationCodeFragment fragment = new SubmitConfirmationCodeFragment();
-
Bundle args = new Bundle();
- args.putParcelable(ExtraConstants.FLOW_PARAMS, flowParameters);
args.putString(ExtraConstants.PHONE, phoneNumber);
-
fragment.setArguments(args);
return fragment;
}
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mHandler = ViewModelProviders.of(requireActivity())
+ .get(PhoneNumberVerificationHandler.class);
+ mPhoneNumber = getArguments().getString(ExtraConstants.PHONE);
+ if (savedInstanceState != null) {
+ mMillisUntilFinished = savedInstanceState.getLong(EXTRA_MILLIS_UNTIL_FINISHED);
+ }
+ }
+
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fui_confirmation_code_layout, container, false);
- FragmentActivity parentActivity = getActivity();
-
- mEditPhoneTextView = v.findViewById(R.id.edit_phone_number);
- mCountDownTextView = v.findViewById(R.id.ticker);
- mResendCodeTextView = v.findViewById(R.id.resend_code);
- mConfirmationCodeEditText = v.findViewById(R.id.confirmation_code);
- mSubmitConfirmationButton = v.findViewById(R.id.submit_confirmation_code);
-
- final String phoneNumber = getArguments().getString(ExtraConstants.PHONE);
-
- parentActivity.setTitle(getString(R.string.fui_verify_your_phone_title));
- setupConfirmationCodeEditText();
- setupEditPhoneNumberTextView(phoneNumber);
- setupCountDown(RESEND_WAIT_MILLIS);
- setupSubmitConfirmationCodeButton();
- setupResendConfirmationCodeTextView(phoneNumber);
- return v;
+ return inflater.inflate(R.layout.fui_confirmation_code_layout, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- TextView footerText = view.findViewById(R.id.email_footer_tos_and_pp_text);
- PrivacyDisclosureUtils.setupTermsOfServiceFooter(getContext(), getFlowParams(), footerText);
+ mProgressBar = view.findViewById(R.id.top_progress_bar);
+ mPhoneTextView = view.findViewById(R.id.edit_phone_number);
+ mCountDownTextView = view.findViewById(R.id.ticker);
+ mResendCodeTextView = view.findViewById(R.id.resend_code);
+ mConfirmationCodeEditText = view.findViewById(R.id.confirmation_code);
+ mSubmitConfirmationButton = view.findViewById(R.id.submit_confirmation_code);
+
+ requireActivity().setTitle(getString(R.string.fui_verify_your_phone_title));
+ processCountdownTick();
+ setupSubmitConfirmationButton();
+ setupConfirmationCodeEditText();
+ setupEditPhoneNumberTextView();
+ setupResendConfirmationCodeTextView();
+ PrivacyDisclosureUtils.setupTermsOfServiceFooter(
+ requireContext(),
+ getFlowParams(),
+ view.findViewById(R.id.email_footer_tos_and_pp_text));
}
@Override
public void onStart() {
super.onStart();
mConfirmationCodeEditText.requestFocus();
- InputMethodManager imgr = (InputMethodManager) getActivity().getSystemService(
- Context.INPUT_METHOD_SERVICE);
- imgr.showSoftInput(mConfirmationCodeEditText, 0);
+ ((InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE))
+ .showSoftInput(mConfirmationCodeEditText, 0);
}
@Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- if (savedInstanceState != null) {
- mCountdownTimer.update(savedInstanceState.getLong(EXTRA_MILLIS_UNTIL_FINISHED));
- }
-
- if (!(getActivity() instanceof PhoneActivity)) {
- throw new IllegalStateException("Activity must implement PhoneVerificationHandler");
- }
- mVerifier = (PhoneActivity) getActivity();
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ mLooper.removeCallbacks(mCountdown);
+ outState.putLong(EXTRA_MILLIS_UNTIL_FINISHED, mMillisUntilFinished);
}
@Override
public void onDestroy() {
- cancelTimer();
super.onDestroy();
+ // Remove here in addition to onSaveInstanceState since it might not be called if finishing
+ // for good.
+ mLooper.removeCallbacks(mCountdown);
}
- @Override
- public void onSaveInstanceState(@NonNull Bundle outState) {
- outState.putLong(EXTRA_MILLIS_UNTIL_FINISHED, mMillisUntilFinished);
- }
-
- private void setTimer(long millisUntilFinished) {
- mCountDownTextView.setText(String.format(getString(R.string.fui_resend_code_in),
- timeRoundedToSeconds(millisUntilFinished)));
- }
-
- private void setupResendConfirmationCodeTextView(final String phoneNumber) {
- mResendCodeTextView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mVerifier.verifyPhoneNumber(phoneNumber, true);
- mResendCodeTextView.setVisibility(View.GONE);
- mCountDownTextView.setVisibility(View.VISIBLE);
- mCountDownTextView.setText(String.format(getString(R.string.fui_resend_code_in),
- RESEND_WAIT_MILLIS / 1000));
- mCountdownTimer.renew();
- }
- });
- }
-
- private void setupCountDown(long startTimeMillis) {
- //set the timer view
- setTimer(startTimeMillis / 1000);
-
- //create a countdown
- mCountdownTimer = createCountDownTimer(mCountDownTextView, mResendCodeTextView, this,
- startTimeMillis);
-
- //start the countdown
- startTimer();
- }
-
- private void setupSubmitConfirmationCodeButton() {
+ private void setupSubmitConfirmationButton() {
mSubmitConfirmationButton.setEnabled(false);
-
mSubmitConfirmationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- submitConfirmationCode();
- }
- });
- }
-
- private void submitConfirmationCode() {
- mVerifier.submitConfirmationCode(mConfirmationCodeEditText.getUnspacedText().toString());
- }
-
- private void setupEditPhoneNumberTextView(@Nullable String phoneNumber) {
- mEditPhoneTextView.setText(TextUtils.isEmpty(phoneNumber) ? "" : phoneNumber);
- mEditPhoneTextView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (getFragmentManager().getBackStackEntryCount() > 0) {
- getFragmentManager().popBackStack();
- }
+ submitCode();
}
});
}
private void setupConfirmationCodeEditText() {
mConfirmationCodeEditText.setText("------");
- BucketedTextChangeListener listener = createBucketedTextChangeListener();
- mConfirmationCodeEditText.addTextChangedListener(listener);
+ mConfirmationCodeEditText.addTextChangedListener(new BucketedTextChangeListener(
+ mConfirmationCodeEditText, 6, "-",
+ new BucketedTextChangeListener.ContentChangeCallback() {
+ @Override
+ public void whileComplete() {
+ mSubmitConfirmationButton.setEnabled(true);
+ }
+
+ @Override
+ public void whileIncomplete() {
+ mSubmitConfirmationButton.setEnabled(false);
+ }
+ }));
+
ImeHelper.setImeOnDoneListener(mConfirmationCodeEditText,
new ImeHelper.DonePressedListener() {
@Override
public void onDonePressed() {
if (mSubmitConfirmationButton.isEnabled()) {
- submitConfirmationCode();
+ submitCode();
}
}
});
}
- private BucketedTextChangeListener createBucketedTextChangeListener() {
- return new BucketedTextChangeListener(this.mConfirmationCodeEditText, 6, "-",
- createBucketOnEditCallback(mSubmitConfirmationButton));
- }
-
- private void startTimer() {
- if (mCountdownTimer != null) {
- mCountdownTimer.start();
- }
+ private void setupEditPhoneNumberTextView() {
+ mPhoneTextView.setText(mPhoneNumber);
+ mPhoneTextView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getFragmentManager().popBackStack();
+ }
+ });
}
- private void cancelTimer() {
- if (mCountdownTimer != null) {
- mCountdownTimer.cancel();
- }
- }
+ private void setupResendConfirmationCodeTextView() {
+ mResendCodeTextView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHandler.verifyPhoneNumber(mPhoneNumber, true);
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- CustomCountDownTimer getCountdownTimer() {
- return mCountdownTimer;
+ mResendCodeTextView.setVisibility(View.GONE);
+ mCountDownTextView.setVisibility(View.VISIBLE);
+ mCountDownTextView.setText(String.format(getString(R.string.fui_resend_code_in),
+ RESEND_WAIT_MILLIS / 1000));
+ mMillisUntilFinished = RESEND_WAIT_MILLIS;
+ mLooper.postDelayed(mCountdown, TICK_INTERVAL_MILLIS);
+ }
+ });
}
- private int timeRoundedToSeconds(double millis) {
- return (int) Math.ceil(millis / 1000);
+ private void processCountdownTick() {
+ mMillisUntilFinished -= TICK_INTERVAL_MILLIS;
+ if (mMillisUntilFinished <= 0) {
+ mCountDownTextView.setText("");
+ mCountDownTextView.setVisibility(View.GONE);
+ mResendCodeTextView.setVisibility(View.VISIBLE);
+ } else {
+ mCountDownTextView.setText(String.format(getString(R.string.fui_resend_code_in),
+ TimeUnit.MILLISECONDS.toSeconds(mMillisUntilFinished) + 1));
+ mLooper.postDelayed(mCountdown, TICK_INTERVAL_MILLIS);
+ }
}
- private CustomCountDownTimer createCountDownTimer(final TextView timerText, final TextView
- resendCode, final SubmitConfirmationCodeFragment fragment, final long startTimeMillis) {
- return new CustomCountDownTimer(startTimeMillis, 500) {
- SubmitConfirmationCodeFragment mSubmitConfirmationCodeFragment = fragment;
-
- public void onTick(long millisUntilFinished) {
- mMillisUntilFinished = millisUntilFinished;
- mSubmitConfirmationCodeFragment.setTimer(millisUntilFinished);
- }
-
- public void onFinish() {
- timerText.setText("");
- timerText.setVisibility(View.GONE);
- resendCode.setVisibility(View.VISIBLE);
- }
- };
+ private void submitCode() {
+ mHandler.submitVerificationCode(
+ mPhoneNumber, mConfirmationCodeEditText.getUnspacedText().toString());
}
- private BucketedTextChangeListener.ContentChangeCallback createBucketOnEditCallback(final
- Button button) {
- return new BucketedTextChangeListener.ContentChangeCallback() {
- @Override
- public void whileComplete() {
- button.setEnabled(true);
- }
-
- @Override
- public void whileIncomplete() {
- button.setEnabled(false);
- }
- };
+ @Override
+ public void showProgress(int message) {
+ mSubmitConfirmationButton.setEnabled(false);
+ mProgressBar.setVisibility(View.VISIBLE);
}
- void setConfirmationCode(String code) {
- mConfirmationCodeEditText.setText(code);
+ @Override
+ public void hideProgress() {
+ mSubmitConfirmationButton.setEnabled(true);
+ mProgressBar.setVisibility(View.INVISIBLE);
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/VerifyPhoneNumberFragment.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/VerifyPhoneNumberFragment.java
deleted file mode 100644
index 721632025..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/VerifyPhoneNumberFragment.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright 2017 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.firebase.ui.auth.ui.phone;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.design.widget.TextInputLayout;
-import android.support.v4.app.FragmentActivity;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.firebase.ui.auth.R;
-import com.firebase.ui.auth.data.model.CountryInfo;
-import com.firebase.ui.auth.data.model.FlowParameters;
-import com.firebase.ui.auth.data.model.PhoneNumber;
-import com.firebase.ui.auth.ui.FragmentBase;
-import com.firebase.ui.auth.util.ExtraConstants;
-import com.firebase.ui.auth.util.GoogleApiUtils;
-import com.firebase.ui.auth.util.data.PhoneNumberUtils;
-import com.firebase.ui.auth.util.data.PrivacyDisclosureUtils;
-import com.firebase.ui.auth.util.ui.ImeHelper;
-import com.firebase.ui.auth.viewmodel.RequestCodes;
-import com.google.android.gms.auth.api.credentials.Credential;
-import com.google.android.gms.auth.api.credentials.CredentialPickerConfig;
-import com.google.android.gms.auth.api.credentials.HintRequest;
-
-import java.util.Locale;
-
-/**
- * Displays country selector and phone number input form for users
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class VerifyPhoneNumberFragment extends FragmentBase implements View.OnClickListener {
- public static final String TAG = "VerifyPhoneFragment";
- private Context mAppContext;
-
- private CountryListSpinner mCountryListSpinner;
- private TextInputLayout mPhoneInputLayout;
- private EditText mPhoneEditText;
- private Button mSendCodeButton;
- private PhoneActivity mVerifier;
- private TextView mSmsTermsText;
-
- public static VerifyPhoneNumberFragment newInstance(
- FlowParameters flowParameters, Bundle params) {
- VerifyPhoneNumberFragment fragment = new VerifyPhoneNumberFragment();
-
- Bundle args = new Bundle();
- args.putParcelable(ExtraConstants.FLOW_PARAMS, flowParameters);
- args.putBundle(ExtraConstants.PARAMS, params);
-
- fragment.setArguments(args);
- return fragment;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- mAppContext = context.getApplicationContext();
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
-
- View v = inflater.inflate(R.layout.fui_phone_layout, container, false);
-
- mCountryListSpinner = v.findViewById(R.id.country_list);
- mPhoneInputLayout = v.findViewById(R.id.phone_layout);
- mPhoneEditText = v.findViewById(R.id.phone_number);
- mSendCodeButton = v.findViewById(R.id.send_code);
- mSmsTermsText = v.findViewById(R.id.send_sms_tos);
-
- ImeHelper.setImeOnDoneListener(mPhoneEditText, new ImeHelper.DonePressedListener() {
- @Override
- public void onDonePressed() {
- onNext();
- }
- });
-
- FragmentActivity parentActivity = getActivity();
- parentActivity.setTitle(getString(R.string.fui_verify_phone_number_title));
- setupCountrySpinner();
- setupSendCodeButton();
- return v;
- }
-
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- TextView footerText = view.findViewById(R.id.email_footer_tos_and_pp_text);
- setupPrivacyDisclosures(footerText);
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- // Set listener
- if (!(getActivity() instanceof PhoneActivity)) {
- throw new IllegalStateException("Activity must implement PhoneVerificationHandler");
- }
- mVerifier = (PhoneActivity) getActivity();
-
- if (savedInstanceState != null) {
- return;
- }
-
- // Check for phone
- // It is assumed that the phone number that are being wired in via Credential Selector
- // are e164 since we store it.
- Bundle params = getArguments().getBundle(ExtraConstants.PARAMS);
- String phone = null;
- String countryIso = null;
- String nationalNumber = null;
- if (params != null) {
- phone = params.getString(ExtraConstants.PHONE);
- countryIso = params.getString(ExtraConstants.COUNTRY_ISO);
- nationalNumber = params.getString(ExtraConstants.NATIONAL_NUMBER);
- }
- if (!TextUtils.isEmpty(countryIso) && !TextUtils.isEmpty(nationalNumber)) {
- // User supplied country code & national number
- PhoneNumber phoneNumber = PhoneNumberUtils.getPhoneNumber(countryIso, nationalNumber);
- setPhoneNumber(phoneNumber);
- setCountryCode(phoneNumber);
- } else if (!TextUtils.isEmpty(countryIso)) {
- setCountryCode(new PhoneNumber(
- "",
- countryIso,
- String.valueOf(PhoneNumberUtils.getCountryCode(countryIso))));
- } else if (!TextUtils.isEmpty(phone)) {
- // User supplied full phone number
- PhoneNumber phoneNumber = PhoneNumberUtils.getPhoneNumber(phone);
- setPhoneNumber(phoneNumber);
- setCountryCode(phoneNumber);
- } else if (getFlowParams().enableHints) {
- // Try SmartLock phone autocomplete hint
- showPhoneAutoCompleteHint();
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == RequestCodes.CRED_HINT) {
- if (data != null) {
- Credential cred = data.getParcelableExtra(Credential.EXTRA_KEY);
- if (cred != null) {
- // Hint selector does not always return phone numbers in e164 format.
- // To accommodate either case, we normalize to e164 with best effort
- final String unformattedPhone = cred.getId();
- final String formattedPhone =
- PhoneNumberUtils.formatUsingCurrentCountry(unformattedPhone,
- mAppContext);
- if (formattedPhone == null) {
- Log.e(TAG, "Unable to normalize phone number from hint selector:"
- + unformattedPhone);
- return;
- }
- final PhoneNumber phoneNumberObj =
- PhoneNumberUtils.getPhoneNumber(formattedPhone);
- setPhoneNumber(phoneNumberObj);
- setCountryCode(phoneNumberObj);
- onNext();
- }
- }
- }
- }
-
- @Override
- public void onClick(View v) {
- onNext();
- }
-
- private void onNext() {
- String phoneNumber = getPseudoValidPhoneNumber();
- if (phoneNumber == null) {
- mPhoneInputLayout.setError(getString(R.string.fui_invalid_phone_number));
- } else {
- mPhoneInputLayout.setError(null);
- mVerifier.verifyPhoneNumber(phoneNumber, false);
- }
- }
-
- @Nullable
- private String getPseudoValidPhoneNumber() {
- final CountryInfo countryInfo = mCountryListSpinner.getSelectedCountryInfo();
- final String everythingElse = mPhoneEditText.getText().toString();
-
- if (TextUtils.isEmpty(everythingElse)) {
- return null;
- }
-
- return PhoneNumberUtils.format(everythingElse, countryInfo);
- }
-
- private void setupCountrySpinner() {
- //clear error when spinner is clicked on
- mCountryListSpinner.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mPhoneInputLayout.setError(null);
- }
- });
- }
-
- private void setupSendCodeButton() {
- mSendCodeButton.setOnClickListener(this);
- }
-
- private void showPhoneAutoCompleteHint() {
- try {
- startIntentSenderForResult(
- getPhoneHintIntent().getIntentSender(),
- RequestCodes.CRED_HINT,
- null,
- 0,
- 0,
- 0,
- null);
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "Unable to start hint intent", e);
- }
- }
-
- private PendingIntent getPhoneHintIntent() {
- HintRequest hintRequest = new HintRequest.Builder()
- .setHintPickerConfig(
- new CredentialPickerConfig.Builder().setShowCancelButton(true).build())
- .setPhoneNumberIdentifierSupported(true)
- .setEmailAddressIdentifierSupported(false)
- .build();
-
- return GoogleApiUtils.getCredentialsClient(getContext()).getHintPickerIntent(hintRequest);
- }
-
- private void setPhoneNumber(PhoneNumber phoneNumber) {
- if (PhoneNumber.isValid(phoneNumber)) {
- mPhoneEditText.setText(phoneNumber.getPhoneNumber());
- mPhoneEditText.setSelection(phoneNumber.getPhoneNumber().length());
- }
- }
-
- private void setCountryCode(PhoneNumber phoneNumber) {
- if (PhoneNumber.isCountryValid(phoneNumber)) {
- mCountryListSpinner.setSelectedForCountry(new Locale("", phoneNumber.getCountryIso()),
- phoneNumber.getCountryCode());
- }
- }
-
- private void setupPrivacyDisclosures(TextView footerText) {
- final String verifyPhoneButtonText = getString(R.string.fui_verify_phone_number);
- final String multipleProviderFlowText = getString(R.string.fui_sms_terms_of_service,
- verifyPhoneButtonText);
- FlowParameters flowParameters = getFlowParams();
-
- if (flowParameters.isSingleProviderFlow()) {
- PrivacyDisclosureUtils.setupTermsOfServiceAndPrivacyPolicySmsText(getContext(),
- flowParameters,
- mSmsTermsText);
- } else {
- PrivacyDisclosureUtils.setupTermsOfServiceFooter(getContext(),
- flowParameters,
- footerText);
- mSmsTermsText.setText(multipleProviderFlowText);
- }
- }
-
- void showError(String e) {
- mPhoneInputLayout.setError(e);
- }
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/provider/GitHubLoginActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/provider/GitHubLoginActivity.java
new file mode 100644
index 000000000..6877cf78c
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/provider/GitHubLoginActivity.java
@@ -0,0 +1,125 @@
+package com.firebase.ui.auth.ui.provider;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.customtabs.CustomTabsIntent;
+import android.support.v4.content.ContextCompat;
+
+import com.firebase.ui.auth.R;
+import com.firebase.ui.auth.data.remote.GitHubSignInHandler;
+import com.firebase.ui.auth.ui.HelperActivityBase;
+import com.firebase.ui.auth.util.ExtraConstants;
+
+/**
+ * These are our goals for GitHub login:
+ *
- Launch CCT
+ *
- If user presses back, close resources related to CCT
+ *
- Same for success and failure, but send result data too
+ *
+ * Given that CCT is going to redirect to our activity, we need a wrapper with special stuff like
+ * `singleTop` and ignored config changes so the stack doesn't nest itself—hence this activity. Now
+ * that we're guaranteed to have a single activity with a CCT layer on top, we can safely assume
+ * that `onCreate` is the only place to start CCT. So the current flow now looks like this:
+ *
- Launch CCT in `onCreate`
+ *
- Receive redirects in `onNewIntent`
+ *
+ * That flow creates a problem though: how do we close CCT? Android doesn't give you a nice way to
+ * close all activities on top of the stack, so we're forced to relaunch our wrapper activity with
+ * the CLEAR_TOP flag. That will recurse while killing CCT to bring us back to `onNewIntent` again
+ * where we check for the refresh action. At that point, we can finally finish with our result.
+ *
+ * Now for the `onResume` stuff. Remember how we always have a CCT layer on top? That means
+ * `onResume` will only ever be called once... unless the user presses back. At that point, our
+ * wrapper activity gains focus for the second time and we can safely kill it knowing it was a back
+ * event.
+ */
+@SuppressLint("GoogleAppIndexingApiWarning")
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class GitHubLoginActivity extends HelperActivityBase {
+ private static final String REFRESH_ACTION = "refresh_action";
+ private static final String SHOULD_CLOSE_CCT_KEY = "should_close_cct_key";
+
+ private boolean mShouldCloseCustomTab;
+
+ @NonNull
+ public static Intent createIntent(Context context, Uri starter) {
+ return new Intent(context, GitHubLoginActivity.class)
+ .putExtra(ExtraConstants.GITHUB_URL, starter);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState == null) {
+ new CustomTabsIntent.Builder()
+ .setShowTitle(true)
+ .enableUrlBarHiding()
+ .setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
+ .build()
+ .launchUrl(this,
+ (Uri) getIntent().getParcelableExtra(ExtraConstants.GITHUB_URL));
+ mShouldCloseCustomTab = false;
+ } else {
+ mShouldCloseCustomTab = savedInstanceState.getBoolean(SHOULD_CLOSE_CCT_KEY);
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mShouldCloseCustomTab) { // User pressed back
+ finish(RESULT_CANCELED, null);
+ }
+ mShouldCloseCustomTab = true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(SHOULD_CLOSE_CCT_KEY, mShouldCloseCustomTab);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ mShouldCloseCustomTab = false;
+
+ if (REFRESH_ACTION.equals(intent.getAction())) {
+ finish(RESULT_OK, (Intent) intent.getParcelableExtra(ExtraConstants.PARAMS));
+ return;
+ }
+
+ Intent result = new Intent();
+
+ String code = intent.getData().getQueryParameter("code");
+ if (code == null) {
+ result.putExtra(GitHubSignInHandler.RESULT_CODE, RESULT_CANCELED);
+ } else {
+ result.putExtra(GitHubSignInHandler.RESULT_CODE, RESULT_OK)
+ .putExtra(GitHubSignInHandler.KEY_GITHUB_CODE, code);
+ }
+
+ // Force a recursive launch to clear the Custom Tabs activity
+ startActivity(new Intent(this, GitHubLoginActivity.class)
+ .putExtra(ExtraConstants.PARAMS, result)
+ .setAction(REFRESH_ACTION)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP));
+ }
+
+ @Override
+ public void showProgress(int message) {
+ throw new UnsupportedOperationException(
+ "GitHubLoginActivity is just a wrapper around Chrome Custom Tabs");
+ }
+
+ @Override
+ public void hideProgress() {
+ throw new UnsupportedOperationException(
+ "GitHubLoginActivity is just a wrapper around Chrome Custom Tabs");
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/AuthHelper.java b/auth/src/main/java/com/firebase/ui/auth/util/AuthHelper.java
deleted file mode 100644
index db6007cfa..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/util/AuthHelper.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.firebase.ui.auth.util;
-
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-
-import com.firebase.ui.auth.data.model.FlowParameters;
-import com.google.firebase.FirebaseApp;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.auth.FirebaseUser;
-import com.google.firebase.auth.PhoneAuthProvider;
-
-/**
- * Factory for instances of authentication classes. Should eventually be replaced by dependency
- * injection.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class AuthHelper {
- private final FlowParameters mFlowParams;
-
- public AuthHelper(FlowParameters params) {
- mFlowParams = params;
- }
-
- public FirebaseAuth getFirebaseAuth() {
- return FirebaseAuth.getInstance(FirebaseApp.getInstance(mFlowParams.appName));
- }
-
- @Nullable
- public FirebaseUser getCurrentUser() {
- return getFirebaseAuth().getCurrentUser();
- }
-
- public PhoneAuthProvider getPhoneAuthProvider() {
- return PhoneAuthProvider.getInstance(getFirebaseAuth());
- }
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/CustomCountDownTimer.java b/auth/src/main/java/com/firebase/ui/auth/util/CustomCountDownTimer.java
deleted file mode 100644
index cb7577211..000000000
--- a/auth/src/main/java/com/firebase/ui/auth/util/CustomCountDownTimer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2017 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.firebase.ui.auth.util;
-
-import android.os.CountDownTimer;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public abstract class CustomCountDownTimer {
- private final long mMillisInFuture;
- private final long mCountDownInterval;
- private CountDownTimer mCountDownTimer;
-
- protected CustomCountDownTimer(long millisInFuture, long countDownInterval) {
- mMillisInFuture = millisInFuture;
- mCountDownInterval = countDownInterval;
- mCountDownTimer = create(millisInFuture, countDownInterval);
- }
-
- public void update(long millisInFuture) {
- mCountDownTimer.cancel();
- mCountDownTimer = create(millisInFuture, mCountDownInterval);
- mCountDownTimer.start();
- }
-
- public void renew() {
- update(mMillisInFuture);
- }
-
- private CountDownTimer create(long millisInFuture, long countDownInterval) {
- return new CountDownTimer(millisInFuture, countDownInterval) {
- @Override
- public void onTick(long millisUntilFinished) {
- CustomCountDownTimer.this.onTick(millisUntilFinished);
- }
-
- @Override
- public void onFinish() {
- CustomCountDownTimer.this.onFinish();
- }
- };
- }
-
- public void cancel() {
- mCountDownTimer.cancel();
- }
-
- public void start() {
- mCountDownTimer.start();
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
- public abstract void onFinish();
-
- protected abstract void onTick(long millisUntilFinished);
-}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java b/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java
index 7e2035a0f..96e5a6627 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/ExtraConstants.java
@@ -31,12 +31,17 @@ public final class ExtraConstants {
public static final String REQUIRE_NAME = "extra_require_name";
public static final String GOOGLE_SIGN_IN_OPTIONS = "extra_google_sign_in_options";
public static final String FACEBOOK_PERMISSIONS = "extra_facebook_permissions";
+ public static final String GITHUB_PERMISSIONS = "extra_github_permissions";
+ public static final String GITHUB_URL = "github_url";
public static final String PARAMS = "extra_params";
public static final String PHONE = "extra_phone_number";
public static final String COUNTRY_ISO = "extra_country_iso";
public static final String NATIONAL_NUMBER = "extra_national_number";
+ public static final String WHITELISTED_COUNTRIES = "whitelisted_countries";
+ public static final String BLACKLISTED_COUNTRIES = "blacklisted_countries";
+
private ExtraConstants() {
throw new AssertionError("No instance for you!");
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/Preconditions.java b/auth/src/main/java/com/firebase/ui/auth/util/Preconditions.java
index f594655d8..465341e5c 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/Preconditions.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/Preconditions.java
@@ -91,4 +91,17 @@ public static void checkConfigured(@NonNull Context context,
}
}
}
+
+ /**
+ * Ensures the truth of an expression involving parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @param errorMessage the exception message to use if the check fails
+ * @throws IllegalArgumentException if {@code expression} is false
+ */
+ public static void checkArgument(boolean expression, String errorMessage) {
+ if (!expression) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/AuthOperationManager.java b/auth/src/main/java/com/firebase/ui/auth/util/data/AuthOperationManager.java
new file mode 100644
index 000000000..1a5288a5d
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/util/data/AuthOperationManager.java
@@ -0,0 +1,105 @@
+package com.firebase.ui.auth.util.data;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+
+import com.firebase.ui.auth.data.model.FlowParameters;
+import com.google.android.gms.tasks.Continuation;
+import com.google.android.gms.tasks.Task;
+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.FirebaseAuth;
+
+/**
+ * Utilities to help with Anonymous user upgrade.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class AuthOperationManager {
+
+ private static String firebaseAppName = "FUIScratchApp";
+
+ private static AuthOperationManager mAuthManager;
+
+ @VisibleForTesting
+ public FirebaseAuth mScratchAuth;
+
+ private AuthOperationManager() {}
+
+ public static synchronized AuthOperationManager getInstance() {
+ if (mAuthManager == null) {
+ mAuthManager = new AuthOperationManager();
+ }
+ return mAuthManager;
+ }
+
+ private FirebaseApp getScratchApp(FirebaseApp defaultApp) {
+ try {
+ return FirebaseApp.getInstance(firebaseAppName);
+ } catch (IllegalStateException e) {
+ return FirebaseApp.initializeApp(defaultApp.getApplicationContext(),
+ defaultApp.getOptions(), firebaseAppName);
+ }
+ }
+
+ private FirebaseAuth getScratchAuth(FlowParameters flowParameters) {
+ // Use a different FirebaseApp so that the anonymous user state is not lost in our
+ // original FirebaseAuth instance.
+ if (mScratchAuth == null) {
+ FirebaseApp app = FirebaseApp.getInstance(flowParameters.appName);
+ mScratchAuth = FirebaseAuth.getInstance(getScratchApp(app));
+ }
+ return mScratchAuth;
+ }
+
+ public Task createOrLinkUserWithEmailAndPassword(@NonNull FirebaseAuth auth,
+ @NonNull FlowParameters flowParameters,
+ @NonNull String email,
+ @NonNull String password) {
+ if (canUpgradeAnonymous(auth, flowParameters)) {
+ AuthCredential credential = EmailAuthProvider.getCredential(email, password);
+ return auth.getCurrentUser().linkWithCredential(credential);
+ } else {
+ return auth.createUserWithEmailAndPassword(email, password);
+ }
+ }
+
+ public Task signInAndLinkWithCredential(@NonNull FirebaseAuth auth,
+ @NonNull FlowParameters flowParameters,
+ @NonNull AuthCredential credential) {
+ if (canUpgradeAnonymous(auth, flowParameters)) {
+ return auth.getCurrentUser().linkWithCredential(credential);
+ } else {
+ return auth.signInWithCredential(credential);
+ }
+ }
+
+ public boolean canUpgradeAnonymous(FirebaseAuth auth, FlowParameters flowParameters) {
+ return flowParameters.isAnonymousUpgradeEnabled() && auth.getCurrentUser() != null &&
+ auth.getCurrentUser().isAnonymous();
+ }
+
+ @NonNull
+ public Task validateCredential(AuthCredential credential,
+ FlowParameters flowParameters) {
+ return getScratchAuth(flowParameters).signInWithCredential(credential);
+ }
+
+ public Task safeLink(final AuthCredential credential,
+ final AuthCredential credentialToLink,
+ final FlowParameters flowParameters) {
+ return getScratchAuth(flowParameters)
+ .signInWithCredential(credential)
+ .continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ if (task.isSuccessful()) {
+ return task.getResult().getUser().linkWithCredential(credentialToLink);
+ }
+ return task;
+ }
+ });
+ }
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/PhoneNumberUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/data/PhoneNumberUtils.java
index 704bb3060..53f84e8a4 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/data/PhoneNumberUtils.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/data/PhoneNumberUtils.java
@@ -51,8 +51,8 @@ public final class PhoneNumberUtils {
private static final SparseArray> COUNTRY_TO_REGION_CODES =
createCountryCodeToRegionCodeMap();
- private static final Map COUNTRY_TO_ISO_CODES =
- Collections.unmodifiableMap(createCountryCodeByIsoMap());
+
+ private static Map COUNTRY_TO_ISO_CODES;
/**
* This method works as follow:
When the android version is LOLLIPOP or greater, the
@@ -151,10 +151,20 @@ public static PhoneNumber getPhoneNumber(
@Nullable
public static Integer getCountryCode(String countryIso) {
+ if (COUNTRY_TO_ISO_CODES == null) {
+ initCountryCodeByIsoMap();
+ }
return countryIso == null
? null : COUNTRY_TO_ISO_CODES.get(countryIso.toUpperCase(Locale.getDefault()));
}
+ public static Map getImmutableCountryIsoMap() {
+ if (COUNTRY_TO_ISO_CODES == null) {
+ initCountryCodeByIsoMap();
+ }
+ return COUNTRY_TO_ISO_CODES;
+ }
+
private static String getCountryIsoForCountryCode(String countryCode) {
List countries = COUNTRY_TO_REGION_CODES.get(Integer.parseInt(countryCode));
if (countries != null) {
@@ -163,6 +173,12 @@ private static String getCountryIsoForCountryCode(String countryCode) {
return DEFAULT_LOCALE.getCountry();
}
+ @Nullable
+ public static List getCountryIsosFromCountryCode(String countryCode) {
+ return !isValid(countryCode) ? null :
+ COUNTRY_TO_REGION_CODES.get(Integer.parseInt(countryCode.substring(1)));
+ }
+
/**
* Country code extracted using shortest matching prefix like libPhoneNumber. See:
* https://github.com/googlei18n/libphonenumber/blob/master/java/libphonenumber/src/com
@@ -181,7 +197,6 @@ private static String getCountryCodeForPhoneNumber(String normalizedPhoneNumber)
return potentialCountryCode;
}
}
-
return null;
}
@@ -433,7 +448,7 @@ private static SparseArray> createCountryCodeToRegionCodeMap() {
return map;
}
- private static Map createCountryCodeByIsoMap() {
+ private static void initCountryCodeByIsoMap() {
Map map = new HashMap<>(MAX_COUNTRIES);
for (int i = 0; i < COUNTRY_TO_REGION_CODES.size(); i++) {
@@ -457,6 +472,6 @@ private static Map createCountryCodeByIsoMap() {
map.put("GS", 500);
map.put("XK", 381);
- return map;
+ COUNTRY_TO_ISO_CODES = Collections.unmodifiableMap(map);
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/PrivacyDisclosureUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/data/PrivacyDisclosureUtils.java
index 4855c0690..7f0807644 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/data/PrivacyDisclosureUtils.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/data/PrivacyDisclosureUtils.java
@@ -49,10 +49,6 @@ private static int getGlobalTermsStringResource(FlowParameters flowParameters) {
if (termsOfServiceUrlProvided && privacyPolicyUrlProvided) {
return R.string.fui_tos_and_pp;
- } else if (termsOfServiceUrlProvided) {
- return R.string.fui_tos_only;
- } else if (privacyPolicyUrlProvided) {
- return R.string.fui_pp_only;
}
return NO_TOS_OR_PP;
@@ -65,10 +61,6 @@ private static int getGlobalTermsFooterStringResource(FlowParameters flowParamet
if (termsOfServiceUrlProvided && privacyPolicyUrlProvided) {
return R.string.fui_tos_and_pp_footer;
- } else if (termsOfServiceUrlProvided) {
- return R.string.fui_tos_footer;
- } else if (privacyPolicyUrlProvided) {
- return R.string.fui_pp_footer;
}
return NO_TOS_OR_PP;
@@ -81,10 +73,6 @@ private static int getTermsSmsStringResource(FlowParameters flowParameters) {
if (termsOfServiceUrlProvided && privacyPolicyUrlProvided) {
return R.string.fui_sms_terms_of_service_and_privacy_policy_extended;
- } else if (termsOfServiceUrlProvided) {
- return R.string.fui_sms_terms_of_service_only_extended;
- } else if (privacyPolicyUrlProvided) {
- return R.string.fui_sms_privacy_policy_only_extended;
}
return NO_TOS_OR_PP;
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java
index 6520d7c40..6f3254607 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java
@@ -21,6 +21,7 @@
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.util.Preconditions;
import com.google.android.gms.auth.api.credentials.IdentityProviders;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.Task;
@@ -29,6 +30,7 @@
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.SignInMethodQueryResult;
@@ -38,6 +40,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final class ProviderUtils {
+ private static final String GITHUB_IDENTITY = "https://github.com";
private static final String PHONE_IDENTITY = "https://phone.firebase";
private ProviderUtils() {
@@ -54,6 +57,8 @@ public static AuthCredential getAuthCredential(IdpResponse response) {
case TwitterAuthProvider.PROVIDER_ID:
return TwitterAuthProvider.getCredential(response.getIdpToken(),
response.getIdpSecret());
+ case GithubAuthProvider.PROVIDER_ID:
+ return GithubAuthProvider.getCredential(response.getIdpToken());
default:
return null;
}
@@ -78,6 +83,8 @@ public static String signInMethodToProviderId(@NonNull String method) {
return FacebookAuthProvider.PROVIDER_ID;
case TwitterAuthProvider.TWITTER_SIGN_IN_METHOD:
return TwitterAuthProvider.PROVIDER_ID;
+ case GithubAuthProvider.GITHUB_SIGN_IN_METHOD:
+ return GithubAuthProvider.PROVIDER_ID;
case PhoneAuthProvider.PHONE_SIGN_IN_METHOD:
return PhoneAuthProvider.PROVIDER_ID;
case EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD:
@@ -100,6 +107,8 @@ public static String providerIdToAccountType(@AuthUI.SupportedProvider @NonNull
return IdentityProviders.FACEBOOK;
case TwitterAuthProvider.PROVIDER_ID:
return IdentityProviders.TWITTER;
+ case GithubAuthProvider.PROVIDER_ID:
+ return GITHUB_IDENTITY;
case PhoneAuthProvider.PROVIDER_ID:
return PHONE_IDENTITY;
// The account type for email/password creds is null
@@ -118,6 +127,8 @@ public static String accountTypeToProviderId(@NonNull String accountType) {
return FacebookAuthProvider.PROVIDER_ID;
case IdentityProviders.TWITTER:
return TwitterAuthProvider.PROVIDER_ID;
+ case GITHUB_IDENTITY:
+ return GithubAuthProvider.PROVIDER_ID;
case PHONE_IDENTITY:
return PhoneAuthProvider.PROVIDER_ID;
default:
@@ -170,4 +181,14 @@ public String then(@NonNull Task task) {
}
});
}
+
+ public static String getTopProvider(@NonNull List providers) {
+ return providers == null || providers.isEmpty() ? null :
+ providers.get(providers.size() - 1);
+ }
+
+ public static boolean isExistingProvider(@NonNull List providers, String provider) {
+ if (providers == null) throw new IllegalArgumentException("The list of providers is null.");
+ return providers.contains(provider);
+ }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/ui/FlowUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/ui/FlowUtils.java
index 8a9177226..ac80c9426 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/ui/FlowUtils.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/ui/FlowUtils.java
@@ -63,7 +63,7 @@ private static void startIntentSenderForResult(FragmentBase fragment,
fragment.startIntentSenderForResult(
intent.getIntentSender(), requestCode, null, 0, 0, 0, null);
} catch (IntentSender.SendIntentException e) {
- HelperActivityBase activity = (HelperActivityBase) fragment.getActivity();
+ HelperActivityBase activity = (HelperActivityBase) fragment.requireActivity();
activity.finish(Activity.RESULT_CANCELED, IdpResponse.getErrorIntent(e));
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/util/ui/PreambleHandler.java b/auth/src/main/java/com/firebase/ui/auth/util/ui/PreambleHandler.java
index 635e9f576..7929ccf7e 100644
--- a/auth/src/main/java/com/firebase/ui/auth/util/ui/PreambleHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/util/ui/PreambleHandler.java
@@ -20,6 +20,8 @@
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
+import java.lang.ref.WeakReference;
+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class PreambleHandler {
private static final String BTN_TARGET = "%BTN%";
@@ -73,10 +75,7 @@ private void initPreamble(@StringRes int textViewText) {
mBuilder = new SpannableStringBuilder(withTargets);
replaceTarget(BTN_TARGET, mButtonText);
- replaceUrlTarget(
- TOS_TARGET,
- R.string.fui_terms_of_service,
- mFlowParameters.termsOfServiceUrl);
+ replaceUrlTarget(TOS_TARGET, R.string.fui_terms_of_service, mFlowParameters.termsOfServiceUrl);
replaceUrlTarget(PP_TARGET, R.string.fui_privacy_policy, mFlowParameters.privacyPolicyUrl);
}
@@ -96,7 +95,7 @@ private void replaceUrlTarget(String target, @StringRes int replacementRes, Stri
int end = targetIndex + replacement.length();
mBuilder.setSpan(mLinkSpan, targetIndex, end, 0);
- mBuilder.setSpan(new CustomTabsSpan(url), targetIndex, end, 0);
+ mBuilder.setSpan(new CustomTabsSpan(mContext, url), targetIndex, end, 0);
}
}
@@ -104,51 +103,29 @@ private void replaceUrlTarget(String target, @StringRes int replacementRes, Stri
private String getPreambleStringWithTargets(@StringRes int textViewText, boolean hasButton) {
boolean termsOfServiceUrlProvided = !TextUtils.isEmpty(mFlowParameters.termsOfServiceUrl);
boolean privacyPolicyUrlProvided = !TextUtils.isEmpty(mFlowParameters.privacyPolicyUrl);
+
if (termsOfServiceUrlProvided && privacyPolicyUrlProvided) {
Object[] targets = hasButton ?
new Object[]{BTN_TARGET, TOS_TARGET, PP_TARGET}
: new Object[]{TOS_TARGET, PP_TARGET};
return mContext.getString(textViewText, targets);
- } else if (termsOfServiceUrlProvided) {
- Object[] targets = hasButton ?
- new Object[]{BTN_TARGET, TOS_TARGET} : new Object[]{TOS_TARGET};
- return mContext.getString(textViewText, targets);
- } else if (privacyPolicyUrlProvided) {
- Object[] targets = hasButton ?
- new Object[]{BTN_TARGET, PP_TARGET} : new Object[]{PP_TARGET};
- return mContext.getString(textViewText, targets);
}
- return null;
- }
- @Nullable
- private String getPreambleStringWithTargetsNoButton(@StringRes int textViewText) {
- boolean hasTos = !TextUtils.isEmpty(mFlowParameters.termsOfServiceUrl);
- boolean hasPp = !TextUtils.isEmpty(mFlowParameters.privacyPolicyUrl);
- if (hasTos && hasPp) {
- return mContext.getString(textViewText,
- TOS_TARGET, PP_TARGET);
- } else if (hasTos) {
- return mContext.getString(textViewText,
- TOS_TARGET);
- } else if (hasPp) {
- return mContext.getString(textViewText,
- PP_TARGET);
- }
return null;
}
-
- private class CustomTabsSpan extends ClickableSpan {
+ private static final class CustomTabsSpan extends ClickableSpan {
+ private final WeakReference mContext;
private final String mUrl;
private final CustomTabsIntent mCustomTabsIntent;
- public CustomTabsSpan(String url) {
+ public CustomTabsSpan(Context context, String url) {
+ mContext = new WeakReference<>(context);
mUrl = url;
// Getting default color
TypedValue typedValue = new TypedValue();
- mContext.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
+ context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
@ColorInt int color = typedValue.data;
mCustomTabsIntent = new CustomTabsIntent.Builder()
@@ -159,7 +136,10 @@ public CustomTabsSpan(String url) {
@Override
public void onClick(View widget) {
- mCustomTabsIntent.launchUrl(mContext, Uri.parse(mUrl));
+ Context context = mContext.get();
+ if (context != null) {
+ mCustomTabsIntent.launchUrl(context, Uri.parse(mUrl));
+ }
}
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/ProviderSignInBase.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/ProviderSignInBase.java
similarity index 91%
rename from auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/ProviderSignInBase.java
rename to auth/src/main/java/com/firebase/ui/auth/viewmodel/ProviderSignInBase.java
index 88829b02b..664ebad10 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/ProviderSignInBase.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/ProviderSignInBase.java
@@ -1,4 +1,4 @@
-package com.firebase.ui.auth.viewmodel.idp;
+package com.firebase.ui.auth.viewmodel;
import android.app.Application;
import android.content.Intent;
@@ -9,7 +9,6 @@
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.Resource;
import com.firebase.ui.auth.ui.HelperActivityBase;
-import com.firebase.ui.auth.viewmodel.OperableViewModel;
/**
* Handles retrieving a provider's login credentials, be that a token, secret, or both.
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/RequestCodes.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/RequestCodes.java
index 4e7af44d8..9864e54a7 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/RequestCodes.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/RequestCodes.java
@@ -37,6 +37,9 @@ public final class RequestCodes {
/** Request code for retrieving a Google credential. */
public static final int GOOGLE_PROVIDER = 110;
+ /** Request code for retrieving a GitHub credential. */
+ public static final int GITHUB_PROVIDER = 111;
+
private RequestCodes() {
throw new AssertionError("No instance for you!");
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/ResourceObserver.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/ResourceObserver.java
index b5d822ba8..75d87b197 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/ResourceObserver.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/ResourceObserver.java
@@ -6,8 +6,8 @@
import android.support.annotation.StringRes;
import android.util.Log;
-import com.firebase.ui.auth.R;
import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.Resource;
import com.firebase.ui.auth.data.model.State;
import com.firebase.ui.auth.ui.FragmentBase;
@@ -31,6 +31,10 @@ protected ResourceObserver(@NonNull HelperActivityBase activity, @StringRes int
this(activity, null, activity, message);
}
+ protected ResourceObserver(@NonNull FragmentBase fragment) {
+ this(null, fragment, fragment, R.string.fui_progress_dialog_loading);
+ }
+
protected ResourceObserver(@NonNull FragmentBase fragment, @StringRes int message) {
this(null, fragment, fragment, message);
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java
new file mode 100644
index 000000000..b47a6f6ec
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/SignInViewModelBase.java
@@ -0,0 +1,40 @@
+package com.firebase.ui.auth.viewmodel;
+
+import android.app.Application;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.data.model.Resource;
+import com.google.firebase.auth.AuthCredential;
+import com.google.firebase.auth.AuthResult;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public abstract class SignInViewModelBase extends AuthViewModelBase {
+ protected SignInViewModelBase(Application application) {
+ super(application);
+ }
+
+ @Override
+ protected void setResult(Resource output) {
+ super.setResult(output);
+ }
+
+ protected void handleSuccess(@NonNull IdpResponse response, @NonNull AuthResult result) {
+ setResult(Resource.forSuccess(response.withResult(result)));
+ }
+
+ protected void handleMergeFailure(@NonNull AuthCredential credential) {
+ IdpResponse failureResponse = new IdpResponse.Builder(credential).build();
+ handleMergeFailure(failureResponse);
+ }
+
+ protected void handleMergeFailure(@NonNull IdpResponse failureResponse) {
+ setResult(Resource.forFailure(new FirebaseAuthAnonymousUpgradeException(
+ ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT,
+ failureResponse)));
+ }
+
+}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/EmailProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java
similarity index 67%
rename from auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/EmailProviderResponseHandler.java
rename to auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java
index 0e4f92bb3..6287cb13f 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/EmailProviderResponseHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/EmailProviderResponseHandler.java
@@ -1,4 +1,4 @@
-package com.firebase.ui.auth.viewmodel.idp;
+package com.firebase.ui.auth.viewmodel.email;
import android.app.Application;
import android.support.annotation.NonNull;
@@ -11,25 +11,27 @@
import com.firebase.ui.auth.data.remote.ProfileMerger;
import com.firebase.ui.auth.ui.email.WelcomeBackPasswordPrompt;
import com.firebase.ui.auth.ui.idp.WelcomeBackIdpPrompt;
+import com.firebase.ui.auth.util.data.AuthOperationManager;
import com.firebase.ui.auth.util.data.ProviderUtils;
import com.firebase.ui.auth.util.data.TaskFailureLogger;
-import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
import com.firebase.ui.auth.viewmodel.RequestCodes;
+import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class EmailProviderResponseHandler extends AuthViewModelBase {
+public class EmailProviderResponseHandler extends SignInViewModelBase {
private static final String TAG = "EmailProviderResponseHa";
public EmailProviderResponseHandler(Application application) {
super(application);
}
- public void startSignIn(@NonNull final IdpResponse response, @NonNull String password) {
+ public void startSignIn(@NonNull final IdpResponse response, @NonNull final String password) {
if (!response.isSuccessful()) {
setResult(Resource.forFailure(response.getError()));
return;
@@ -40,30 +42,42 @@ public void startSignIn(@NonNull final IdpResponse response, @NonNull String pas
}
setResult(Resource.forLoading());
+ final AuthOperationManager authOperationManager = AuthOperationManager.getInstance();
final String email = response.getEmail();
- getAuth().createUserWithEmailAndPassword(email, password)
+ authOperationManager.createOrLinkUserWithEmailAndPassword(getAuth(),
+ getArguments(),
+ email,
+ password)
.continueWithTask(new ProfileMerger(response))
.addOnFailureListener(new TaskFailureLogger(TAG, "Error creating user"))
.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(AuthResult result) {
- setResult(Resource.forSuccess(response));
+ handleSuccess(response, result);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof FirebaseAuthUserCollisionException) {
- // Collision with existing user email, it should be very hard for
- // the user to even get to this error due to CheckEmailFragment.
- ProviderUtils.fetchTopProvider(getAuth(), email)
- .addOnSuccessListener(new StartWelcomeBackFlow(email))
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- setResult(Resource.forFailure(e));
- }
- });
+ if (authOperationManager.canUpgradeAnonymous(getAuth(),
+ getArguments())) {
+ AuthCredential credential = EmailAuthProvider.getCredential(email,
+ password);
+ handleMergeFailure(credential);
+ } else {
+ // Collision with existing user email without anonymous upgrade
+ // it should be very hard for the user to even get to this error
+ // due to CheckEmailFragment.
+ ProviderUtils.fetchTopProvider(getAuth(), email)
+ .addOnSuccessListener(new StartWelcomeBackFlow(email))
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
+ }
} else {
setResult(Resource.forFailure(e));
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java
index 198498e4a..dbd860094 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java
@@ -5,14 +5,18 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
+import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.Resource;
import com.firebase.ui.auth.data.model.User;
import com.firebase.ui.auth.data.remote.ProfileMerger;
+import com.firebase.ui.auth.util.data.AuthOperationManager;
import com.firebase.ui.auth.util.data.TaskFailureLogger;
-import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
+import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.auth.AuthCredential;
@@ -25,7 +29,7 @@
* SmartLock.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class WelcomeBackPasswordHandler extends AuthViewModelBase {
+public class WelcomeBackPasswordHandler extends SignInViewModelBase {
private static final String TAG = "WBPasswordHandler";
private String mPendingPassword;
@@ -61,38 +65,80 @@ public void startSignIn(@NonNull final String email,
.build();
}
- // Kick off the flow including signing in, linking accounts, and saving with SmartLock
- getAuth().signInWithEmailAndPassword(email, password)
- .continueWithTask(new Continuation>() {
- @Override
- public Task then(@NonNull Task task) throws Exception {
- // Forward task failure by asking for result
- AuthResult result = task.getResult(Exception.class);
+ final AuthOperationManager authOperationManager = AuthOperationManager.getInstance();
+ if (authOperationManager.canUpgradeAnonymous(getAuth(), getArguments())) {
+ final AuthCredential credToValidate = EmailAuthProvider.getCredential(email, password);
- // Task succeeded, link user if necessary
- if (credential == null) {
- return Tasks.forResult(result);
- } else {
- return result.getUser()
- .linkWithCredential(credential)
- .continueWithTask(new ProfileMerger(outputResponse))
- .addOnFailureListener(new TaskFailureLogger(TAG, "linkWithCredential+merge failed."));
+ // Check to see if we need to link (for social providers with the same email)
+ if (AuthUI.SOCIAL_PROVIDERS.contains(inputResponse.getProviderType())) {
+ // Add the provider to the same account before triggering a merge failure.
+ authOperationManager.safeLink(credToValidate, credential, getArguments())
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ handleMergeFailure(credToValidate);
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
+ } else {
+ // The user has not tried to log in with a federated IDP containing the same email.
+ // In this case, we just need to verify that the credential they provided is valid.
+ // No linking is done for non-federated IDPs.
+ // A merge failure occurs because the account exists and the user is anonymous.
+ authOperationManager.validateCredential(credToValidate, getArguments())
+ .addOnCompleteListener(
+ new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ handleMergeFailure(credToValidate);
+ } else {
+ setResult(Resource.forFailure(task.getException()));
+ }
+ }
+ });
+ }
+ } else {
+ // Kick off the flow including signing in, linking accounts, and saving with SmartLock
+ getAuth().signInWithEmailAndPassword(email, password)
+ .continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ // Forward task failure by asking for result
+ AuthResult result = task.getResult(Exception.class);
+
+ // Task succeeded, link user if necessary
+ if (credential == null) {
+ return Tasks.forResult(result);
+ } else {
+ return result.getUser()
+ .linkWithCredential(credential)
+ .continueWithTask(new ProfileMerger(outputResponse))
+ .addOnFailureListener(new TaskFailureLogger(TAG,
+ "linkWithCredential+merge failed."));
+ }
}
- }
- })
- .addOnCompleteListener(new OnCompleteListener() {
- @Override
- public void onComplete(@NonNull Task task) {
- if (!task.isSuccessful()) {
- setResult(Resource.forFailure(task.getException()));
- return;
+ })
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ handleSuccess(outputResponse, result);
}
-
- setResult(Resource.forSuccess(outputResponse));
- }
- })
- .addOnFailureListener(
- new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed."));
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ })
+ .addOnFailureListener(
+ new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed."));
+ }
}
/**
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java
index 4b65d6b96..76e3ff152 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/LinkingSocialProviderResponseHandler.java
@@ -6,28 +6,34 @@
import android.support.annotation.RestrictTo;
import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.ErrorCodes;
+import com.firebase.ui.auth.FirebaseUiException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.util.data.AuthOperationManager;
import com.firebase.ui.auth.util.data.ProviderUtils;
-import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
+import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
-import com.google.firebase.auth.FirebaseUser;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class LinkingSocialProviderResponseHandler extends AuthViewModelBase {
+public class LinkingSocialProviderResponseHandler extends SignInViewModelBase {
private AuthCredential mRequestedSignInCredential;
-
+ private String mEmail;
public LinkingSocialProviderResponseHandler(Application application) {
super(application);
}
- public void setRequestedSignInCredential(@Nullable AuthCredential credential) {
+ public void setRequestedSignInCredentialForEmail(@Nullable AuthCredential credential,
+ @Nullable String email) {
mRequestedSignInCredential = credential;
+ mEmail = email;
}
public void startSignIn(@NonNull final IdpResponse response) {
@@ -39,52 +45,81 @@ public void startSignIn(@NonNull final IdpResponse response) {
throw new IllegalStateException(
"This handler cannot be used to link email or phone providers");
}
+ if (mEmail != null && !mEmail.equals(response.getEmail())) {
+ setResult(Resource.forFailure(new FirebaseUiException
+ (ErrorCodes.EMAIL_MISMATCH_ERROR)));
+ return;
+ }
+
setResult(Resource.forLoading());
- AuthCredential credential = ProviderUtils.getAuthCredential(response);
- FirebaseUser currentUser = getCurrentUser();
- if (currentUser == null) {
+ final AuthOperationManager authOperationManager = AuthOperationManager.getInstance();
+ final AuthCredential credential = ProviderUtils.getAuthCredential(response);
+
+ if (authOperationManager.canUpgradeAnonymous(getAuth(), getArguments())) {
+ if (mRequestedSignInCredential == null) {
+ // The user has provided a valid credential by signing in with a federated
+ // idp. linkWithCredential will fail because the user is anonymous and the account
+ // exists (we're in the welcome back flow).
+ // We know that they are signing in with the same IDP because requestSignInCredential
+ // is null.
+ // We just need to have the developer handle the merge failure.
+ handleMergeFailure(credential);
+ } else {
+ // The user has logged in with an IDP that has the same email with another IDP
+ // present on the account.
+ // These IDPs belong to the same account - they must be linked, but we can't lose
+ // our anonymous user session
+ authOperationManager.safeLink(credential, mRequestedSignInCredential, getArguments())
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ handleMergeFailure(credential);
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(e));
+ }
+ });
+ }
+ } else {
getAuth().signInWithCredential(credential)
- .continueWithTask(new Continuation>() {
+ .continueWithTask(new Continuation>() {
@Override
- public Task then(@NonNull Task task) {
- AuthResult result = task.getResult();
+ public Task then(@NonNull Task task) {
+ final AuthResult result = task.getResult();
if (mRequestedSignInCredential == null) {
- return Tasks.forResult(null);
+ return Tasks.forResult(result);
} else {
return result.getUser()
.linkWithCredential(mRequestedSignInCredential)
- .continueWith(new Continuation() {
+ .continueWith(new Continuation() {
@Override
- public Void then(@NonNull Task task) {
- // Since we've already signed in, it's too late to
- // backtrack so we just ignore any errors.
- return null;
+ public AuthResult then(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ return task.getResult();
+ } else {
+ // Since we've already signed in, it's too late
+ // to backtrack so we just ignore any errors.
+ return result;
+ }
}
});
}
}
})
- .addOnCompleteListener(new OnCompleteListener() {
+ .addOnCompleteListener(new OnCompleteListener() {
@Override
- public void onComplete(@NonNull Task task) {
+ public void onComplete(@NonNull Task task) {
if (task.isSuccessful()) {
- setResult(Resource.forSuccess(response));
+ handleSuccess(response, task.getResult());
} else {
setResult(Resource.forFailure(task.getException()));
}
}
});
- } else {
- currentUser.linkWithCredential(credential)
- .addOnCompleteListener(new OnCompleteListener() {
- @Override
- public void onComplete(@NonNull Task task) {
- // I'm not sure why we ignore failures here, but this mirrors previous
- // behavior.
- setResult(Resource.forSuccess(response));
- }
- });
}
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java
index 09524c437..1ad639957 100644
--- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/idp/SocialProviderResponseHandler.java
@@ -17,17 +17,22 @@
import com.firebase.ui.auth.data.remote.ProfileMerger;
import com.firebase.ui.auth.ui.email.WelcomeBackPasswordPrompt;
import com.firebase.ui.auth.ui.idp.WelcomeBackIdpPrompt;
+import com.firebase.ui.auth.util.data.AuthOperationManager;
import com.firebase.ui.auth.util.data.ProviderUtils;
-import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
import com.firebase.ui.auth.viewmodel.RequestCodes;
+import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
+import com.google.firebase.auth.SignInMethodQueryResult;
+
+import java.util.List;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class SocialProviderResponseHandler extends AuthViewModelBase {
+public class SocialProviderResponseHandler extends SignInViewModelBase {
public SocialProviderResponseHandler(Application application) {
super(application);
}
@@ -41,39 +46,97 @@ public void startSignIn(@NonNull final IdpResponse response) {
throw new IllegalStateException(
"This handler cannot be used with email or phone providers");
}
+
setResult(Resource.forLoading());
- getAuth().signInWithCredential(ProviderUtils.getAuthCredential(response))
+ final AuthCredential credential = ProviderUtils.getAuthCredential(response);
+
+ AuthOperationManager.getInstance().signInAndLinkWithCredential(
+ getAuth(),
+ getArguments(),
+ credential)
.continueWithTask(new ProfileMerger(response))
.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(AuthResult result) {
- setResult(Resource.forSuccess(response));
+ handleSuccess(response, result);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
- public void onFailure(@NonNull Exception e) {
- String email = response.getEmail();
- if (email != null) {
- if (e instanceof FirebaseAuthUserCollisionException) {
- ProviderUtils.fetchTopProvider(getAuth(), email)
- .addOnSuccessListener(
- new StartWelcomeBackFlow(response))
- .addOnFailureListener(new OnFailureListener() {
- @Override
- public void onFailure(@NonNull Exception e) {
- setResult(Resource.forFailure(e));
- }
- });
+ public void onFailure(@NonNull final Exception e) {
+ if (e instanceof FirebaseAuthUserCollisionException) {
+ final String email = response.getEmail();
+ if (email == null) {
+ setResult(Resource.forFailure(e));
return;
}
+ // There can be a collision due to:
+ // CASE 1: Anon user signing in with a credential that belongs to an
+ // existing user.
+ // CASE 2: non - anon user signing in with a credential that does not
+ // belong to an existing user, but the email matches an existing user
+ // that has another social IDP. We need to link this new IDP to this
+ // existing user.
+ // CASE 3: CASE 2 with an anonymous user. We link the new IDP to the
+ // same account before handling invoking a merge failure.
+ getAuth().fetchSignInMethodsForEmail(email)
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(SignInMethodQueryResult result) {
+ List providers = result.getSignInMethods();
+ if (ProviderUtils.isExistingProvider(providers,
+ response.getProviderType())) {
+ // Case 1
+ handleMergeFailure(credential);
+ } else {
+ // Case 2 & 3 - we need to link
+ startWelcomeBackFlowForLinking(
+ ProviderUtils.getTopProvider(providers),
+ response);
+ }
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ setResult(Resource.forFailure(
+ e));
+ }
+ });
}
- setResult(Resource.forFailure(e));
}
});
}
+ public void startWelcomeBackFlowForLinking(String provider, IdpResponse response) {
+ if (provider == null) {
+ throw new IllegalStateException(
+ "No provider even though we received a FirebaseAuthUserCollisionException");
+ }
+
+ if (provider.equals(EmailAuthProvider.PROVIDER_ID)) {
+ // Start email welcome back flow
+ setResult(Resource.forFailure(new IntentRequiredException(
+ WelcomeBackPasswordPrompt.createIntent(
+ getApplication(),
+ getArguments(),
+ response),
+ RequestCodes.ACCOUNT_LINK_FLOW
+ )));
+ } else {
+ // Start Idp welcome back flow
+ setResult(Resource.forFailure(new IntentRequiredException(
+ WelcomeBackIdpPrompt.createIntent(
+ getApplication(),
+ getArguments(),
+ new User.Builder(provider, response.getEmail()).build(),
+ response),
+ RequestCodes.ACCOUNT_LINK_FLOW
+ )));
+ }
+ }
+
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == RequestCodes.ACCOUNT_LINK_FLOW) {
IdpResponse response = IdpResponse.fromResultIntent(data);
@@ -92,40 +155,4 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
}
}
- private class StartWelcomeBackFlow implements OnSuccessListener {
- private final IdpResponse mResponse;
-
- public StartWelcomeBackFlow(IdpResponse response) {
- mResponse = response;
- }
-
- @Override
- public void onSuccess(String provider) {
- if (provider == null) {
- throw new IllegalStateException(
- "No provider even though we received a FirebaseAuthUserCollisionException");
- }
-
- if (provider.equals(EmailAuthProvider.PROVIDER_ID)) {
- // Start email welcome back flow
- setResult(Resource.forFailure(new IntentRequiredException(
- WelcomeBackPasswordPrompt.createIntent(
- getApplication(),
- getArguments(),
- mResponse),
- RequestCodes.ACCOUNT_LINK_FLOW
- )));
- } else {
- // Start Idp welcome back flow
- setResult(Resource.forFailure(new IntentRequiredException(
- WelcomeBackIdpPrompt.createIntent(
- getApplication(),
- getArguments(),
- new User.Builder(provider, mResponse.getEmail()).build(),
- mResponse),
- RequestCodes.ACCOUNT_LINK_FLOW
- )));
- }
- }
- }
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java b/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java
new file mode 100644
index 000000000..4c8d5387f
--- /dev/null
+++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/phone/PhoneProviderResponseHandler.java
@@ -0,0 +1,59 @@
+package com.firebase.ui.auth.viewmodel.phone;
+
+import android.app.Application;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.util.data.AuthOperationManager;
+import com.firebase.ui.auth.viewmodel.SignInViewModelBase;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuthUserCollisionException;
+import com.google.firebase.auth.PhoneAuthCredential;
+import com.google.firebase.auth.PhoneAuthProvider;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class PhoneProviderResponseHandler extends SignInViewModelBase {
+ public PhoneProviderResponseHandler(Application application) {
+ super(application);
+ }
+
+ public void startSignIn(@NonNull PhoneAuthCredential credential,
+ @NonNull final IdpResponse response) {
+ if (!response.isSuccessful()) {
+ setResult(Resource.forFailure(response.getError()));
+ return;
+ }
+ if (!response.getProviderType().equals(PhoneAuthProvider.PROVIDER_ID)) {
+ throw new IllegalStateException(
+ "This handler cannot be used without a phone response.");
+ }
+
+ setResult(Resource.forLoading());
+
+ AuthOperationManager.getInstance()
+ .signInAndLinkWithCredential(getAuth(), getArguments(), credential)
+ .addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(AuthResult result) {
+ handleSuccess(response, result);
+ }
+ })
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ if (e instanceof FirebaseAuthUserCollisionException) {
+ // With phone auth, this only happens if we are trying to upgrade
+ // an anonymous account using a phone number that is already registered
+ // on another account
+ handleMergeFailure(((FirebaseAuthUserCollisionException) e).getUpdatedCredential());
+ } else {
+ setResult(Resource.forFailure(e));
+ }
+ }
+ });
+ }
+}
diff --git a/auth/src/main/res/drawable-v21/fui_idp_button_background_github.xml b/auth/src/main/res/drawable-v21/fui_idp_button_background_github.xml
new file mode 100644
index 000000000..14b568c33
--- /dev/null
+++ b/auth/src/main/res/drawable-v21/fui_idp_button_background_github.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/auth/src/main/res/drawable/fui_done_check_mark.xml b/auth/src/main/res/drawable/fui_done_check_mark.xml
deleted file mode 100644
index 3a9ad8a11..000000000
--- a/auth/src/main/res/drawable/fui_done_check_mark.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/auth/src/main/res/drawable/fui_ic_github_white_24dp.xml b/auth/src/main/res/drawable/fui_ic_github_white_24dp.xml
new file mode 100644
index 000000000..ad2cc2cd9
--- /dev/null
+++ b/auth/src/main/res/drawable/fui_ic_github_white_24dp.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/auth/src/main/res/drawable/fui_idp_button_background_github.xml b/auth/src/main/res/drawable/fui_idp_button_background_github.xml
new file mode 100644
index 000000000..32e8906ec
--- /dev/null
+++ b/auth/src/main/res/drawable/fui_idp_button_background_github.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/auth/src/main/res/layout-land/fui_auth_method_picker_layout.xml b/auth/src/main/res/layout-land/fui_auth_method_picker_layout.xml
index db8e0fb24..646d3cbda 100644
--- a/auth/src/main/res/layout-land/fui_auth_method_picker_layout.xml
+++ b/auth/src/main/res/layout-land/fui_auth_method_picker_layout.xml
@@ -21,9 +21,26 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/container"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/main_tos_and_pp"
tools:ignore="ContentDescription" />
+
+
-
-
diff --git a/auth/src/main/res/layout/fui_activity_register_email.xml b/auth/src/main/res/layout/fui_activity_register_email.xml
index 4132aabc7..0eedf347a 100644
--- a/auth/src/main/res/layout/fui_activity_register_email.xml
+++ b/auth/src/main/res/layout/fui_activity_register_email.xml
@@ -5,6 +5,4 @@
android:id="@+id/fragment_register_email"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:ignore="MergeRootFrame">
-
-
+ tools:ignore="MergeRootFrame" />
diff --git a/auth/src/main/res/layout/fui_activity_register_phone.xml b/auth/src/main/res/layout/fui_activity_register_phone.xml
index 2704b5124..cebe78645 100644
--- a/auth/src/main/res/layout/fui_activity_register_phone.xml
+++ b/auth/src/main/res/layout/fui_activity_register_phone.xml
@@ -2,9 +2,7 @@
-
-
+ tools:ignore="MergeRootFrame" />
diff --git a/auth/src/main/res/layout/fui_auth_method_picker_layout.xml b/auth/src/main/res/layout/fui_auth_method_picker_layout.xml
index 0aa9cc036..e5d558340 100644
--- a/auth/src/main/res/layout/fui_auth_method_picker_layout.xml
+++ b/auth/src/main/res/layout/fui_auth_method_picker_layout.xml
@@ -6,7 +6,6 @@
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:clipChildren="false"
android:clipToPadding="false">
+ app:layout_constraintVertical_weight="2">
+ style="@style/FirebaseUI.AuthMethodPicker.ButtonHolder"
+ android:gravity="bottom" />
@@ -48,10 +50,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/fui_field_padding_vert"
- android:layout_marginBottom="16dp"
+ android:layout_marginBottom="@dimen/fui_field_padding_vert"
android:gravity="center"
android:textColor="?android:textColorTertiary"
android:textIsSelectable="true"
+ app:layout_constraintTop_toBottomOf="@+id/container"
app:layout_constraintBottom_toBottomOf="parent" />
diff --git a/auth/src/main/res/layout/fui_check_email_layout.xml b/auth/src/main/res/layout/fui_check_email_layout.xml
index f80f6933d..1e588c3f0 100644
--- a/auth/src/main/res/layout/fui_check_email_layout.xml
+++ b/auth/src/main/res/layout/fui_check_email_layout.xml
@@ -14,8 +14,7 @@
+ android:layout_height="match_parent">
+
+
@@ -102,8 +107,10 @@
+ app:layout_constraintBottom_toBottomOf="parent" />
diff --git a/auth/src/main/res/layout/fui_forgot_password_layout.xml b/auth/src/main/res/layout/fui_forgot_password_layout.xml
index fe6a8a4b8..85550ee0a 100644
--- a/auth/src/main/res/layout/fui_forgot_password_layout.xml
+++ b/auth/src/main/res/layout/fui_forgot_password_layout.xml
@@ -1,42 +1,56 @@
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
+
-
+
-
+ android:orientation="vertical">
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
diff --git a/auth/src/main/res/layout/fui_idp_button_facebook.xml b/auth/src/main/res/layout/fui_idp_button_facebook.xml
index b8ac067c5..47eb88122 100644
--- a/auth/src/main/res/layout/fui_idp_button_facebook.xml
+++ b/auth/src/main/res/layout/fui_idp_button_facebook.xml
@@ -1,7 +1,4 @@
+ android:text="@string/fui_sign_in_with_facebook" />
diff --git a/auth/src/main/res/layout/fui_idp_button_github.xml b/auth/src/main/res/layout/fui_idp_button_github.xml
new file mode 100644
index 000000000..06e970841
--- /dev/null
+++ b/auth/src/main/res/layout/fui_idp_button_github.xml
@@ -0,0 +1,4 @@
+
diff --git a/auth/src/main/res/layout/fui_idp_button_google.xml b/auth/src/main/res/layout/fui_idp_button_google.xml
index 23d55dd79..ff5e282c6 100644
--- a/auth/src/main/res/layout/fui_idp_button_google.xml
+++ b/auth/src/main/res/layout/fui_idp_button_google.xml
@@ -1,7 +1,4 @@
+ android:text="@string/fui_sign_in_with_google" />
diff --git a/auth/src/main/res/layout/fui_idp_button_twitter.xml b/auth/src/main/res/layout/fui_idp_button_twitter.xml
index 0813410d3..f186afebc 100644
--- a/auth/src/main/res/layout/fui_idp_button_twitter.xml
+++ b/auth/src/main/res/layout/fui_idp_button_twitter.xml
@@ -1,7 +1,4 @@
+ android:text="@string/fui_sign_in_with_twitter" />
diff --git a/auth/src/main/res/layout/fui_phone_layout.xml b/auth/src/main/res/layout/fui_phone_layout.xml
index 7685f223f..28cc7f7d2 100644
--- a/auth/src/main/res/layout/fui_phone_layout.xml
+++ b/auth/src/main/res/layout/fui_phone_layout.xml
@@ -1,11 +1,16 @@
-
+
+
@@ -56,11 +61,11 @@
+ app:layout_constraintTop_toBottomOf="@+id/send_sms_tos"
+ app:layout_constraintBottom_toBottomOf="parent" />
-
diff --git a/auth/src/main/res/layout/fui_phone_progress_dialog.xml b/auth/src/main/res/layout/fui_phone_progress_dialog.xml
deleted file mode 100644
index cb13c7e37..000000000
--- a/auth/src/main/res/layout/fui_phone_progress_dialog.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/auth/src/main/res/layout/fui_register_email_layout.xml b/auth/src/main/res/layout/fui_register_email_layout.xml
index fa3e6e380..66d9b2739 100644
--- a/auth/src/main/res/layout/fui_register_email_layout.xml
+++ b/auth/src/main/res/layout/fui_register_email_layout.xml
@@ -15,10 +15,7 @@
+ android:clipToPadding="false">
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
+
-
+
-
+
-
+
diff --git a/auth/src/main/res/layout/fui_welcome_back_password_prompt_layout.xml b/auth/src/main/res/layout/fui_welcome_back_password_prompt_layout.xml
index fd42bb9bc..6af10307f 100644
--- a/auth/src/main/res/layout/fui_welcome_back_password_prompt_layout.xml
+++ b/auth/src/main/res/layout/fui_welcome_back_password_prompt_layout.xml
@@ -1,20 +1,20 @@
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
+
-
+
+ app:layout_constraintTop_toBottomOf="@+id/button_done"
+ app:layout_constraintBottom_toBottomOf="parent" />
-
+
-
+
diff --git a/auth/src/main/res/values-ar/strings.xml b/auth/src/main/res/values-ar/strings.xml
index f6cf4c1bf..30334a2a6 100755
--- a/auth/src/main/res/values-ar/strings.xml
+++ b/auth/src/main/res/values-ar/strings.xml
@@ -2,17 +2,15 @@
جارٍ التحميل…تسجيل الدخولتشير المتابعة إلى موافقتك على %1$s و%2$s.
- تشير المتابعة إلى موافقتك على %1$s.
- تشير المتابعة إلى موافقتك على %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubتسجيل الدخول عبر Googleتسجيل الدخول عبر Facebookتسجيل الدخول عبر Twitter
+ تسجيل الدخول باستخدام GitHubتسجيل الدخول عبر البريد الإلكترونيتسجيل الدخول عبر رقم الهاتفالتالي
@@ -53,22 +51,15 @@
إعادة إرسال الرمز بعد 0:%02dإثبات ملكية رقم هاتفكجارٍ التحقق…
- جارٍ استرداد الرسائل القصيرة SMS…الرمز غير صحيح. يُرجى المحاولة مجددًا.
- موافقتم استخدام رقم الهاتف هذا لعدد كبير جدًا من المراتحدثت مشكلة أثناء إثبات ملكية رقم هاتفكلم يعد هذا الرمز صالحًاتسجيل الدخول عبر رقم الهاتف
- تم
- اكتملت عملية إثبات الملكية!
- تم إرسال الرمز!
- جارٍ إعادة الإرسال…
+ تمّ التحقّق تلقائيًا من رقم الهاتف.إعادة إرسال الرمزتأكيد ملكية رقم الهاتفمتابعةعند النقر على “%1$s”، قد يتمّ إرسال رسالة قصيرة SMS وقد يتمّ تطبيق رسوم الرسائل والبيانات.يشير النقر على “%1$s” إلى موافقتك على %2$s و%3$s. وقد يتمّ إرسال رسالة قصيرة كما قد تنطبق رسوم الرسائل والبيانات.
- يشير النقر على “%1$s” إلى موافقتك على %2$s. وقد يتمّ إرسال رسالة قصيرة كما قد تنطبق رسوم الرسائل والبيانات.
- يشير النقر على “%1$s” إلى موافقتك على %2$s. وقد يتمّ إرسال رسالة قصيرة كما قد تنطبق رسوم الرسائل والبيانات.
diff --git a/auth/src/main/res/values-b+es+419/strings.xml b/auth/src/main/res/values-b+es+419/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-b+es+419/strings.xml
+++ b/auth/src/main/res/values-b+es+419/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-bg/strings.xml b/auth/src/main/res/values-bg/strings.xml
index 6c8a788c2..a3a67a10a 100755
--- a/auth/src/main/res/values-bg/strings.xml
+++ b/auth/src/main/res/values-bg/strings.xml
@@ -2,17 +2,15 @@
Зарежда се…ВходПродължавайки, приемате нашите %1$s и %2$s.
- Продължавайки, приемате нашите %1$s.
- Продължавайки, приемате нашата %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubВход с GoogleВход с FacebookВход с Twitter
+ Вход с GitHubВход с имейлВход с телефонНапред
@@ -53,22 +51,15 @@
Повторно изпращане на кода след 0:%02dПотвърждаване на телефонния ви номерПотвърждава се…
- SMS съобщението се извлича…Неправилен код. Опитайте отново.
- ОКТози телефонен номер е използван твърде много пътиПри потвърждаването на телефонния ви номер възникна проблемТози код вече не е валиденВход с телефонен номер
- Готово
- Потвърдено!
- Кодът е изпратен!
- Изпраща се повторно…
+ Телефонният номер е потвърден автоматичноПовторно изпращане на кодаПотвърждаване на телефонния номерНапредДокосвайки „%1$s“, може да получите SMS съобщение. То може да се таксува по тарифите за данни и SMS.Докосвайки „%1$s“, приемате нашите %2$s и %3$s. Възможно е да получите SMS съобщение. То може да се таксува по тарифите за данни и SMS.
- Докосвайки „%1$s“, приемате нашите %2$s. Възможно е да получите SMS съобщение. То може да се таксува по тарифите за данни и SMS.
- Докосвайки „%1$s“, приемате нашата %2$s. Възможно е да получите SMS съобщение. То може да се таксува по тарифите за данни и SMS.
diff --git a/auth/src/main/res/values-bn/strings.xml b/auth/src/main/res/values-bn/strings.xml
index f0edf5be9..340eb0429 100755
--- a/auth/src/main/res/values-bn/strings.xml
+++ b/auth/src/main/res/values-bn/strings.xml
@@ -2,17 +2,15 @@
লোড হচ্ছে…সাইন-ইন করুনচালিয়ে যাওয়ার অর্থ, আপনি আমাদের %1$s এবং %2$s-এর সাথে সম্মত।
- চালিয়ে যাওয়ার অর্থ, আপনি আমাদের %1$s-এর সাথে সম্মত।
- চালিয়ে যাওয়ার অর্থ, আপনি আমাদের %1$s-এর সাথে সম্মত।%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GithubGoogle দিয়ে সাইন-ইন করুনFacebook দিয়ে সাইন-ইন করুনTwitter দিয়ে সাইন-ইন করুন
+ GitHub ব্যবহার করে সাইন-ইন করুনইমেল দিয়ে সাইন-ইন করুনফোন দিয়ে সাইন-ইন করুনপরবর্তী
@@ -53,22 +51,15 @@
0:%02d এ কোডটি আবার পাঠানআপনার ফোন নম্বর যাচাই করুনযাচাই করা হচ্ছে…
- এসএমএসটি পুনরুদ্ধার করা হচ্ছে…কোডটি ভুল। আবার চেষ্টা করুন।
- ঠিক আছেএই ফোন নম্বরটি অনেকবার ব্যবহার করা হয়েছেআপনার ফোন নম্বরটি যাচাই করতে সমস্যা হয়েছেএই কোডটি আর ব্যবহার করা যাবে নাফোন নম্বর দিয়ে সাইন-ইন করুন
- সম্পন্ন হয়েছে
- যাচাই করা হয়েছে!
- কোডটি পাঠানো হয়েছে!
- আবার পাঠানো হচ্ছে…
+ ফোন নম্বরটি নিজে থেকে যাচাই করা হয়েছেকোডটি আবার পাঠানফোন নম্বর যাচাই করুনচালিয়ে যান%1$s এ ট্যাপ করলে আপনি একটি এসএমএস পাঠাতে পারেন। মেসেজ ও ডেটার চার্জ প্রযোজ্য।“%1$s” বোতামে ট্যাপ করার অর্থ, আপনি আমাদের %2$s এবং %3$s-এর সাথে সম্মত। একটি এসএমএস পাঠানো হতে পারে। মেসেজ এবং ডেটার উপরে প্রযোজ্য চার্জ লাগতে পারে।
- “%1$s” বোতামে ট্যাপ করার অর্থ, আপনি আমাদের %2$s-এর সাথে সম্মত। একটি এসএমএস পাঠানো হতে পারে। মেসেজ এবং ডেটার উপরে প্রযোজ্য চার্জ লাগতে পারে।
- “%1$s” বোতামে ট্যাপ করার অর্থ, আপনি আমাদের %2$s-এর সাথে সম্মত। একটি এসএমএস পাঠানো হতে পারে। মেসেজ এবং ডেটার উপরে প্রযোজ্য চার্জ লাগতে পারে।
diff --git a/auth/src/main/res/values-ca/strings.xml b/auth/src/main/res/values-ca/strings.xml
index 2b3a3fd7e..0539229f8 100755
--- a/auth/src/main/res/values-ca/strings.xml
+++ b/auth/src/main/res/values-ca/strings.xml
@@ -2,17 +2,15 @@
S\'està carregant…Inicia la sessióEn continuar, acceptes les nostres %1$s i la nostra %2$s.
- En continuar, acceptes les nostres %1$s.
- En continuar, acceptes la nostra %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubInicia la sessió amb GoogleInicia la sessió amb FacebookInicia la sessió amb Twitter
+ Inicia la sessió amb GitHubInicia la sessió amb l\'adreça electrònicaInicia la sessió amb el telèfonSegüent
@@ -53,22 +51,15 @@
Torna a enviar el codi d\'aquí a 0:%02dVerifica el número de telèfonS\'està verificant…
- S\'està recuperant l\'SMS…El codi no és correcte. Torna-ho a provar.
- D\'acordAquest número de telèfon s\'ha utilitzat massa vegadesHi ha hagut un problema en verificar el número de telèfonAquest codi ja no és vàlidInicia la sessió amb el número de telèfon
- Fet
- S\'ha verificat.
- S\'ha enviat el codi.
- S\'està tornant a enviar…
+ El número de telèfon s\'ha verificat automàticamentTorna a enviar el codiVerifica el número de telèfonContinuaEn tocar %1$s, és possible que s\'enviï un SMS. Es poden aplicar tarifes de dades i missatges.En tocar %1$s, acceptes les nostres %2$s i la nostra %3$s. És possible que s\'enviï un SMS. Es poden aplicar tarifes de dades i missatges.
- En tocar %1$s, acceptes les nostres %2$s. És possible que s\'enviï un SMS. Es poden aplicar tarifes de dades i missatges.
- En tocar %1$s, acceptes la nostra %2$s. És possible que s\'enviï un SMS. Es poden aplicar tarifes de dades i missatges.
diff --git a/auth/src/main/res/values-cs/strings.xml b/auth/src/main/res/values-cs/strings.xml
index 9537ea17e..e2c818e04 100755
--- a/auth/src/main/res/values-cs/strings.xml
+++ b/auth/src/main/res/values-cs/strings.xml
@@ -2,17 +2,15 @@
Načítání…Přihlásit seBudete-li pokračovat, vyjadřujete svůj souhlas s dokumenty %1$s a %2$s.
- Budete-li pokračovat, vyjadřujete svůj souhlas s dokumentem %1$s.
- Budete-li pokračovat, vyjadřujete svůj souhlas s dokumentem %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubPřihlásit se přes GooglePřihlásit se přes FacebookPřihlásit se přes Twitter
+ Přihlásit se přes GitHubPřihlásit se pomocí e-mailuPřihlásit se pomocí telefonuDalší
@@ -53,22 +51,15 @@
Znovu zaslat kód za 0:%02dOvěřit telefonní čísloOvěřování…
- Načítání SMS…Špatný kód. Zkuste to znovu.
- V pořádkuToto telefonní číslo již bylo použito příliš mnohokrátPři ověřování vašeho telefonního čísla došlo k potížímPlatnost kódu vypršelaPřihlášení pomocí telefonního čísla
- Hotovo
- Ověřeno!
- Kód odeslán!
- Opakované odesílání…
+ Telefonní číslo bylo automaticky ověřenoZnovu poslat kódOvěřit telefonní čísloPokračovatPo klepnutí na možnost %1$s může být odeslána SMS. Mohou být účtovány poplatky za zprávy a data.Klepnutím na tlačítko %1$s vyjadřujete svůj souhlas s dokumenty %2$s a %3$s. Může být odeslána SMS a mohou být účtovány poplatky za zprávy a data.
- Klepnutím na tlačítko %1$s vyjadřujete svůj souhlas s dokumentem %2$s. Může být odeslána SMS a mohou být účtovány poplatky za zprávy a data.
- Klepnutím na tlačítko %1$s vyjadřujete svůj souhlas s dokumentem %2$s. Může být odeslána SMS a mohou být účtovány poplatky za zprávy a data.
diff --git a/auth/src/main/res/values-da/strings.xml b/auth/src/main/res/values-da/strings.xml
index 72f689d76..9eb0b6061 100755
--- a/auth/src/main/res/values-da/strings.xml
+++ b/auth/src/main/res/values-da/strings.xml
@@ -2,17 +2,15 @@
Indlæser…Log indVed at fortsætte indikerer du, at du accepterer vores %1$s og %2$s.
- Ved at fortsætte indikerer du, at du accepterer vores %1$s.
- Ved at fortsætte indikerer du, at du accepterer vores %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubLog ind med GoogleLog ind med FacebookLog ind med Twitter
+ Log ind med GitHubLog ind med mailLog ind med telefonNæste
@@ -53,22 +51,15 @@
Send koden igen om 0:%02dBekræft dit telefonnummerBekræfter…
- Henter sms…Koden er forkert. Prøv igen.
- OKDette telefonnummer er blevet brugt for mange gangeDit telefonnummer kunne ikke bekræftesDenne kode er ikke længere gyldigLog ind med telefonnummer
- Udført
- Bekræftet!
- Kode sendt.
- Sender igen…
+ Telefonnummeret blev bekræftet automatiskSend koden igenBekræft telefonnummerFortsætNår du trykker på “%1$s”, sendes der måske en sms. Der opkræves muligvis gebyrer for beskeder og data.Når du trykker på “%1$s”, indikerer du, at du accepterer vores %2$s og %3$s. Der sendes måske en sms. Der opkræves muligvis gebyrer for beskeder og data.
- Når du trykker på “%1$s”, indikerer du, at du accepterer vores %2$s. Der sendes måske en sms. Der opkræves muligvis gebyrer for beskeder og data.
- Når du trykker på “%1$s”, indikerer du, at du accepterer vores %2$s. Der sendes måske en sms. Der opkræves muligvis gebyrer for beskeder og data.
diff --git a/auth/src/main/res/values-de-rAT/strings.xml b/auth/src/main/res/values-de-rAT/strings.xml
index 1909f450b..ed621c961 100755
--- a/auth/src/main/res/values-de-rAT/strings.xml
+++ b/auth/src/main/res/values-de-rAT/strings.xml
@@ -2,17 +2,15 @@
Wird geladen…AnmeldenIndem Sie fortfahren, stimmen Sie unseren %1$s und unserer %2$s zu.
- Indem Sie fortfahren, stimmen Sie unseren %1$s zu.
- Indem Sie fortfahren, stimmen Sie unserer %1$s zu.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubÜber Google anmeldenÜber Facebook anmeldenÜber Twitter anmelden
+ Über GitHub anmeldenMit einer E-Mail-Adresse anmeldenMit einer Telefonnummer anmeldenWeiter
@@ -53,22 +51,15 @@
Code in 0:%02d erneut sendenTelefonnummer bestätigenWird verifiziert…
- SMS werden abgerufen…Falscher Code. Versuchen Sie es noch einmal.
- OKDiese Telefonnummer wurde schon zu oft verwendetBei der Bestätigung Ihrer Telefonnummer ist ein Problem aufgetretenDieser Code ist nicht mehr gültigMit einer Telefonnummer anmelden
- Fertig
- Bestätigt
- Code gesendet
- Wird erneut gesendet…
+ Telefonnummer wurde automatisch bestätigtCode erneut sendenTelefonnummer bestätigenWeiterWenn Sie auf “%1$s” tippen, erhalten Sie möglicherweise eine SMS. Es können Gebühren für SMS und Datenübertragung anfallen.Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s und unserer %3$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unserer %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
diff --git a/auth/src/main/res/values-de-rCH/strings.xml b/auth/src/main/res/values-de-rCH/strings.xml
index 1909f450b..ed621c961 100755
--- a/auth/src/main/res/values-de-rCH/strings.xml
+++ b/auth/src/main/res/values-de-rCH/strings.xml
@@ -2,17 +2,15 @@
Wird geladen…AnmeldenIndem Sie fortfahren, stimmen Sie unseren %1$s und unserer %2$s zu.
- Indem Sie fortfahren, stimmen Sie unseren %1$s zu.
- Indem Sie fortfahren, stimmen Sie unserer %1$s zu.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubÜber Google anmeldenÜber Facebook anmeldenÜber Twitter anmelden
+ Über GitHub anmeldenMit einer E-Mail-Adresse anmeldenMit einer Telefonnummer anmeldenWeiter
@@ -53,22 +51,15 @@
Code in 0:%02d erneut sendenTelefonnummer bestätigenWird verifiziert…
- SMS werden abgerufen…Falscher Code. Versuchen Sie es noch einmal.
- OKDiese Telefonnummer wurde schon zu oft verwendetBei der Bestätigung Ihrer Telefonnummer ist ein Problem aufgetretenDieser Code ist nicht mehr gültigMit einer Telefonnummer anmelden
- Fertig
- Bestätigt
- Code gesendet
- Wird erneut gesendet…
+ Telefonnummer wurde automatisch bestätigtCode erneut sendenTelefonnummer bestätigenWeiterWenn Sie auf “%1$s” tippen, erhalten Sie möglicherweise eine SMS. Es können Gebühren für SMS und Datenübertragung anfallen.Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s und unserer %3$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unserer %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
diff --git a/auth/src/main/res/values-de/strings.xml b/auth/src/main/res/values-de/strings.xml
index 1909f450b..ed621c961 100755
--- a/auth/src/main/res/values-de/strings.xml
+++ b/auth/src/main/res/values-de/strings.xml
@@ -2,17 +2,15 @@
Wird geladen…AnmeldenIndem Sie fortfahren, stimmen Sie unseren %1$s und unserer %2$s zu.
- Indem Sie fortfahren, stimmen Sie unseren %1$s zu.
- Indem Sie fortfahren, stimmen Sie unserer %1$s zu.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubÜber Google anmeldenÜber Facebook anmeldenÜber Twitter anmelden
+ Über GitHub anmeldenMit einer E-Mail-Adresse anmeldenMit einer Telefonnummer anmeldenWeiter
@@ -53,22 +51,15 @@
Code in 0:%02d erneut sendenTelefonnummer bestätigenWird verifiziert…
- SMS werden abgerufen…Falscher Code. Versuchen Sie es noch einmal.
- OKDiese Telefonnummer wurde schon zu oft verwendetBei der Bestätigung Ihrer Telefonnummer ist ein Problem aufgetretenDieser Code ist nicht mehr gültigMit einer Telefonnummer anmelden
- Fertig
- Bestätigt
- Code gesendet
- Wird erneut gesendet…
+ Telefonnummer wurde automatisch bestätigtCode erneut sendenTelefonnummer bestätigenWeiterWenn Sie auf “%1$s” tippen, erhalten Sie möglicherweise eine SMS. Es können Gebühren für SMS und Datenübertragung anfallen.Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s und unserer %3$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unserer %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
diff --git a/auth/src/main/res/values-el/strings.xml b/auth/src/main/res/values-el/strings.xml
index 998fd2e45..d37fcf26f 100755
--- a/auth/src/main/res/values-el/strings.xml
+++ b/auth/src/main/res/values-el/strings.xml
@@ -2,17 +2,15 @@
Γίνεται φόρτωση…ΣύνδεσηΑν συνεχίσετε, δηλώνετε ότι αποδέχεστε τους %1$s και την %2$s.
- Αν συνεχίσετε, δηλώνετε ότι αποδέχεστε τους %1$s.
- Αν συνεχίσετε, δηλώνετε ότι αποδέχεστε την %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubΣύνδεση μέσω GoogleΣύνδεση μέσω FacebookΣύνδεση μέσω Twitter
+ Σύνδεση μέσω GitHubΣύνδεση μέσω ηλεκτρονικού ταχυδρομείουΣύνδεση μέσω τηλεφώνουΕπόμενο
@@ -53,22 +51,15 @@
Επανάληψη αποστολής κωδικού σε 0:%02dΕπαλήθευση του τηλεφώνου σαςΕπαλήθευση…
- Γίνεται ανάκτηση SMS…Εσφαλμένος κωδικός. Δοκιμάστε ξανά.
- ΟΚΑυτός ο αριθμός τηλεφώνου χρησιμοποιήθηκε πάρα πολλές φορέςΠαρουσιάστηκε πρόβλημα με την επαλήθευση του αριθμού τηλεφώνουΑυτός ο κωδικός δεν είναι πλέον έγκυροςΣύνδεση με αριθμό τηλεφώνου
- Τέλος
- Επαληθεύτηκε!
- Ο κωδικός στάλθηκε!
- Επανάληψη αποστολής…
+ Ο αριθμός τηλεφώνου επαληθεύτηκε αυτόματαΕπανάληψη αποστολής κωδικούΕπαλήθευση αριθμού τηλεφώνουΣυνέχειαΑν πατήσετε “%1$s”, μπορεί να σταλεί ένα SMS. Ενδέχεται να ισχύουν χρεώσεις μηνυμάτων και δεδομένων.Αν πατήσετε “%1$s”, δηλώνετε ότι αποδέχεστε τους %2$s και την %3$s. Μπορεί να σταλεί ένα SMS. Ενδέχεται να ισχύουν χρεώσεις μηνυμάτων και δεδομένων.
- Αν πατήσετε “%1$s”, δηλώνετε ότι αποδέχεστε τους %2$s. Μπορεί να σταλεί ένα SMS. Ενδέχεται να ισχύουν χρεώσεις μηνυμάτων και δεδομένων.
- Αν πατήσετε “%1$s”, δηλώνετε ότι αποδέχεστε την %2$s. Μπορεί να σταλεί ένα SMS. Ενδέχεται να ισχύουν χρεώσεις μηνυμάτων και δεδομένων.
diff --git a/auth/src/main/res/values-en-rAU/strings.xml b/auth/src/main/res/values-en-rAU/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rAU/strings.xml
+++ b/auth/src/main/res/values-en-rAU/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-en-rCA/strings.xml b/auth/src/main/res/values-en-rCA/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rCA/strings.xml
+++ b/auth/src/main/res/values-en-rCA/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-en-rGB/strings.xml b/auth/src/main/res/values-en-rGB/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rGB/strings.xml
+++ b/auth/src/main/res/values-en-rGB/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-en-rIE/strings.xml b/auth/src/main/res/values-en-rIE/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rIE/strings.xml
+++ b/auth/src/main/res/values-en-rIE/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-en-rIN/strings.xml b/auth/src/main/res/values-en-rIN/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rIN/strings.xml
+++ b/auth/src/main/res/values-en-rIN/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-en-rSG/strings.xml b/auth/src/main/res/values-en-rSG/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rSG/strings.xml
+++ b/auth/src/main/res/values-en-rSG/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-en-rZA/strings.xml b/auth/src/main/res/values-en-rZA/strings.xml
index 398144aad..3f77e4877 100755
--- a/auth/src/main/res/values-en-rZA/strings.xml
+++ b/auth/src/main/res/values-en-rZA/strings.xml
@@ -2,17 +2,15 @@
Loading…Sign inBy continuing, you are indicating that you accept our %1$s and %2$s.
- By continuing, you are indicating that you accept our %1$s.
- By continuing, you are indicating that you accept our %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSign in with GoogleSign in with FacebookSign in with Twitter
+ Sign in with GitHubSign in with emailSign in with phoneNext
@@ -53,22 +51,15 @@
Resend code in 0:%02dVerify your phone numberVerifying…
- Retrieving SMS…Wrong code. Try again.
- OKThis phone number has been used too many timesThere was a problem verifying your phone numberThis code is no longer validSign in with phone number
- Done
- Verified.
- Code sent.
- Resending…
+ Phone number automatically verifiedResend codeVerify Phone NumberContinueBy tapping “%1$s”, an SMS may be sent. Message & data rates may apply.By tapping “%1$s”, you are indicating that you accept our %2$s and %3$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
- By tapping “%1$s”, you are indicating that you accept our %2$s. An SMS may be sent. Message & data rates may apply.
diff --git a/auth/src/main/res/values-es-rAR/strings.xml b/auth/src/main/res/values-es-rAR/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rAR/strings.xml
+++ b/auth/src/main/res/values-es-rAR/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rBO/strings.xml b/auth/src/main/res/values-es-rBO/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rBO/strings.xml
+++ b/auth/src/main/res/values-es-rBO/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rCL/strings.xml b/auth/src/main/res/values-es-rCL/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rCL/strings.xml
+++ b/auth/src/main/res/values-es-rCL/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rCO/strings.xml b/auth/src/main/res/values-es-rCO/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rCO/strings.xml
+++ b/auth/src/main/res/values-es-rCO/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rCR/strings.xml b/auth/src/main/res/values-es-rCR/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rCR/strings.xml
+++ b/auth/src/main/res/values-es-rCR/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rDO/strings.xml b/auth/src/main/res/values-es-rDO/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rDO/strings.xml
+++ b/auth/src/main/res/values-es-rDO/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rEC/strings.xml b/auth/src/main/res/values-es-rEC/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rEC/strings.xml
+++ b/auth/src/main/res/values-es-rEC/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rGT/strings.xml b/auth/src/main/res/values-es-rGT/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rGT/strings.xml
+++ b/auth/src/main/res/values-es-rGT/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rHN/strings.xml b/auth/src/main/res/values-es-rHN/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rHN/strings.xml
+++ b/auth/src/main/res/values-es-rHN/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rMX/strings.xml b/auth/src/main/res/values-es-rMX/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rMX/strings.xml
+++ b/auth/src/main/res/values-es-rMX/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rNI/strings.xml b/auth/src/main/res/values-es-rNI/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rNI/strings.xml
+++ b/auth/src/main/res/values-es-rNI/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rPA/strings.xml b/auth/src/main/res/values-es-rPA/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rPA/strings.xml
+++ b/auth/src/main/res/values-es-rPA/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rPE/strings.xml b/auth/src/main/res/values-es-rPE/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rPE/strings.xml
+++ b/auth/src/main/res/values-es-rPE/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rPR/strings.xml b/auth/src/main/res/values-es-rPR/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rPR/strings.xml
+++ b/auth/src/main/res/values-es-rPR/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rPY/strings.xml b/auth/src/main/res/values-es-rPY/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rPY/strings.xml
+++ b/auth/src/main/res/values-es-rPY/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rSV/strings.xml b/auth/src/main/res/values-es-rSV/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rSV/strings.xml
+++ b/auth/src/main/res/values-es-rSV/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rUS/strings.xml b/auth/src/main/res/values-es-rUS/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rUS/strings.xml
+++ b/auth/src/main/res/values-es-rUS/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rUY/strings.xml b/auth/src/main/res/values-es-rUY/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rUY/strings.xml
+++ b/auth/src/main/res/values-es-rUY/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es-rVE/strings.xml b/auth/src/main/res/values-es-rVE/strings.xml
index e866cf722..7d63da241 100755
--- a/auth/src/main/res/values-es-rVE/strings.xml
+++ b/auth/src/main/res/values-es-rVE/strings.xml
@@ -2,17 +2,15 @@
Cargando…AccederSi continúas, indicas que aceptas nuestras %1$s y %2$s.
- Si continúas, indicas que aceptas nuestras %1$s.
- Si continúas, indicas que aceptas nuestras %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAcceder con GoogleAcceder con FacebookAcceder con Twitter
+ Acceder con GitHubAcceder con el correo electrónicoAcceder con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Se reenviará el código en 0:%02dVerifica tu número de teléfonoVerificando…
- Recuperando SMS…Código incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se usó demasiadas vecesOcurrió un problema durante la verificación de tu número de teléfonoEste código ya no es válidoAcceder con el número de teléfono
- Listo
- ¡Verificado!
- Se envió el código.
- Reenviando…
+ Se verificó automáticamente el número de teléfonoReenviar códigoVerificar número de teléfonoContinuarSi presionas “%1$s”, se enviará un SMS. Se aplicarán las tarifas de mensajes y datos.Si presionas “%1$s”, indicas que aceptas nuestras %2$s y %3$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
- Si presionas “%1$s”, indicas que aceptas nuestras %2$s. Es posible que se te envíe un SMS. Podrían aplicarse las tarifas de mensajes y datos.
diff --git a/auth/src/main/res/values-es/strings.xml b/auth/src/main/res/values-es/strings.xml
index fde709c50..960d42bcf 100755
--- a/auth/src/main/res/values-es/strings.xml
+++ b/auth/src/main/res/values-es/strings.xml
@@ -2,17 +2,15 @@
Cargando…Iniciar sesiónSi continúas, confirmas que aceptas nuestras %1$s y nuestra %2$s.
- Si continúas, confirmas que aceptas nuestras %1$s.
- Si continúas, confirmas que aceptas nuestra %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubIniciar sesión con GoogleIniciar sesión con FacebookIniciar sesión con Twitter
+ Iniciar sesión con GitHubIniciar sesión con el correo electrónicoIniciar sesión con el teléfonoSiguiente
@@ -53,22 +51,15 @@
Volver a enviar el código en 0:%02dVerificar el número de teléfonoVerificando…
- Recuperando SMS…El código es incorrecto. Vuelve a intentarlo.
- AceptarEste número de teléfono se ha usado demasiadas vecesNo se ha podido verificar el número de teléfonoEste código ya no es válidoIniciar sesión con el número de teléfono
- Listo
- Verificado
- Se ha enviado el código.
- Enviándolo de nuevo…
+ Se ha verificado automáticamente el número de teléfonoVolver a enviar códigoVerificar número de teléfonoContinuarAl tocar %1$s, podría enviarse un SMS. Es posible que se apliquen cargos de mensajería y de uso de datos.Si tocas %1$s, confirmas que aceptas nuestras %2$s y nuestra %3$s. Podría enviarse un SMS, por lo que es posible que se apliquen cargos de mensajería y de uso de datos.
- Si tocas %1$s, confirmas que aceptas nuestras %2$s. Podría enviarse un SMS, por lo que es posible que se apliquen cargos de mensajería y de uso de datos.
- Si tocas %1$s, confirmas que aceptas nuestra %2$s. Podría enviarse un SMS, por lo que es posible que se apliquen cargos de mensajería y de uso de datos.
diff --git a/auth/src/main/res/values-fa/strings.xml b/auth/src/main/res/values-fa/strings.xml
index 6cf8eeb74..9ea43bb1e 100755
--- a/auth/src/main/res/values-fa/strings.xml
+++ b/auth/src/main/res/values-fa/strings.xml
@@ -2,17 +2,15 @@
درحال بارگیری…ورود به سیستمدرصورت ادامهدادن، موافقتتان را با %1$s و %2$s اعلام میکنید.
- درصورت ادامهدادن موافقتتان را با %1$s اعلام میکنید.
- درصورت ادامهدادن موافقتتان را با %1$s اعلام میکنید.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubورود به سیستم با Googleورود به سیستم با Facebookورود به سیستم با Twitter
+ ورود به سیستم با GitHubورود به سیستم با رایانامهورود به سیستم با تلفنبعدی
@@ -53,22 +51,15 @@
کد پس از %02d:0 مجدداً ارسال میشودتأیید شماره تلفندرحال تأیید…
- در حال بازیابی پیامک…کد اشتباه است. دوباره امتحان کنید.
- تأییداز این شماره تلفن به دفعات زیاد استفاده شده استهنگام تأیید شماره تلفنتان مشکلی پیش آمداین کد دیگر معتبر نیستورود به سیستم با شماره تلفن
- انجام شد
- تأیید شد!
- کد ارسال شد!
- در حال ارسال مجدد…
+ شماره تلفن بهطور خودکار بهتأیید رسیدارسال مجدد کدتأیید شماره تلفنادامهبا ضربه زدن روی «%1$s»، پیامکی برایتان ارسال میشود. هزینه پیام و داده اعمال میشود.درصورت ضربهزدن روی «%1$s»، موافقتتان را با %2$s و %3$s اعلام میکنید. پیامکی ارسال میشود. ممکن است هزینه داده و «پیام» محاسبه شود.
- درصورت ضربهزدن روی «%1$s»، موافقتتان را با %2$s اعلام میکنید. پیامکی ارسال میشود. ممکن است هزینه داده و «پیام» محاسبه شود.
- درصورت ضربهزدن روی «%1$s»، موافقتتان را با %2$s اعلام میکنید. پیامکی ارسال میشود. ممکن است هزینه داده و «پیام» محاسبه شود.
diff --git a/auth/src/main/res/values-fi/strings.xml b/auth/src/main/res/values-fi/strings.xml
index 0c745d4f8..6e5d776fa 100755
--- a/auth/src/main/res/values-fi/strings.xml
+++ b/auth/src/main/res/values-fi/strings.xml
@@ -2,17 +2,15 @@
Ladataan…Kirjaudu sisäänJatkamalla vahvistat, että hyväksyt seuraavat: %1$s ja %2$s.
- Jatkamalla vahvistat, että hyväksyt %1$s.
- Jatkamalla vahvistat, että hyväksyt seuraavan: %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubKirjaudu Google-tililläKirjaudu Facebook-tililläKirjaudu Twitter-tilillä
+ Kirjaudu GitHub-tililläKirjaudu sähköpostillaKirjaudu puhelimellaSeuraava
@@ -53,22 +51,15 @@
Lähetä koodi uudelleen seuraavan ajan kuluttua: 0:%02d.Puhelinnumeron vahvistaminenVahvistetaan…
- Noudetaan tekstiviesti…Väärä koodi. Yritä uudelleen.
- OkTätä puhelinnumeroa on käytetty liian monta kertaa.Puhelinnumerosi vahvistamisessa tapahtui virhe.Tämä koodi ei ole enää voimassa.Kirjaudu puhelinnumerolla
- Valmis
- Vahvistettu!
- Koodi lähetetty
- Lähetetään uudelleen…
+ Puhelinnumero vahvistettu automaattisestiLähetä koodi uudelleenVahvista puhelinnumeroJatkaKun napautat %1$s, tekstiviesti voidaan lähettää. Datan ja viestien käyttö voi olla maksullista.Napauttamalla %1$s vahvistat hyväksyväsi seuraavat: %2$s ja %3$s. Tekstiviesti voidaan lähettää, ja datan ja viestien käyttö voi olla maksullista.
- Napauttamalla %1$s vahvistat hyväksyväsi %2$s. Tekstiviesti voidaan lähettää, ja datan ja viestien käyttö voi olla maksullista.
- Napauttamalla %1$s vahvistat hyväksyväsi seuraavan: %2$s. Tekstiviesti voidaan lähettää, ja datan ja viestien käyttö voi olla maksullista.
diff --git a/auth/src/main/res/values-fil/strings.xml b/auth/src/main/res/values-fil/strings.xml
index 6eddc0122..e9a8de2de 100755
--- a/auth/src/main/res/values-fil/strings.xml
+++ b/auth/src/main/res/values-fil/strings.xml
@@ -2,17 +2,15 @@
Naglo-load…Mag-sign inSa pagpapatuloy, ipinababatid mo na tinatanggap mo ang aming %1$s at %2$s.
- Sa pagpapatuloy, ipinababatid mo na tinatanggap mo ang aming %1$s.
- Sa pagpapatuloy, ipinababatid mo na tinatanggap mo ang aming %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFecebookTwitter
+ GitHubMag-sign in sa GoogleMag-sign in sa FacebookMag-sign in sa Twitter
+ Mag-sign in sa GitHubMag-sign in gamit ang emailMag-sign in gamit ang teleponoSusunod
@@ -53,22 +51,15 @@
Ipadala muli ang code sa loob ng 0:%02dI-verify ang numero ng iyong teleponoBine-verify…
- Kinukuha ang sms…Maling code. Subukang muli.
- OKMasyadong maraming beses nang nagamit ang numero ng teleponong itoNagkaproblema sa pag-verify ng numero ng iyong teleponoWala nang bisa ang code na itoMag-sign in gamit ang numero ng telepono
- Tapos Na
- Na-verify!
- Naipadala ang code!
- Ipinapadalang muli…
+ Awtomatikong na-verify ang numero ng teleponoIpadala Muli ang CodeI-verify ang Numero ng TeleponoMagpatuloySa pag-tap sa “%1$s,“ maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.Sa pag-tap sa “%1$s”, ipinababatid mo na tinatanggap mo ang aming %2$s at %3$s. Maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.
- Sa pag-tap sa “%1$s”, ipinababatid mo na tinatanggap mo ang aming %2$s. Maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.
- Sa pag-tap sa “%1$s”, ipinababatid mo na tinatanggap mo ang aming %2$s. Maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.
diff --git a/auth/src/main/res/values-fr-rCH/strings.xml b/auth/src/main/res/values-fr-rCH/strings.xml
index c89153c43..747acacae 100755
--- a/auth/src/main/res/values-fr-rCH/strings.xml
+++ b/auth/src/main/res/values-fr-rCH/strings.xml
@@ -2,17 +2,15 @@
Chargement…Se connecterEn continuant, vous acceptez les %1$s et les %2$s.
- En continuant, vous acceptez les %1$s.
- En continuant, vous acceptez les %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSe connecter avec GoogleSe connecter avec FacebookSe connecter avec Twitter
+ Se connecter avec GitHubSe connecter avec une adresse e-mailSe connecter avec un téléphoneSuivant
@@ -53,22 +51,15 @@
Renvoyer le code dans 0:%02dValider votre numéro de téléphoneValidation…
- Récupération du SMS…Code erroné. Veuillez réessayer.
- OKCe numéro de téléphone a été utilisé un trop grand nombre de foisUn problème est survenu lors de la validation de votre numéro de téléphoneCe code n\'est plus valideConnectez-vous avec votre numéro de téléphone
- OK
- Le code a bien été validé.
- Le code a bien été envoyé.
- Nouvel envoi du code…
+ Numéro de téléphone validé automatiquementRenvoyer le codeValider le numéro de téléphoneContinuerEn appuyant sur “%1$s”, vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.En appuyant sur “%1$s”, vous acceptez les %2$s et les %3$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
- En appuyant sur “%1$s”, vous acceptez les %2$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
- En appuyant sur “%1$s”, vous acceptez les %2$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
diff --git a/auth/src/main/res/values-fr/strings.xml b/auth/src/main/res/values-fr/strings.xml
index c89153c43..747acacae 100755
--- a/auth/src/main/res/values-fr/strings.xml
+++ b/auth/src/main/res/values-fr/strings.xml
@@ -2,17 +2,15 @@
Chargement…Se connecterEn continuant, vous acceptez les %1$s et les %2$s.
- En continuant, vous acceptez les %1$s.
- En continuant, vous acceptez les %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSe connecter avec GoogleSe connecter avec FacebookSe connecter avec Twitter
+ Se connecter avec GitHubSe connecter avec une adresse e-mailSe connecter avec un téléphoneSuivant
@@ -53,22 +51,15 @@
Renvoyer le code dans 0:%02dValider votre numéro de téléphoneValidation…
- Récupération du SMS…Code erroné. Veuillez réessayer.
- OKCe numéro de téléphone a été utilisé un trop grand nombre de foisUn problème est survenu lors de la validation de votre numéro de téléphoneCe code n\'est plus valideConnectez-vous avec votre numéro de téléphone
- OK
- Le code a bien été validé.
- Le code a bien été envoyé.
- Nouvel envoi du code…
+ Numéro de téléphone validé automatiquementRenvoyer le codeValider le numéro de téléphoneContinuerEn appuyant sur “%1$s”, vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.En appuyant sur “%1$s”, vous acceptez les %2$s et les %3$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
- En appuyant sur “%1$s”, vous acceptez les %2$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
- En appuyant sur “%1$s”, vous acceptez les %2$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
diff --git a/auth/src/main/res/values-gsw/strings.xml b/auth/src/main/res/values-gsw/strings.xml
index 1909f450b..ed621c961 100755
--- a/auth/src/main/res/values-gsw/strings.xml
+++ b/auth/src/main/res/values-gsw/strings.xml
@@ -2,17 +2,15 @@
Wird geladen…AnmeldenIndem Sie fortfahren, stimmen Sie unseren %1$s und unserer %2$s zu.
- Indem Sie fortfahren, stimmen Sie unseren %1$s zu.
- Indem Sie fortfahren, stimmen Sie unserer %1$s zu.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubÜber Google anmeldenÜber Facebook anmeldenÜber Twitter anmelden
+ Über GitHub anmeldenMit einer E-Mail-Adresse anmeldenMit einer Telefonnummer anmeldenWeiter
@@ -53,22 +51,15 @@
Code in 0:%02d erneut sendenTelefonnummer bestätigenWird verifiziert…
- SMS werden abgerufen…Falscher Code. Versuchen Sie es noch einmal.
- OKDiese Telefonnummer wurde schon zu oft verwendetBei der Bestätigung Ihrer Telefonnummer ist ein Problem aufgetretenDieser Code ist nicht mehr gültigMit einer Telefonnummer anmelden
- Fertig
- Bestätigt
- Code gesendet
- Wird erneut gesendet…
+ Telefonnummer wurde automatisch bestätigtCode erneut sendenTelefonnummer bestätigenWeiterWenn Sie auf “%1$s” tippen, erhalten Sie möglicherweise eine SMS. Es können Gebühren für SMS und Datenübertragung anfallen.Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s und unserer %3$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unseren %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
- Indem Sie auf “%1$s” tippen, stimmen Sie unserer %2$s zu. Sie erhalten möglicherweise eine SMS und es können Gebühren für die Nachricht und die Datenübertragung anfallen.
diff --git a/auth/src/main/res/values-gu/strings.xml b/auth/src/main/res/values-gu/strings.xml
index febf5bfaf..4fbd261d9 100755
--- a/auth/src/main/res/values-gu/strings.xml
+++ b/auth/src/main/res/values-gu/strings.xml
@@ -2,17 +2,15 @@
લોડ કરી રહ્યું છે…સાઇન ઇન કરોચાલુ રાખીને, તમે સૂચવી રહ્યાં છો કે તમે અમારી %1$s અને %2$sને સ્વીકારો છો.
- ચાલુ રાખીને, તમે સૂચવી રહ્યાં છો કે તમે અમારી %1$sને સ્વીકારો છો.
- ચાલુ રાખીને, તમે સૂચવી રહ્યાં છો કે તમે અમારી %1$sને સ્વીકારો છો.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubGoogle વડે સાઇન ઇન કરોFacebook વડે સાઇન ઇન કરોTwitter વડે સાઇન ઇન કરો
+ GitHub વડે સાઇન ઇન કરોઇમેઇલ વડે સાઇન ઇન કરોફોન વડે સાઇન ઇન કરોઆગળ
@@ -53,22 +51,15 @@
0 માં કોડ ફરીથી મોકલો:%02dતમારો ફોન નંબર ચકાસોચકાસી રહ્યાં છીએ…
- SMS પુનઃપ્રાપ્ત કરી રહ્યાં છીએ…કોડ ખોટો છે. ફરી પ્રયાસ કરો.
- ઓકેઆ ફોન નંબરનો ઉપયોગ ઘણી બધી વખત થઇ ગયો છેતમારો ફોન નંબર ચકાસવામાં સમસ્યા આવી હતીઆ કોડ હવે માન્ય નથીફોન નંબર વડે સાઇન ઇન કરો
- થઈ ગયું
- ચકાસેલ!
- કોડ મોકલ્યો!
- ફરીથી મોકલી રહ્યાં છીએ…
+ ફોન નંબર આપમેળે ચકાસવામાં આવ્યોકોડ ફરીથી મોકલોફોન નંબર ચકાસોઆગળ વધો“%1$s”ને ટૅપ કરવાથી, કદાચ એક SMS મોકલવામાં આવી શકે છે. સંદેશ અને ડેટા શુલ્ક લાગુ થઈ શકે છે.“%1$s” ટૅપ કરીને, તમે સૂચવી રહ્યાં છો કે તમે અમારી %2$s અને %3$sને સ્વીકારો છો. SMS મોકલવામાં આવી શકે છે. સંદેશ અને ડેટા શુલ્ક લાગુ થઈ શકે છે.
- “%1$s” ટૅપ કરીને, તમે સૂચવી રહ્યાં છો કે તમે અમારી %2$sને સ્વીકારો છો. SMS મોકલવામાં આવી શકે છે. સંદેશ અને ડેટા શુલ્ક લાગુ થઈ શકે છે.
- “%1$s” ટૅપ કરીને, તમે સૂચવી રહ્યાં છો કે તમે અમારી %2$sને સ્વીકારો છો. SMS મોકલવામાં આવી શકે છે. સંદેશ અને ડેટા શુલ્ક લાગુ થઈ શકે છે.
diff --git a/auth/src/main/res/values-hi/strings.xml b/auth/src/main/res/values-hi/strings.xml
index af4147e76..4622c179e 100755
--- a/auth/src/main/res/values-hi/strings.xml
+++ b/auth/src/main/res/values-hi/strings.xml
@@ -2,17 +2,15 @@
लोड हो रहा है…प्रवेश करेंजारी रखकर, आप यह बताते हैं कि आप हमारी %1$s और %2$s को मंज़ूर करते हैं.
- जारी रखकर, आप यह बताते हैं कि आप हमारी %1$s मंज़ूर करते हैं.
- जारी रखकर, आप यह बताते हैं कि आप हमारी %1$s मंज़ूर करते हैं.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubGoogle से प्रवेश करेंFacebook से प्रवेश करेंTwitter से प्रवेश करें
+ GitHub के साथ साइन इन करेंईमेल से प्रवेश करेंफ़ोन से प्रवेश करेंअगला
@@ -53,22 +51,15 @@
0:%02d में कोड फिर से भेजेंअपने फ़ोन नंबर की पुष्टि करेंपुष्टि की जा रही है…
- sms फिर से लाया जा रहा है…गलत कोड. फिर से कोशिश करें.
- ठीकइस फ़ोन नंबर का उपयोग कई बार किया गया हैआपके फ़ोन नंबर की पुष्टि करने में कोई समस्या हुईयह कोड अब मान्य नहीं हैफ़ोन नंबर के साथ प्रवेश करें
- हो गया
- पुष्टि हो चुकी है!
- कोड भेज दिया गया!
- फिर से भेजा जा रहा है…
+ फ़ोन नंबर की अपने आप पुष्टि की गईकोड फिर से भेजेंफ़ोन नंबर की पुष्टि करेंजारी रखें“%1$s” पर टैप करने पर, एक मैसेज (एसएमएस) भेजा जा सकता है. मैसेज और डेटा दरें लागू हो सकती हैं.“%1$s” पर टैप करके, आप यह बताते हैं कि आप हमारी %2$s और %3$s को मंज़ूर करते हैं. एक मैसेज (एसएमएस) भेजा जा सकता है. मैसेज और डेटा दरें लागू हो सकती हैं.
- “%1$s” पर टैप करके, आप यह बताते हैं कि आप हमारी %2$s मंज़ूर करते हैं. एक मैसेज (एसएमएस) भेजा जा सकता है. मैसेज और डेटा दरें लागू हो सकती हैं.
- “%1$s” पर टैप करके, आप यह बताते हैं कि आप हमारी %2$s मंज़ूर करते हैं. एक मैसेज (एसएमएस) भेजा जा सकता है. मैसेज और डेटा दरें लागू हो सकती हैं.
diff --git a/auth/src/main/res/values-hr/strings.xml b/auth/src/main/res/values-hr/strings.xml
index 3cbfabf82..b677fe535 100755
--- a/auth/src/main/res/values-hr/strings.xml
+++ b/auth/src/main/res/values-hr/strings.xml
@@ -2,17 +2,15 @@
Učitavanje…PrijavaAko nastavite, potvrđujete da prihvaćate odredbe koje sadrže %1$s i %2$s.
- Ako nastavite, potvrđujete da prihvaćate odredbe koje sadrži %1$s.
- Ako nastavite, potvrđujete da prihvaćate odredbe koje sadrži %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubPrijava putem GoogleaPrijava putem FacebookaPrijava putem Twittera
+ Prijava putem GitHubaPrijava putem e-adresePrijava putem telefonaDalje
@@ -53,22 +51,15 @@
Ponovno slanje koda za 0:%02dPotvrda telefonskog brojaPotvrđivanje…
- Dohvaćanje SMS-a…Pogrešan kôd. Pokušajte ponovo.
- U reduTaj telefonski broj upotrijebljen je previše putaDošlo je do problema s potvrdom vašeg telefonskog brojaKôd više nije važećiPrijava putem telefonskog broja
- Gotovo
- Potvrda je uspjela!
- Kôd je poslan!
- Ponovno slanje…
+ Telefonski je broj automatski potvrđenPonovo pošalji kôdPotvrda telefonskog brojaNastaviDodirivanje gumba “%1$s” može dovesti do slanja SMS poruke. Mogu se primijeniti naknade za slanje poruka i podatkovni promet.Ako dodirnete “%1$s”, potvrđujete da prihvaćate odredbe koje sadrže %2$s i %3$s. Možda ćemo vam poslati SMS. Moguća je naplata poruke i podatkovnog prometa.
- Ako dodirnete “%1$s”, potvrđujete da prihvaćate odredbe koje sadrži %2$s. Možda ćemo vam poslati SMS. Moguća je naplata poruke i podatkovnog prometa.
- Ako dodirnete “%1$s”, potvrđujete da prihvaćate odredbe koje sadrži %2$s. Možda ćemo vam poslati SMS. Moguća je naplata poruke i podatkovnog prometa.
diff --git a/auth/src/main/res/values-hu/strings.xml b/auth/src/main/res/values-hu/strings.xml
index 27ced0ba1..0a1dcf73a 100755
--- a/auth/src/main/res/values-hu/strings.xml
+++ b/auth/src/main/res/values-hu/strings.xml
@@ -2,17 +2,15 @@
Betöltés…BejelentkezésA folytatással elfogadja a következő dokumentumokat: %1$s és %2$s.
- A folytatással elfogadja a következő dokumentumot: %1$s.
- A folytatással elfogadja a következő dokumentumot: %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubBejelentkezés Google-fiókkalBejelentkezés Facebook-fiókkalBejelentkezés Twitter-fiókkal
+ Bejelentkezés GitHubbalBejelentkezés e-mail-fiókkalBejelentkezés telefonnalKövetkező
@@ -53,22 +51,15 @@
Kód újraküldése ennyi idő elteltével: 0:%02dTelefonszám igazolásaEllenőrzés…
- SMS lekérése…Hibás kód. Próbálja újra.
- RendbenEzt a telefonszámot már túl sokszor használták.Hiba történt a telefonszám ellenőrzésekor.Ez a kód már nem érvényes.Bejelentkezés telefonszámmal
- Kész
- Ellenőrzött!
- A kódot elküldtük.
- Újraküldés…
+ A telefonszám automatikusan ellenőrizveKód újraküldéseTelefonszám igazolásaFolytatásHa a(z) „%1$s” gombra koppint, a rendszer SMS-t küldhet Önnek. A szolgáltató ezért üzenet- és adatforgalmi díjat számíthat fel.A(z) „%1$s” gombra való koppintással elfogadja a következő dokumentumokat: %2$s és %3$s. A rendszer SMS-t küldhet Önnek. A szolgáltató ezért üzenet- és adatforgalmi díjat számíthat fel.
- A(z) „%1$s” gombra való koppintással elfogadja a következő dokumentumot: %2$s. A rendszer SMS-t küldhet Önnek. A szolgáltató ezért üzenet- és adatforgalmi díjat számíthat fel.
- A(z) „%1$s” gombra való koppintással elfogadja a következő dokumentumot: %2$s. A rendszer SMS-t küldhet Önnek. A szolgáltató ezért üzenet- és adatforgalmi díjat számíthat fel.
diff --git a/auth/src/main/res/values-in/strings.xml b/auth/src/main/res/values-in/strings.xml
index 23a477021..4cc582a4e 100755
--- a/auth/src/main/res/values-in/strings.xml
+++ b/auth/src/main/res/values-in/strings.xml
@@ -2,17 +2,15 @@
Memuat…LoginDengan melanjutkan, Anda menyatakan bahwa Anda menyetujui %1$s dan %2$s kami.
- Dengan melanjutkan, Anda menyatakan bahwa Anda menyetujui %1$s kami.
- Dengan melanjutkan, Anda menyatakan bahwa Anda menyetujui %1$s kami.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubLogin dengan GoogleLogin dengan FacebookLogin dengan Twitter
+ Login dengan GitHubLogin dengan emailLogin dengan nomor teleponBerikutnya
@@ -53,22 +51,15 @@
Kirimkan ulang kode dalam 0.%02dVerifikasi nomor telepon AndaMemverifikasi…
- Mengambil sms…Kode salah. Coba lagi.
- OkeNomor telepon ini sudah terlalu sering digunakanAda masalah saat memverifikasi nomor telepon AndaKode ini sudah tidak validLogin dengan nomor telepon
- Selesai
- Terverifikasi!
- Kode terkirim!
- Mengirim ulang…
+ Nomor telepon terverifikasi secara otomatisKirim Ulang KodeVerifikasi Nomor TeleponLanjutkanDengan menge-tap “%1$s\", SMS mungkin akan dikirim. Mungkin dikenakan biaya pesan & data.Dengan menge-tap “%1$s”, Anda menyatakan bahwa Anda menyetujui %2$s dan %3$s kami. SMS mungkin akan dikirim. Mungkin dikenakan biaya pesan & data.
- Dengan menge-tap “%1$s”, Anda menyatakan bahwa Anda menyetujui %2$s kami. SMS mungkin akan dikirim. Mungkin dikenakan biaya pesan & data.
- Dengan menge-tap “%1$s”, Anda menyatakan bahwa Anda menyetujui %2$s kami. SMS mungkin akan dikirim. Mungkin dikenakan biaya pesan & data.
diff --git a/auth/src/main/res/values-it/strings.xml b/auth/src/main/res/values-it/strings.xml
index 7ba464cd7..4f649ef95 100755
--- a/auth/src/main/res/values-it/strings.xml
+++ b/auth/src/main/res/values-it/strings.xml
@@ -2,17 +2,15 @@
Caricamento in corso…AccediSe continui, accetti le nostre %1$s e i nostri %2$s.
- Se continui, accetti i nostri %1$s.
- Se continui, accetti le nostre %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubAccedi con GoogleAccedi con FacebookAccedi con Twitter
+ Accedi con GitHubAccedi con l\'indirizzo emailAccedi con il telefonoAvanti
@@ -53,22 +51,15 @@
Invia di nuovo il codice tra 0:%02dVerifica il numero di telefonoVerifica…
- Recupero SMS in corso…Codice errato. Riprova.
- OKQuesto numero di telefono è stato usato troppe volteSi è verificato un problema durante la verifica del tuo numero di telefonoQuesto codice non è più validoAccedi con il numero di telefono
- Fine
- Verifica eseguita.
- Codice inviato.
- Nuovo invio in corso…
+ Numero di telefono verificato automaticamenteInvia di nuovo il codiceVerifica numero di telefonoContinuaSe tocchi “%1$s”, è possibile che venga inviato un SMS. Potrebbero essere applicate le tariffe per l\'invio dei messaggi e per il traffico dati.Se tocchi “%1$s”, accetti le nostre %2$s e i nostri %3$s. È possibile che venga inviato un SMS. Potrebbero essere applicate le tariffe per l\'invio dei messaggi e per il traffico dati.
- Se tocchi “%1$s”, accetti i nostri %2$s. È possibile che venga inviato un SMS. Potrebbero essere applicate le tariffe per l\'invio dei messaggi e per il traffico dati.
- Se tocchi “%1$s”, accetti le nostre %2$s. È possibile che venga inviato un SMS. Potrebbero essere applicate le tariffe per l\'invio dei messaggi e per il traffico dati.
diff --git a/auth/src/main/res/values-iw/strings.xml b/auth/src/main/res/values-iw/strings.xml
index e37c1d477..8b9aa2e7d 100755
--- a/auth/src/main/res/values-iw/strings.xml
+++ b/auth/src/main/res/values-iw/strings.xml
@@ -2,17 +2,15 @@
טוען…כניסההמשך התהליך יפורש כהסכמתך ל%1$s ול%2$s.
- המשך התהליך יפורש כהסכמתך ל%1$s.
- המשך התהליך יפורש כהסכמתך ל%1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubכניסה באמצעות Googleכניסה באמצעות Facebookכניסה באמצעות Twitter
+ כניסה באמצעות GitHubכניסה באמצעות אימיילכניסה באמצעות הטלפוןהבא
@@ -53,22 +51,15 @@
שולח קוד חדש בעוד %02d:0אמת את מספר הטלפוןמאמת…
- מאחזר SMS…הקוד שגוי. נסה שוב.
- אישורלמספר הטלפון הזה כבר נשלחו יותר מדי קודיםאירעה בעיה באימות של מספר הטלפוןהקוד הזה כבר לא בתוקףכניסה באמצעות מספר טלפון
- סיום
- אומת.
- הקוד נשלח.
- שולח קוד חדש…
+ מספר הטלפון אומת באופן אוטומטישלח קוד חדשאמת את מספר הטלפוןהמשךהקשה על “%1$s” עשויה לגרום לשליחה של הודעת SMS. ייתכן שיחולו תעריפי הודעות והעברת נתונים.הקשה על “%1$s”, תפורש כהסכמתך ל%2$s ול%3$s. ייתכן שתישלח הודעת SMS. ייתכנו חיובים בגין שליחת הודעות ושימוש בנתונים.
- הקשה על “%1$s”, תפורש כהסכמתך ל%2$s. ייתכן שתישלח הודעת SMS. ייתכנו חיובים בגין שליחת הודעות ושימוש בנתונים.
- הקשה על “%1$s”, תפורש כהסכמתך ל%2$s. ייתכן שתישלח הודעת SMS. ייתכנו חיובים בגין שליחת הודעות ושימוש בנתונים.
diff --git a/auth/src/main/res/values-ja/strings.xml b/auth/src/main/res/values-ja/strings.xml
index 336a783fe..b642db63a 100755
--- a/auth/src/main/res/values-ja/strings.xml
+++ b/auth/src/main/res/values-ja/strings.xml
@@ -2,17 +2,15 @@
読み込んでいます…ログイン続行すると、%1$s と %2$s に同意したことになります。
- 続行すると、%1$s に同意したことになります。
- 続行すると、%1$s に同意したことになります。%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubGoogle でログインFacebook でログインTwitter でログイン
+ GitHub でログインメールアドレスでログイン電話番号でログイン次へ
@@ -53,22 +51,15 @@
0:%02d 秒後にコードを再送信します電話番号を確認確認しています…
- SMS を取得しています…コードが間違っています。もう一度お試しください。
- OKこの電話番号は何度も使用されています電話番号の確認中に問題が発生しましたこのコードは無効になりました電話番号でログイン
- 完了
- 確認済み
- コード送信完了
- 再送信しています…
+ 電話番号は自動的に確認されましたコードを再送信電話番号を確認続行[%1$s] をタップすると、SMS が送信されます。データ通信料がかかることがあります。[%1$s] をタップすると、%2$s と %3$s に同意したことになり、SMS が送信されます。データ通信料がかかることがあります。
- [%1$s] をタップすると、%2$s に同意したことになり、SMS が送信されます。データ通信料がかかることがあります。
- [%1$s] をタップすると、%2$s に同意したことになり、SMS が送信されます。データ通信料がかかることがあります。
diff --git a/auth/src/main/res/values-kn/strings.xml b/auth/src/main/res/values-kn/strings.xml
index fd0bf2531..34f906db0 100755
--- a/auth/src/main/res/values-kn/strings.xml
+++ b/auth/src/main/res/values-kn/strings.xml
@@ -2,17 +2,15 @@
ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ…ಸೈನ್ ಇನ್ಮುಂದುವರಿಸುವ ಮೂಲಕ, ನೀವು ನಮ್ಮ %1$s ಮತ್ತು %2$s ಸ್ವೀಕರಿಸುತ್ತೀರಿ ಎಂದು ನೀವು ಸೂಚಿಸುತ್ತಿರುವಿರಿ
- ಮುಂದುವರಿಸುವ ಮೂಲಕ, ನೀವು ನಮ್ಮ %1$s ಅನ್ನು ಸ್ವೀಕರಿಸುತ್ತೀರಿ ಎಂದು ನೀವು ಸೂಚಿಸುತ್ತಿರುವಿರಿ
- ಮುಂದುವರಿಸುವ ಮೂಲಕ, ನೀವು ನಮ್ಮ %1$s ಅನ್ನು ಸ್ವೀಕರಿಸುತ್ತೀರಿ ಎಂದು ನೀವು ಸೂಚಿಸುತ್ತಿರುವಿರಿ%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubGoogle ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿFacebook ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿTwitter ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿ
+ GitHub ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿಇಮೇಲ್ ಜೊತೆ ಸೈನ್ ಇನ್ ಮಾಡಿಫೋನ್ ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿಮುಂದೆ
@@ -53,22 +51,15 @@
ಇಷ್ಟರ ಒಳಗೆ ಕೋಡ್ ಮತ್ತೆ ಕಳುಹಿಸಿ 0:%02dನಿಮ್ಮ ಪೋನ್ ಸಂಖ್ಯೆಯನ್ನು ಪರಿಶೀಲಿಸಿಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ…
- ಎಸ್ಎಂಎಸ್ ಹಿಂಪಡೆಯಲಾಗುತ್ತಿದೆ…ಕೋಡ್ ತಪ್ಪಾಗಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.
- ಸರಿಈ ಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ಈಗಾಗಲೇ ಹಲವಾರು ಬಾರಿ ಬಳಸಲಾಗಿದೆನಿಮ್ಮ ಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ಪರಿಶೀಲಿಸುವಲ್ಲಿ ತೊಂದರೆ ಇದೆಈ ಕೋಡ್ ಇನ್ನು ಮುಂದೆ ಮಾನ್ಯವಾಗಿರುವುದಿಲ್ಲಫೋನ್ ಸಂಖ್ಯೆಯ ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಿ
- ಮುಗಿದಿದೆ
- ಪರಿಶೀಲಿಸಲಾಗಿದೆ
- ಕೋಡ್ ಕಳುಹಿಸಲಾಗಿದೆ!
- ಪುನಃ ಕಳುಹಿಸಲಾಗುತ್ತಿದೆ…
+ ಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಪರಿಶೀಲಿಸಲಾಗಿದೆಕೋಡ್ ಪುನಃ ಕಳುಹಿಸಿಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ಪರಿಶೀಲಿಸಿಮುಂದುವರಿಸಿ“%1$s” ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವ ಮೂಲಕ, ಎಸ್ಎಂಎಸ್ ಅನ್ನು ಕಳುಹಿಸಬಹುದಾಗಿದೆ. ಸಂದೇಶ ಮತ್ತು ಡೇಟಾ ದರಗಳು ಅನ್ವಯಿಸಬಹುದು.“%1$s” ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವ ಮೂಲಕ, ನೀವು ನಮ್ಮ %2$s ಮತ್ತು %3$s ಸ್ವೀಕರಿಸುತ್ತೀರಿ ಎಂದು ನೀವು ಸೂಚಿಸುತ್ತಿರುವಿರಿ. ಎಸ್ಎಂಎಸ್ ಅನ್ನು ಕಳುಹಿಸಬಹುದಾಗಿದೆ. ಸಂದೇಶ ಮತ್ತು ಡೇಟಾ ದರಗಳು ಅನ್ವಯಿಸಬಹುದು.
- “%1$s” ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವ ಮೂಲಕ, ನೀವು ನಮ್ಮ %2$s ಅನ್ನು ಸ್ವೀಕರಿಸುತ್ತೀರಿ ಎಂದು ನೀವು ಸೂಚಿಸುತ್ತಿರುವಿರಿ. ಎಸ್ಎಂಎಸ್ ಅನ್ನು ಕಳುಹಿಸಬಹುದಾಗಿದೆ. ಸಂದೇಶ ಮತ್ತು ಡೇಟಾ ದರಗಳು ಅನ್ವಯಿಸಬಹುದು.
- “%1$s” ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವ ಮೂಲಕ, ನೀವು ನಮ್ಮ %2$s ಅನ್ನು ಸ್ವೀಕರಿಸುತ್ತೀರಿ ಎಂದು ನೀವು ಸೂಚಿಸುತ್ತಿರುವಿರಿ. ಎಸ್ಎಂಎಸ್ ಅನ್ನು ಕಳುಹಿಸಬಹುದಾಗಿದೆ. ಸಂದೇಶ ಮತ್ತು ಡೇಟಾ ದರಗಳು ಅನ್ವಯಿಸಬಹುದು.
diff --git a/auth/src/main/res/values-ko/strings.xml b/auth/src/main/res/values-ko/strings.xml
index 30066a64c..7527fcc3e 100755
--- a/auth/src/main/res/values-ko/strings.xml
+++ b/auth/src/main/res/values-ko/strings.xml
@@ -2,17 +2,15 @@
로드 중…로그인계속 진행하면 %1$s 및 %2$s에 동의하는 것으로 간주됩니다.
- 계속 진행하면 %1$s에 동의하는 것으로 간주됩니다.
- 계속 진행하면 %1$s에 동의하는 것으로 간주됩니다.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubGoogle 계정으로 로그인Facebook으로 로그인Twitter로 로그인
+ GitHub로 로그인이메일로 로그인전화로 로그인다음
@@ -53,22 +51,15 @@
0:%02d 후에 코드 재전송전화번호 인증인증 중…
- SMS 검색 중…코드가 잘못되었습니다. 다시 시도하세요.
- 확인이 전화번호로 전송 시도를 너무 많이 했습니다.전화번호를 인증하는 중에 문제가 발생했습니다.더 이상 유효하지 않은 코드입니다.전화번호로 로그인
- 완료
- 인증되었습니다.
- 코드가 전송되었습니다.
- 다시 전송하는 중…
+ 전화번호가 자동으로 확인되었습니다.코드 재전송전화번호 인증계속“%1$s” 버튼을 탭하면 SMS가 발송될 수 있으며, 메시지 및 데이터 요금이 부과될 수 있습니다.‘%1$s’ 버튼을 탭하면 %2$s 및 %3$s에 동의하는 것으로 간주됩니다. SMS가 발송될 수 있으며, 메시지 및 데이터 요금이 부과될 수 있습니다.
- ‘%1$s’ 버튼을 탭하면 %2$s에 동의하는 것으로 간주됩니다. SMS가 발송될 수 있으며, 메시지 및 데이터 요금이 부과될 수 있습니다.
- ‘%1$s’ 버튼을 탭하면 %2$s에 동의하는 것으로 간주됩니다. SMS가 발송될 수 있으며, 메시지 및 데이터 요금이 부과될 수 있습니다.
diff --git a/auth/src/main/res/values-ln/strings.xml b/auth/src/main/res/values-ln/strings.xml
index c89153c43..747acacae 100755
--- a/auth/src/main/res/values-ln/strings.xml
+++ b/auth/src/main/res/values-ln/strings.xml
@@ -2,17 +2,15 @@
Chargement…Se connecterEn continuant, vous acceptez les %1$s et les %2$s.
- En continuant, vous acceptez les %1$s.
- En continuant, vous acceptez les %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubSe connecter avec GoogleSe connecter avec FacebookSe connecter avec Twitter
+ Se connecter avec GitHubSe connecter avec une adresse e-mailSe connecter avec un téléphoneSuivant
@@ -53,22 +51,15 @@
Renvoyer le code dans 0:%02dValider votre numéro de téléphoneValidation…
- Récupération du SMS…Code erroné. Veuillez réessayer.
- OKCe numéro de téléphone a été utilisé un trop grand nombre de foisUn problème est survenu lors de la validation de votre numéro de téléphoneCe code n\'est plus valideConnectez-vous avec votre numéro de téléphone
- OK
- Le code a bien été validé.
- Le code a bien été envoyé.
- Nouvel envoi du code…
+ Numéro de téléphone validé automatiquementRenvoyer le codeValider le numéro de téléphoneContinuerEn appuyant sur “%1$s”, vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.En appuyant sur “%1$s”, vous acceptez les %2$s et les %3$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
- En appuyant sur “%1$s”, vous acceptez les %2$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
- En appuyant sur “%1$s”, vous acceptez les %2$s. Vous déclencherez peut-être l\'envoi d\'un SMS. Des frais de messages et de données peuvent être facturés.
diff --git a/auth/src/main/res/values-lt/strings.xml b/auth/src/main/res/values-lt/strings.xml
index 86618010e..8f48c0f64 100755
--- a/auth/src/main/res/values-lt/strings.xml
+++ b/auth/src/main/res/values-lt/strings.xml
@@ -2,17 +2,15 @@
Įkeliama…PrisijungtiTęsdami nurodote, kad sutinkate su %1$s ir %2$s.
- Tęsdami nurodote, kad sutinkate su %1$s.
- Tęsdami nurodote, kad sutinkate su %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubPrisijungti per „Google“Prisijungti per „Facebook“Prisijungti per „Twitter“
+ Prisijungti per „GitHub“Prisijungti nurodant el. pašto adresąPrisijungti nurodant telefono numerįKitas
@@ -53,22 +51,15 @@
Siųsti kodą iš naujo po 0:%02dPatvirtinti telefono numerįPatvirtinama…
- Gaunama SMS…Klaidingas kodas. Bandykite dar kartą.
- GeraiŠis telefono numeris panaudotas per daug kartųPatvirtinant telefono numerį kilo problemaŠis kodas nebegaliojaPrisijungti nurodant telefono numerį
- Atlikta
- Patvirtinta.
- Kodas išsiųstas.
- Siunčiama iš naujo…
+ Telefono numeris patvirtintas automatiškaiSiųsti kodą iš naujoPatvirtinti telefono numerįTęstiPalietus „%1$s“ gali būti išsiųstas SMS pranešimas. Gali būti taikomi pranešimų ir duomenų įkainiai.Paliesdami „%1$s“ nurodote, kad sutinkate su %2$s ir %3$s. Gali būti išsiųstas SMS pranešimas, taip pat – taikomi pranešimų ir duomenų įkainiai.
- Paliesdami „%1$s“ nurodote, kad sutinkate su %2$s. Gali būti išsiųstas SMS pranešimas, taip pat – taikomi pranešimų ir duomenų įkainiai.
- Paliesdami „%1$s“ nurodote, kad sutinkate su %2$s. Gali būti išsiųstas SMS pranešimas, taip pat – taikomi pranešimų ir duomenų įkainiai.
diff --git a/auth/src/main/res/values-lv/strings.xml b/auth/src/main/res/values-lv/strings.xml
index a81ef9345..0c658d719 100755
--- a/auth/src/main/res/values-lv/strings.xml
+++ b/auth/src/main/res/values-lv/strings.xml
@@ -2,17 +2,15 @@
Notiek ielāde…PierakstītiesTurpinot jūs norādāt, ka piekrītat šādiem dokumentiem: %1$s un %2$s.
- Turpinot jūs norādāt, ka piekrītat šādam dokumentam: %1$s.
- Turpinot jūs norādāt, ka piekrītat šādam dokumentam: %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubPierakstīties ar GooglePierakstīties ar FacebookPierakstīties ar Twitter
+ Pierakstīties, izmantojot GitHubPierakstīties ar e-pasta adresiPierakstīties ar tālruniTālāk
@@ -53,22 +51,15 @@
Vēlreiz nosūtīt kodu pēc 0:%02dVerificēt tālruņa numuruNotiek verifikācija…
- Notiek īsziņas izgūšana…Nepareizs kods. Mēģiniet vēlreiz.
- LabiŠis tālruņa numurs ir izmantots pārāk daudz reižuVerificējot jūsu tālruņa numuru, radās problēmaŠis kods vairs nav derīgsPierakstieties ar tālruņa numuru
- Gatavs
- Verificēts.
- Kods ir nosūtīts.
- Notiek atkārtota sūtīšana…
+ Tālruņa numurs tika automātiski verificētsVēlreiz nosūtīt koduVerificēt tālruņa numuruTurpinātPieskaroties pogai %1$s, var tikt nosūtīta īsziņa. Var tikt piemērota maksa par ziņojumiem un datu pārsūtīšanu.Pieskaroties pogai “%1$s”, jūs norādāt, ka piekrītat šādiem dokumentiem: %2$s un %3$s. Var tikt nosūtīta īsziņa. Var tikt piemērota maksa par ziņojumiem un datu pārsūtīšanu.
- Pieskaroties pogai “%1$s”, jūs norādāt, ka piekrītat šādam dokumentam: %2$s. Var tikt nosūtīta īsziņa. Var tikt piemērota maksa par ziņojumiem un datu pārsūtīšanu.
- Pieskaroties pogai “%1$s”, jūs norādāt, ka piekrītat šādam dokumentam: %2$s. Var tikt nosūtīta īsziņa. Var tikt piemērota maksa par ziņojumiem un datu pārsūtīšanu.
diff --git a/auth/src/main/res/values-mo/strings.xml b/auth/src/main/res/values-mo/strings.xml
index b3ba87923..6e8374a04 100755
--- a/auth/src/main/res/values-mo/strings.xml
+++ b/auth/src/main/res/values-mo/strings.xml
@@ -2,17 +2,15 @@
Se încarcă…Conectați-văDacă alegeți să continuați, sunteți de acord cu %1$s și cu %2$s.
- Dacă alegeți să continuați, sunteți de acord cu %1$s.
- Dacă alegeți să continuați, sunteți de acord cu %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubConectați-vă cu GoogleConectați-vă cu FacebookConectați-vă cu Twitter
+ Conectați-vă cu GitHubConectați-vă cu adresa de e-mailConectați-vă cu numărul de telefonÎnainte
@@ -53,22 +51,15 @@
Retrimiteți codul în 00:%02dConfirmați numărul de telefonSe verifică…
- Se obține SMS-ul…Cod greșit. Încercați din nou.
- OKAcest număr de telefon a fost folosit de prea multe oriA apărut o problemă la confirmarea numărului de telefonCodul nu mai este validConectați-vă cu numărul de telefon
- Gata
- Confirmat!
- Codul a fost trimis!
- Se retrimite…
+ Numărul de telefon este verificat automatRetrimiteți codulConfirmați numărul de telefonContinuațiDacă atingeți „%1$s”, poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.Dacă atingeți „%1$s”, sunteți de acord cu %2$s și cu %3$s. Poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.
- Dacă atingeți „%1$s”, sunteți de acord cu %2$s. Poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.
- Dacă atingeți „%1$s”, sunteți de acord cu %2$s. Poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.
diff --git a/auth/src/main/res/values-mr/strings.xml b/auth/src/main/res/values-mr/strings.xml
index 100e9729a..90123720c 100755
--- a/auth/src/main/res/values-mr/strings.xml
+++ b/auth/src/main/res/values-mr/strings.xml
@@ -2,17 +2,15 @@
लोड करत आहे…साइन इन करापुढे सुरू ठेवून, तुम्ही सूचित करता की तुम्ही आमचे %1$s आणि %2$s स्वीकारता.
- पुढे सुरू ठेवून, तुम्ही सूचित करता की तुम्ही आमचे %1$s स्वीकारता.
- पुढे सुरू ठेवून, तुम्ही सूचित करता की तुम्ही आमचे %1$s स्वीकारता.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GithubGoogleने साइन इन कराFacebookने साइन इन कराTwitterने साइन इन करा
+ GitHub सह साइन इन कराईमेलने साइन इन कराफोनने साइन इन करापुढील
@@ -53,22 +51,15 @@
कोड 0:%02dमध्ये पुन्हा पाठवातुमच्या फोन नंबरची पडताळणी करापडताळणी करत आहे…
- sms पुन्हा मिळवत आहे…कोड चुकीचा आहे. पुन्हा प्रयत्न करा.
- ठीक आहेहा फोन नंबर बर्याच वेळा वापरण्यात आला आहेतुमच्या फोन नंबरची पडताळणी करण्यात एक समस्या होतीहा कोड यापुढे वैध नसेलफोन नंबरने साइन इन करा
- पूर्ण झाले
- पडताळणी झाली!
- कोड पाठवला!
- पुन्हा पाठवत आहे…
+ फोन नंबरची अपोआप पडताळणी केली आहेकोड पुन्हा पाठवाफोन नंबरची पडताळणी करासुरू ठेवा“%1$s“ वर टॅप केल्याने, एक एसएमएस पाठवला जाऊ शकतो. मेसेज आणि डेटा शुल्क लागू होऊ शकते.“%1$s” वर टॅप करून, तुम्ही सूचित करता की तुम्ही आमचे %2$s आणि %3$s स्वीकारता. एसएमएस पाठवला जाऊ शकतो. मेसेज आणि डेटा दर लागू केले जाऊ शकते.
- “%1$s” वर टॅप करून, तुम्ही सूचित करता की तुम्ही आमचे %2$s स्वीकारता. एसएमएस पाठवला जाऊ शकतो. मेसेज आणि डेटा दर लागू केले जाऊ शकते.
- “%1$s” वर टॅप करून, तुम्ही सूचित करता की तुम्ही आमचे %2$s स्वीकारता. एसएमएस पाठवला जाऊ शकतो. मेसेज आणि डेटा दर लागू केले जाऊ शकते.
diff --git a/auth/src/main/res/values-ms/strings.xml b/auth/src/main/res/values-ms/strings.xml
index d48e70852..da2e1332e 100755
--- a/auth/src/main/res/values-ms/strings.xml
+++ b/auth/src/main/res/values-ms/strings.xml
@@ -2,17 +2,15 @@
Memuatkan…Log masukDengan meneruskan, anda menyatakan bahawa anda menerima %1$s dan %2$s kami.
- Dengan meneruskan, anda menyatakan bahawa anda menerima %1$s kami.
- Dengan meneruskan, anda menyatakan bahawa anda menerima %1$s kami.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubLog masuk dengan GoogleLog masuk dengan FacebookLog masuk dengan Twitter
+ Log masuk dengan GitHubLog masuk dengan e-melLog masuk dengan telefonSeterusnya
@@ -53,22 +51,15 @@
Hantar semula kod dalam 0:%02dSahkan nombor telefon andaMengesahkan…
- Mendapatkan SMS…Kod salah. Cuba lagi.
- OKNombor telefon ini terlalu kerap digunakanTerdapat masalah sewaktu mengesahkan nombor telefon andaKod ini tidak sah lagiLog masuk dengan nombor telefon
- Selesai
- Disahkan!
- Kod dihantar!
- Menghantar semula…
+ Nombor telefon disahkan secara automatikHantar Semula KodSahkan Nombor TelefonTeruskanDengan mengetik “%1$s”, SMS akan dihantar. Tertakluk pada kadar mesej & data.Dengan mengetik “%1$s”, anda menyatakan bahawa anda menerima %2$s dan %3$s kami. SMS akan dihantar. Tertakluk pada kadar mesej & data.
- Dengan mengetik “%1$s”, anda menyatakan bahawa anda menerima %2$s kami. SMS akan dihantar. Tertakluk pada kadar mesej & data.
- Dengan mengetik “%1$s”, anda menyatakan bahawa anda menerima %2$s kami. SMS akan dihantar. Tertakluk pada kadar mesej & data.
diff --git a/auth/src/main/res/values-nb/strings.xml b/auth/src/main/res/values-nb/strings.xml
index a9facd985..6dd286adc 100755
--- a/auth/src/main/res/values-nb/strings.xml
+++ b/auth/src/main/res/values-nb/strings.xml
@@ -2,17 +2,15 @@
Laster inn…Logg påVed å fortsette godtar du %1$s og %2$s våre.
- Ved å fortsette godtar du %1$s.
- Ved å fortsette godtar du %1$s våre.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubLogg på med GoogleLogg på med FacebookLogg på med Twitter
+ Logg på med GitHubLogg på med e-postadresseLogg på med telefonnummeret dittNeste
@@ -53,22 +51,15 @@
Send koden på nytt om 0:%02dBekreft telefonnummeret dittBekrefter…
- Henter SMS…Feil kode. Prøv på nytt.
- OKDette telefonnummeret er brukt for mange gangerKunne ikke bekrefte telefonnummeret dittDenne koden er ikke lenger gyldigLogg på med telefonnummer
- Ferdig
- Bekreftet.
- Koden er sendt.
- Sender på nytt…
+ Telefonnummeret ble bekreftet automatiskSend koden på nyttBekreft telefonnummeretFortsettNår du trykker på «%1$s», kan det bli sendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.Ved å trykke på «%1$s» godtar du %2$s og %3$s våre. Du kan bli tilsendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.
- Ved å trykke på «%1$s» godtar du %2$s. Du kan bli tilsendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.
- Hvis du trykker på «%1$s», godtar du %2$s våre. Du kan bli tilsendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.
diff --git a/auth/src/main/res/values-nl/strings.xml b/auth/src/main/res/values-nl/strings.xml
index fc1c34748..cd399d306 100755
--- a/auth/src/main/res/values-nl/strings.xml
+++ b/auth/src/main/res/values-nl/strings.xml
@@ -2,17 +2,15 @@
Laden…InloggenAls u doorgaat, geeft u aan dat u onze %1$s en ons %2$s accepteert.
- Als u doorgaat, geeft u aan dat u onze %1$s accepteert.
- Als u doorgaat, geeft u aan dat u ons %1$s accepteert.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubInloggen met GoogleInloggen met FacebookInloggen met Twitter
+ Inloggen met GitHubInloggen met e-mailadresInloggen met telefoonVolgende
@@ -53,22 +51,15 @@
Code opnieuw verzenden over 0:%02dUw telefoonnummer verifiërenVerifiëren…
- Sms ophalen…Onjuiste code. Probeer het opnieuw.
- OKDit telefoonnummer is te vaak gebruiktEr is een probleem met de verificatie van uw telefoonnummerDeze code is niet meer geldigInloggen met telefoonnummer
- Gereed
- Geverifieerd
- Code verzonden
- Opnieuw verzenden…
+ Telefoonnummer is automatisch geverifieerdCode opnieuw verzendenTelefoonnummer verifiërenDoorgaanAls u op “%1$s” tikt, ontvangt u mogelijk een sms. Er kunnen sms- en datakosten in rekening worden gebracht.Als u op “%1$s” tikt, geeft u aan dat u onze %2$s en ons %3$s accepteert. Mogelijk ontvangt u een sms. Er kunnen sms- en datakosten in rekening worden gebracht.
- Als u op “%1$s” tikt, geeft u aan dat u onze %2$s accepteert. Mogelijk ontvangt u een sms. Er kunnen sms- en datakosten in rekening worden gebracht.
- Als u op “%1$s” tikt, geeft u aan dat u ons %2$s accepteert. Mogelijk ontvangt u een sms. Er kunnen sms- en datakosten in rekening worden gebracht.
diff --git a/auth/src/main/res/values-no/strings.xml b/auth/src/main/res/values-no/strings.xml
index a9facd985..6dd286adc 100755
--- a/auth/src/main/res/values-no/strings.xml
+++ b/auth/src/main/res/values-no/strings.xml
@@ -2,17 +2,15 @@
Laster inn…Logg påVed å fortsette godtar du %1$s og %2$s våre.
- Ved å fortsette godtar du %1$s.
- Ved å fortsette godtar du %1$s våre.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubLogg på med GoogleLogg på med FacebookLogg på med Twitter
+ Logg på med GitHubLogg på med e-postadresseLogg på med telefonnummeret dittNeste
@@ -53,22 +51,15 @@
Send koden på nytt om 0:%02dBekreft telefonnummeret dittBekrefter…
- Henter SMS…Feil kode. Prøv på nytt.
- OKDette telefonnummeret er brukt for mange gangerKunne ikke bekrefte telefonnummeret dittDenne koden er ikke lenger gyldigLogg på med telefonnummer
- Ferdig
- Bekreftet.
- Koden er sendt.
- Sender på nytt…
+ Telefonnummeret ble bekreftet automatiskSend koden på nyttBekreft telefonnummeretFortsettNår du trykker på «%1$s», kan det bli sendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.Ved å trykke på «%1$s» godtar du %2$s og %3$s våre. Du kan bli tilsendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.
- Ved å trykke på «%1$s» godtar du %2$s. Du kan bli tilsendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.
- Hvis du trykker på «%1$s», godtar du %2$s våre. Du kan bli tilsendt en SMS. Kostnader for meldinger og datatrafikk kan påløpe.
diff --git a/auth/src/main/res/values-pl/strings.xml b/auth/src/main/res/values-pl/strings.xml
index aa901665b..42b242242 100755
--- a/auth/src/main/res/values-pl/strings.xml
+++ b/auth/src/main/res/values-pl/strings.xml
@@ -2,17 +2,15 @@
Wczytuję…Zaloguj sięKontynuując, potwierdzasz, że akceptujesz te dokumenty: %1$s i %2$s.
- Kontynuując, potwierdzasz, że akceptujesz ten dokument: %1$s.
- Kontynuując, potwierdzasz, że akceptujesz ten dokument: %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubZaloguj się przez GoogleZaloguj się przez FacebookaZaloguj się przez Twittera
+ Zaloguj się przez GitHubaZaloguj się za pomocą e-mailaZaloguj się z użyciem numeru telefonuDalej
@@ -53,22 +51,15 @@
Kod można ponownie wysłać za 0:%02dZweryfikuj swój numer telefonuWeryfikuję…
- Odbieranie SMS-a…Nieprawidłowy kod. Spróbuj jeszcze raz.
- OKTen numer telefonu został użyty zbyt wiele razy.Podczas weryfikacji Twojego numeru telefonu wystąpił problem.Ten kod stracił ważność.Zaloguj się z użyciem numeru telefonu
- Gotowe
- Zweryfikowano.
- Kod wysłany.
- Wysyłam ponownie…
+ Numer telefonu został automatycznie zweryfikowanyWyślij kod ponownieZweryfikuj numer telefonuDalejGdy klikniesz „%1$s”, może zostać wysłany SMS. Może to skutkować pobraniem opłaty za przesłanie wiadomości i danych.Klikając „%1$s”, potwierdzasz, że akceptujesz te dokumenty: %2$s i %3$s. Może zostać wysłany SMS. Może to skutkować pobraniem opłat za przesłanie wiadomości i danych.
- Klikając „%1$s”, potwierdzasz, że akceptujesz ten dokument: %2$s. Może zostać wysłany SMS. Może to skutkować pobraniem opłat za przesłanie wiadomości i danych.
- Klikając „%1$s”, potwierdzasz, że akceptujesz ten dokument: %2$s. Może zostać wysłany SMS. Może to skutkować pobraniem opłat za przesłanie wiadomości i danych.
diff --git a/auth/src/main/res/values-pt-rBR/strings.xml b/auth/src/main/res/values-pt-rBR/strings.xml
index 95ea36e2f..bdc357c16 100755
--- a/auth/src/main/res/values-pt-rBR/strings.xml
+++ b/auth/src/main/res/values-pt-rBR/strings.xml
@@ -2,17 +2,15 @@
Carregando…Fazer loginAo continuar, você concorda com nossos %1$s e a %2$s.
- Ao continuar, você concorda com nossos %1$s.
- Ao continuar, você concorda com nossa %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubFazer login com o GoogleFazer login com o FacebookFazer login com o Twitter
+ Fazer login com o GitHubFazer login com o e-mailFazer login com o telefonePróxima
@@ -53,22 +51,15 @@
Reenviar código em 0:%02dConfirmar seu número de telefoneVerificando…
- Recuperando SMS…Código incorreto. Tente novamente.
- OkEste número de telefone já foi usado muitas vezesOcorreu um problema na verificação do seu número de telefoneEste código não é mais válidoFazer login com o número de telefone
- Concluído
- Verificado.
- Código enviado.
- Reenviando…
+ O número de telefone foi verificado automaticamenteReenviar códigoConfirmar número de telefoneContinuarSe você tocar em “%1$s”, um SMS poderá ser enviado e tarifas de mensagens e de dados serão cobradas.Ao tocar em “%1$s”, você concorda com nossos %2$s e a %3$s. Um SMS poderá ser enviado e tarifas de mensagens e de dados poderão ser cobradas.
- Ao tocar em “%1$s”, você concorda com nossos %2$s. Um SMS poderá ser enviado e tarifas de mensagens e de dados poderão ser cobradas.
- Ao tocar em “%1$s”, você concorda com nossa %2$s. Um SMS poderá ser enviado e tarifas de mensagens e de dados poderão ser cobradas.
diff --git a/auth/src/main/res/values-pt-rPT/strings.xml b/auth/src/main/res/values-pt-rPT/strings.xml
index 2f8168eea..25ac63248 100755
--- a/auth/src/main/res/values-pt-rPT/strings.xml
+++ b/auth/src/main/res/values-pt-rPT/strings.xml
@@ -2,17 +2,15 @@
A carregar…Iniciar sessãoAo continuar, indica que aceita os %1$s e a %2$s.
- Ao continuar, indica que aceita os nossos %1$s.
- Ao continuar, indica que aceita a nossa %1$s.%1$s %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubIniciar sessão com o GoogleIniciar sessão com o FacebookIniciar sessão com o Twitter
+ Iniciar sessão com o GitHubIniciar sessão com o emailIniciar sessão com o telemóvelSeguinte
@@ -53,22 +51,15 @@
Reenviar código em 0:%02dValidar o número de telefoneA validar…
- A obter SMS…Código errado. Tente novamente.
- OKEste número de telefone foi utilizado demasiadas vezesOcorreu um problema ao validar o número de telefoneEste código já não é válidoIniciar sessão com o número de telefone
- Concluído
- Validado!
- Código enviado!
- A reenviar…
+ Número de telefone verificado automaticamenteReenviar códigoValidar número de telefoneContinuarAo tocar em “%1$s”, pode gerar o envio de uma SMS. Podem aplicar-se tarifas de mensagens e dados.Ao tocar em “%1$s”, indica que aceita os %2$s e a %3$s. Pode gerar o envio de uma SMS. Podem aplicar-se tarifas de dados e de mensagens.
- Ao tocar em “%1$s”, indica que aceita os nossos %2$s. Pode gerar o envio de uma SMS. Podem aplicar-se tarifas de mensagens e dados.
- Ao tocar em “%1$s”, indica que aceita a nossa %2$s. Pode gerar o envio de uma SMS. Podem aplicar-se tarifas de mensagens e dados.
diff --git a/auth/src/main/res/values-pt/strings.xml b/auth/src/main/res/values-pt/strings.xml
index 95ea36e2f..bdc357c16 100755
--- a/auth/src/main/res/values-pt/strings.xml
+++ b/auth/src/main/res/values-pt/strings.xml
@@ -2,17 +2,15 @@
Carregando…Fazer loginAo continuar, você concorda com nossos %1$s e a %2$s.
- Ao continuar, você concorda com nossos %1$s.
- Ao continuar, você concorda com nossa %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubFazer login com o GoogleFazer login com o FacebookFazer login com o Twitter
+ Fazer login com o GitHubFazer login com o e-mailFazer login com o telefonePróxima
@@ -53,22 +51,15 @@
Reenviar código em 0:%02dConfirmar seu número de telefoneVerificando…
- Recuperando SMS…Código incorreto. Tente novamente.
- OkEste número de telefone já foi usado muitas vezesOcorreu um problema na verificação do seu número de telefoneEste código não é mais válidoFazer login com o número de telefone
- Concluído
- Verificado.
- Código enviado.
- Reenviando…
+ O número de telefone foi verificado automaticamenteReenviar códigoConfirmar número de telefoneContinuarSe você tocar em “%1$s”, um SMS poderá ser enviado e tarifas de mensagens e de dados serão cobradas.Ao tocar em “%1$s”, você concorda com nossos %2$s e a %3$s. Um SMS poderá ser enviado e tarifas de mensagens e de dados poderão ser cobradas.
- Ao tocar em “%1$s”, você concorda com nossos %2$s. Um SMS poderá ser enviado e tarifas de mensagens e de dados poderão ser cobradas.
- Ao tocar em “%1$s”, você concorda com nossa %2$s. Um SMS poderá ser enviado e tarifas de mensagens e de dados poderão ser cobradas.
diff --git a/auth/src/main/res/values-ro/strings.xml b/auth/src/main/res/values-ro/strings.xml
index b3ba87923..6e8374a04 100755
--- a/auth/src/main/res/values-ro/strings.xml
+++ b/auth/src/main/res/values-ro/strings.xml
@@ -2,17 +2,15 @@
Se încarcă…Conectați-văDacă alegeți să continuați, sunteți de acord cu %1$s și cu %2$s.
- Dacă alegeți să continuați, sunteți de acord cu %1$s.
- Dacă alegeți să continuați, sunteți de acord cu %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubConectați-vă cu GoogleConectați-vă cu FacebookConectați-vă cu Twitter
+ Conectați-vă cu GitHubConectați-vă cu adresa de e-mailConectați-vă cu numărul de telefonÎnainte
@@ -53,22 +51,15 @@
Retrimiteți codul în 00:%02dConfirmați numărul de telefonSe verifică…
- Se obține SMS-ul…Cod greșit. Încercați din nou.
- OKAcest număr de telefon a fost folosit de prea multe oriA apărut o problemă la confirmarea numărului de telefonCodul nu mai este validConectați-vă cu numărul de telefon
- Gata
- Confirmat!
- Codul a fost trimis!
- Se retrimite…
+ Numărul de telefon este verificat automatRetrimiteți codulConfirmați numărul de telefonContinuațiDacă atingeți „%1$s”, poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.Dacă atingeți „%1$s”, sunteți de acord cu %2$s și cu %3$s. Poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.
- Dacă atingeți „%1$s”, sunteți de acord cu %2$s. Poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.
- Dacă atingeți „%1$s”, sunteți de acord cu %2$s. Poate fi trimis un SMS. Se pot aplica tarife pentru mesaje și date.
diff --git a/auth/src/main/res/values-ru/strings.xml b/auth/src/main/res/values-ru/strings.xml
index 263494a65..b814d2500 100755
--- a/auth/src/main/res/values-ru/strings.xml
+++ b/auth/src/main/res/values-ru/strings.xml
@@ -2,17 +2,15 @@
Загрузка…ВойтиПродолжая, вы принимаете %1$s и %2$s.
- Продолжая, вы принимаете %1$s.
- Продолжая, вы принимаете %1$s.
- %1$s %2$s
- %1$s
- %1$s
+ %1$s \u00A0 \u00A0 %2$sGoogleFacebookTwitter
+ GitHubВойти через аккаунт GoogleВойти через аккаунт FacebookВойти через аккаунт Twitter
+ Войти через аккаунт GitHubВойти по адресу электронной почтыВойти по номеру телефонаДалее
@@ -53,22 +51,15 @@
Отправить код ещё раз можно будет через 0:%02d.Подтвердить номер телефонаПроверка…
- Получение SMS…Неверный код. Повторите попытку.
- ОКЭтот номер телефона использовался слишком много раз.Не удалось подтвердить номер телефона.Этот код уже неактивен.Войти по номеру телефона
- Готово
- Проверка выполнена.
- Код отправлен
- Повторная отправка…
+ Номер телефона был подтвержден автоматическиОтправить код ещё разПодтвердить номер телефонаПродолжитьНажимая кнопку “%1$s”, вы соглашаетесь получить SMS. За его отправку и обмен данными может взиматься плата.Нажимая кнопку “%1$s”, вы принимаете %2$s и %3$s, а также соглашаетесь получить SMS. За его отправку и обмен данными может взиматься плата.
- Нажимая кнопку “%1$s”, вы принимаете %2$s и соглашаетесь получить SMS. За его отправку и обмен данными может взиматься плата.
- Нажимая кнопку “%1$s”, вы принимаете %2$s и соглашаетесь получить SMS. За его отправку и обмен данными может взиматься плата.
diff --git a/auth/src/main/res/values-sk/strings.xml b/auth/src/main/res/values-sk/strings.xml
index eafd175ce..51426de9f 100755
--- a/auth/src/main/res/values-sk/strings.xml
+++ b/auth/src/main/res/values-sk/strings.xml
@@ -2,17 +2,15 @@
Načítava sa…Prihlásiť saPokračovaním vyjadrujete súhlas s dokumentmi %1$s a %2$s.
- Pokračovaním vyjadrujete súhlas s dokumentom %1$s.
- Pokračovaním vyjadrujete súhlas s dokumentom %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubPrihlásiť sa cez GooglePrihlásiť sa cez FacebookPrihlásiť sa cez Twitter
+ Prihlásiť sa cez GitHubPrihlásiť sa e-mailomPrihlásiť sa telefónomĎalej
@@ -53,22 +51,15 @@
Kód sa znova odošle o 0:%02dOveriť telefónne čísloOveruje sa…
- Načítava sa SMS…Nesprávny kód. Skúste to znova.
- OKToto telefónne číslo bolo použité príliš veľakrátVyskytol sa problém s overením vášho telefónneho číslaTento kód už nie je platnýPrihláste sa telefónnym číslom
- Hotovo
- Overené.
- Kód bol odoslaný.
- Znova sa odosiela…
+ Telefónne číslo bolo automaticky overenéZnova odoslať kódOveriť telefónne čísloPokračovaťKlepnutím na tlačidlo %1$s možno odoslať SMS. Môžu sa účtovať poplatky za správy a dáta.Klepnutím na tlačidlo %1$s vyjadrujete súhlas s dokumentmi %2$s a %3$s. Môže byť odoslaná SMS a môžu sa účtovať poplatky za správy a dáta.
- Klepnutím na tlačidlo %1$s vyjadrujete súhlas s dokumentom %2$s. Môže byť odoslaná SMS a môžu sa účtovať poplatky za správy a dáta.
- Klepnutím na tlačidlo %1$s vyjadrujete súhlas s dokumentom %2$s. Môže byť odoslaná SMS a môžu sa účtovať poplatky za správy a dáta.
diff --git a/auth/src/main/res/values-sl/strings.xml b/auth/src/main/res/values-sl/strings.xml
index b0911f755..b1bfeef2b 100755
--- a/auth/src/main/res/values-sl/strings.xml
+++ b/auth/src/main/res/values-sl/strings.xml
@@ -2,17 +2,15 @@
Nalaganje…PrijavaZ nadaljevanjem potrjujete, da se strinjate z dokumentoma %1$s in %2$s.
- Z nadaljevanjem potrjujete, da se strinjate z dokumentom %1$s.
- Z nadaljevanjem potrjujete, da se strinjate z dokumentom %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubPrijava z Google RačunomPrijava z računom za FacebookPrijava z računom za Twitter
+ Prijava z računom za GitHubPrijava z e-poštnim naslovomPrijava s telefonomNaprej
@@ -53,22 +51,15 @@
Ponovno pošlji kodo čez 0:%02dPreverjanje telefonske številkePreverjanje…
- Pridobivanje sporočila SMS…Napačna koda. Poskusite znova.
- V reduTelefonska številka je bila uporabljena prevečkratPri preverjanju telefonske številke je prišlo do težaveKoda ni več veljavnaPrijava s telefonsko številko
- Končano
- Preverjeno.
- Koda je poslana.
- Ponovno pošiljanje…
+ Telefonska številka je bila samodejno preverjenaPonovno pošlji kodoPreverjanje telefonske številkeNaprejČe se dotaknete možnosti »%1$s«, bo morda poslano sporočilo SMS. Pošiljanje sporočila in prenos podatkov boste morda morali plačati.Če se dotaknete možnosti »%1$s«, potrjujete, da se strinjate z dokumentoma %2$s in %3$s. Morda bo poslano sporočilo SMS. Pošiljanje sporočila in prenos podatkov boste morda morali plačati.
- Če se dotaknete možnosti »%1$s«, potrjujete, da se strinjate z dokumentom %2$s. Morda bo poslano sporočilo SMS. Pošiljanje sporočila in prenos podatkov boste morda morali plačati.
- Če se dotaknete možnosti »%1$s«, potrjujete, da se strinjate z dokumentom %2$s. Morda bo poslano sporočilo SMS. Pošiljanje sporočila in prenos podatkov boste morda morali plačati.
diff --git a/auth/src/main/res/values-sr/strings.xml b/auth/src/main/res/values-sr/strings.xml
index ec8d21891..e62189d57 100755
--- a/auth/src/main/res/values-sr/strings.xml
+++ b/auth/src/main/res/values-sr/strings.xml
@@ -2,17 +2,15 @@
Учитава се…Пријави меАко наставите, потврђујете да прихватате документе %1$s и %2$s.
- Ако наставите, потврђујете да прихватате документ %1$s.
- Ако наставите, потврђујете да прихватате документ %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubПријави ме помоћу Google-аПријави ме помоћу Facebook-аПријави ме помоћу Twitter-а
+ Пријавите се помоћу GitHub-аПријави ме помоћу имејлаПријави ме помоћу телефонаДаље
@@ -53,22 +51,15 @@
Кôд ће бити поново послат за 0:%02dВерификујте број телефонаВерификује се…
- SMS се преузима…Кôд није тачан. Пробајте поново.
- ПотврдиОвај број телефона је употребљен превише путаДошло је до проблема при верификацији броја телефонаТај кôд више не важиПријавите се помоћу броја телефона
- Готово
- Потврђено је!
- Кôд је послат!
- Поново се шаље…
+ Број телефона је аутоматски верификованПоново пошаљи кôдВерификуј број телефонаНаставиАко додирнете „%1$s“, можда ћете послати SMS. Могу да вам буду наплаћени трошкови слања поруке и преноса података.Ако додирнете „%1$s“, потврђујете да прихватате документе %2$s и %3$s. Можда ћете послати SMS. Могу да вам буду наплаћени трошкови слања поруке и преноса података.
- Ако додирнете „%1$s“, потврђујете да прихватате документ %2$s. Можда ћете послати SMS. Могу да вам буду наплаћени трошкови слања поруке и преноса података.
- Ако додирнете „%1$s“, потврђујете да прихватате документ %2$s. Можда ћете послати SMS. Могу да вам буду наплаћени трошкови слања поруке и преноса података.
diff --git a/auth/src/main/res/values-sv/strings.xml b/auth/src/main/res/values-sv/strings.xml
index 7845aea79..bd2c81a37 100755
--- a/auth/src/main/res/values-sv/strings.xml
+++ b/auth/src/main/res/values-sv/strings.xml
@@ -2,17 +2,15 @@
Läser in…Logga inGenom att fortsätta godkänner du våra %1$s och vår %2$s.
- Genom att fortsätta godkänner du våra %1$s.
- Genom att fortsätta godkänner du vår %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubLogga in med GoogleLogga in med FacebookLogga in med Twitter
+ Logga in med GitHubLogga in med e-postLogga in med telefonNästa
@@ -53,22 +51,15 @@
Skicka kod igen om 0:%02dVerifiera ditt telefonnummerVerifierar …
- Hämtar sms…Fel kod. Försök igen.
- OKDet här telefonnumret har använts för många gångerDet gick inte att verifiera telefonnumretKoden är inte längre giltigLogga in med telefonnummer
- Klart
- Verifierat!
- Koden har skickats!
- Skickar igen…
+ Telefonnumret verifierades automatisktSkicka koden igenVerifiera telefonnummerFortsättGenom att trycka på %1$s skickas ett sms. Meddelande- och dataavgifter kan tillkomma.Genom att trycka på %1$s godkänner du våra %2$s och vår %3$s. Ett sms kan skickas. Meddelande- och dataavgifter kan tillkomma.
- Genom att trycka på %1$s godkänner du våra %2$s. Ett sms kan skickas. Meddelande- och dataavgifter kan tillkomma.
- Genom att trycka på %1$s godkänner du vår %2$s. Ett sms kan skickas. Meddelande- och dataavgifter kan tillkomma.
diff --git a/auth/src/main/res/values-ta/strings.xml b/auth/src/main/res/values-ta/strings.xml
index 9da892934..0dfd772a0 100755
--- a/auth/src/main/res/values-ta/strings.xml
+++ b/auth/src/main/res/values-ta/strings.xml
@@ -2,17 +2,15 @@
ஏற்றுகிறது…உள்நுழைகதொடர்வதன் மூலம், எங்கள் %1$s மற்றும் %2$sஐ ஏற்பதாகக் குறிப்பிடுகிறீர்கள்.
- தொடர்வதன் மூலம், எங்கள் %1$sஐ ஏற்பதாகக் குறிப்பிடுகிறீர்கள்.
- தொடர்வதன் மூலம், எங்கள் %1$sஐ ஏற்பதாகக் குறிப்பிடுகிறீர்கள்.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GithubGoogle மூலம் உள்நுழைகFacebook மூலம் உள்நுழைகTwitter மூலம் உள்நுழைக
+ GitHub பயன்படுத்தி உள்நுழைகமின்னஞ்சல் மூலம் உள்நுழைகஃபோன் எண் மூலம் உள்நுழைகஅடுத்து
@@ -53,22 +51,15 @@
குறியீட்டை 0:%02d நேரத்தில் மீண்டும் அனுப்பவும்ஃபோன் எண்ணைச் சரிபார்சரிபார்க்கிறது…
- smsஐ மீட்டெடுக்கிறது…தவறான குறியீடு. மீண்டும் முயலவும்.
- சரிஇந்த ஃபோன் எண் பலமுறை பயன்படுத்தப்பட்டுள்ளதுஉங்கள் ஃபோன் எண்ணைச் சரிபார்ப்பதில் சிக்கல் ஏற்பட்டதுஇந்தக் குறியீடு இனி செல்லுபடியாகாதுஃபோன் எண் மூலம் உள்நுழையவும்
- முடிந்தது
- சரிபார்க்கப்பட்டது!
- குறியீடு அனுப்பப்பட்டது!
- மீண்டும் அனுப்புகிறது…
+ ஃபோன் எண் தானாகவே சரிபார்க்கப்பட்டதுகுறியீட்டை மீண்டும் அனுப்புஃபோன் எண்ணைச் சரிபார்தொடர்க“%1$s” என்பதைத் தட்டுவதன் மூலம், SMS அனுப்பப்படலாம். செய்தி மற்றும் தரவுக் கட்டணங்கள் விதிக்கப்படலாம்.“%1$s” என்பதைத் தட்டுவதன் மூலம், எங்கள் %2$s மற்றும் %3$sஐ ஏற்பதாகக் குறிப்பிடுகிறீர்கள். SMS அனுப்பப்படலாம். செய்தி மற்றும் தரவுக் கட்டணங்கள் விதிக்கப்படலாம்.
- “%1$s” என்பதைத் தட்டுவதன் மூலம், எங்கள் %2$sஐ ஏற்பதாகக் குறிப்பிடுகிறீர்கள். SMS அனுப்பப்படலாம். செய்தி மற்றும் தரவுக் கட்டணங்கள் விதிக்கப்படலாம்.
- “%1$s” என்பதைத் தட்டுவதன் மூலம், எங்கள் %2$sஐ ஏற்பதாகக் குறிப்பிடுகிறீர்கள். SMS அனுப்பப்படலாம். செய்தி மற்றும் தரவுக் கட்டணங்கள் விதிக்கப்படலாம்.
diff --git a/auth/src/main/res/values-th/strings.xml b/auth/src/main/res/values-th/strings.xml
index dc1c4e713..f5fde37b3 100755
--- a/auth/src/main/res/values-th/strings.xml
+++ b/auth/src/main/res/values-th/strings.xml
@@ -2,17 +2,15 @@
กำลังโหลด…ลงชื่อเข้าใช้การดำเนินการต่อแสดงว่าคุณยอมรับ %1$s และ %2$s
- การดำเนินการต่อแสดงว่าคุณยอมรับ %1$s
- การดำเนินการต่อแสดงว่าคุณยอมรับ %1$s%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubลงชื่อเข้าใช้ด้วย Googleลงชื่อเข้าใช้ด้วย Facebookลงชื่อเข้าใช้ด้วย Twitter
+ ลงชื่อเข้าใช้ด้วย GitHubลงชื่อเข้าใช้ด้วยอีเมลลงชื่อเข้าใช้ด้วยโทรศัพท์ถัดไป
@@ -53,22 +51,15 @@
ส่งรหัสอีกครั้งใน 0:%02dยืนยันหมายเลขโทรศัพท์กำลังยืนยัน…
- กำลังเรียกข้อมูล SMS…รหัสไม่ถูกต้อง โปรดลองอีกครั้ง
- ตกลงมีการใช้หมายเลขโทรศัพท์นี้หลายครั้งเกินไปเกิดปัญหาในการยืนยันหมายเลขโทรศัพท์ของคุณไม่สามารถใช้รหัสนี้ได้อีกต่อไปลงชื่อเข้าใช้ด้วยหมายเลขโทรศัพท์
- เสร็จสิ้น
- ยืนยันแล้ว
- ส่งรหัสแล้ว
- กำลังส่งอีกครั้ง…
+ ยืนยันหมายเลขโทรศัพท์โดยอัตโนมัติแล้วส่งรหัสอีกครั้งยืนยันหมายเลขโทรศัพท์ต่อไปเมื่อคุณแตะ “%1$s” ระบบจะส่ง SMS ให้คุณ อาจมีค่าบริการรับส่งข้อความและค่าบริการอินเทอร์เน็ตการแตะ “%1$s” แสดงว่าคุณยอมรับ %2$s และ %3$s ระบบจะส่ง SMS ให้คุณ อาจมีค่าบริการรับส่งข้อความและค่าบริการอินเทอร์เน็ต
- การแตะ “%1$s” แสดงว่าคุณยอมรับ %2$s ระบบจะส่ง SMS ให้คุณ อาจมีค่าบริการรับส่งข้อความและค่าบริการอินเทอร์เน็ต
- การแตะ “%1$s” แสดงว่าคุณยอมรับ %2$s ระบบจะส่ง SMS ให้คุณ อาจมีค่าบริการรับส่งข้อความและค่าบริการอินเทอร์เน็ต
diff --git a/auth/src/main/res/values-tl/strings.xml b/auth/src/main/res/values-tl/strings.xml
index 6eddc0122..e9a8de2de 100755
--- a/auth/src/main/res/values-tl/strings.xml
+++ b/auth/src/main/res/values-tl/strings.xml
@@ -2,17 +2,15 @@
Naglo-load…Mag-sign inSa pagpapatuloy, ipinababatid mo na tinatanggap mo ang aming %1$s at %2$s.
- Sa pagpapatuloy, ipinababatid mo na tinatanggap mo ang aming %1$s.
- Sa pagpapatuloy, ipinababatid mo na tinatanggap mo ang aming %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFecebookTwitter
+ GitHubMag-sign in sa GoogleMag-sign in sa FacebookMag-sign in sa Twitter
+ Mag-sign in sa GitHubMag-sign in gamit ang emailMag-sign in gamit ang teleponoSusunod
@@ -53,22 +51,15 @@
Ipadala muli ang code sa loob ng 0:%02dI-verify ang numero ng iyong teleponoBine-verify…
- Kinukuha ang sms…Maling code. Subukang muli.
- OKMasyadong maraming beses nang nagamit ang numero ng teleponong itoNagkaproblema sa pag-verify ng numero ng iyong teleponoWala nang bisa ang code na itoMag-sign in gamit ang numero ng telepono
- Tapos Na
- Na-verify!
- Naipadala ang code!
- Ipinapadalang muli…
+ Awtomatikong na-verify ang numero ng teleponoIpadala Muli ang CodeI-verify ang Numero ng TeleponoMagpatuloySa pag-tap sa “%1$s,“ maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.Sa pag-tap sa “%1$s”, ipinababatid mo na tinatanggap mo ang aming %2$s at %3$s. Maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.
- Sa pag-tap sa “%1$s”, ipinababatid mo na tinatanggap mo ang aming %2$s. Maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.
- Sa pag-tap sa “%1$s”, ipinababatid mo na tinatanggap mo ang aming %2$s. Maaaring magpadala ng SMS. Maaaring ipatupad ang mga rate ng pagmemensahe at data.
diff --git a/auth/src/main/res/values-tr/strings.xml b/auth/src/main/res/values-tr/strings.xml
index 13b85138e..a2e39b28a 100755
--- a/auth/src/main/res/values-tr/strings.xml
+++ b/auth/src/main/res/values-tr/strings.xml
@@ -2,17 +2,15 @@
Yükleniyor…Oturum açDevam ederek %1$s ve %2$s hükümlerimizi kabul ettiğinizi bildirirsiniz.
- Devam ederek %1$s hükümlerimizi kabul ettiğinizi bildirirsiniz.
- Devam ederek %1$s hükümlerimizi kabul ettiğinizi bildirirsiniz.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubGoogle ile oturum açFacebook ile oturum açTwitter ile oturum aç
+ GitHub ile oturum açE-posta ile oturum açTelefonla oturum açİleri
@@ -53,22 +51,15 @@
0:%02d içinde kodu yeniden gönderTelefon numaranızı doğrulayınDoğrulanıyor…
- SMS alınıyor…Yanlış kod. Tekrar deneyin.
- TamamBu telefon numarası çok fazla kez kullanıldıTelefon numaranız doğrulanırken bir sorun oluştuBu kod artık geçerli değilTelefon numarasıyla oturum açın
- Bitti
- Doğrulandı!
- Kod gönderildi!
- Yeniden gönderiliyor…
+ Telefon numarası otomatik olarak doğrulandıKodu Yeniden GönderTelefon Numarasını DoğrulaDevam“%1$s” öğesine dokunarak SMS gönderilebilir. Mesaj ve veri ücretleri uygulanabilir.“%1$s” öğesine dokunarak %2$s ve %3$s hükümlerimizi kabul ettiğinizi bildirirsiniz. SMS gönderilebilir. Mesaj ve veri ücretleri uygulanabilir.
- %1$s öğesine dokunarak %2$s hükümlerimizi kabul ettiğinizi bildirirsiniz. SMS gönderilebilir. Mesaj ve veri ücretleri uygulanabilir.
- %1$s öğesine dokunarak %2$s hükümlerimizi kabul ettiğinizi bildirirsiniz. SMS gönderilebilir. Mesaj ve veri ücretleri uygulanabilir.
diff --git a/auth/src/main/res/values-uk/strings.xml b/auth/src/main/res/values-uk/strings.xml
index 6f2365ad1..8fe0677c9 100755
--- a/auth/src/main/res/values-uk/strings.xml
+++ b/auth/src/main/res/values-uk/strings.xml
@@ -2,17 +2,15 @@
Завантаження…УвійтиПродовжуючи, ви приймаєте такі документи: %1$s і %2$s.
- Продовжуючи, ви приймаєте такий документ: %1$s.
- Продовжуючи, ви приймаєте такий документ: %1$s.%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GitHubУвійти через GoogleУвійти через FacebookУвійти через Twitter
+ Увійти через GitHubУвійти, використовуючи електронну адресуУвійти, використовуючи телефонДалі
@@ -53,22 +51,15 @@
Повторно надіслати код через 0:%02dПідтвердити номер телефонуПідтвердження…
- Отримання SMS…Неправильний код. Повторіть спробу.
- ОКЦей номер телефону використовувався забагато разівНе вдалося підтвердити ваш номер телефонуЦей код уже не дійснийУвійти, використовуючи номер телефону
- Готово
- Підтверджено
- Код надіслано
- Повторне надсилання…
+ Номер телефону підтверджено автоматичноПовторно надіслати кодПідтвердити номер телефонуПродовжитиКоли ви торкнетесь опції “%1$s”, вам може надійти SMS-повідомлення. За SMS і використання трафіку може стягуватися плата.Торкаючись кнопки “%1$s”, ви приймаєте такі документи: %2$s і %3$s. Вам може надійти SMS-повідомлення. За SMS і використання трафіку може стягуватися плата.
- Торкаючись кнопки “%1$s”, ви приймаєте такий документ: %2$s. Вам може надійти SMS-повідомлення. За SMS і використання трафіку може стягуватися плата.
- Торкаючись кнопки “%1$s”, ви приймаєте такий документ: %2$s. Вам може надійти SMS-повідомлення. За SMS і використання трафіку може стягуватися плата.
diff --git a/auth/src/main/res/values-ur/strings.xml b/auth/src/main/res/values-ur/strings.xml
index e6b9ee877..f523cd7b5 100755
--- a/auth/src/main/res/values-ur/strings.xml
+++ b/auth/src/main/res/values-ur/strings.xml
@@ -2,17 +2,15 @@
لوڈ ہو رہا ہے…سائن ان کریںجاری رکھ کر، آپ نشاندہی کر رہے ہیں کہ آپ ہماری %1$s اور %2$s کو قبول کرتے ہیں۔
- جاری رکھ کر، آپ نشاندہی کر رہے ہیں کہ آپ ہماری %1$s کو قبول کرتے ہیں۔
- جاری رکھ کر، آپ نشاندہی کر رہے ہیں کہ آپ ہماری %1$s کو قبول کرتے ہیں۔%1$s \u00A0 \u00A0 %2$s
- %1$s
- %1$sGoogleFacebookTwitter
+ GithubGoogle کے ساتھ سائن ان کریںFacebook کے ساتھ سائن ان کریںTwitter کے ساتھ سائن ان کریں
+ GitHub کے ساتھ سائن ان کریںای میل کے ساتھ سائن ان کریںفون کے ساتھ سائں ان کریںاگلا
@@ -53,22 +51,15 @@
0:%02d میں دوبارہ کوڈ بھیجیںاپنے فون نمبر کی توثیق کریںتوثیق ہو رہی ہے…
- sms بازیافت کیا جا رہا ہے…غلط کوڈ۔ دوبارہ کوشش کریں۔
- ٹھیک ہےیہ فون نمبر پہلے ہی کافی مرتبہ استعمال ہو چکا ہےآپ کے فون نمبر کی توثیق کرنے میں ایک مسئلہ تھایہ کوڈ اب جائز نہیں رہافون نمبر کے ساتھ سائن ان کریں
- ہو گیا
- توثیق مکمل!
- کوڈ بھیج دیا گیا!
- دوبارہ بھیجا جا رہا ہے…
+ فون نمبر کی خودکار طور پر توثیق ہو گئیکوڈ دوبارہ بھیجیںفون نمبر کی توثیق کریںجاری رکھیں%1$s پر تھپتھپانے سے، ایک SMS بھیجا جا سکتا ہے۔ پیغام اور ڈیٹا کی شرحوں کا اطلاق ہو سکتا ہے۔“%1$s” کو تھپتھپا کر، آپ نشاندہی کر رہے ہیں کہ آپ ہماری %2$s اور %3$s کو قبول کرتے ہیں۔ ایک SMS بھیجا جا سکتا ہے۔ پیغام اور ڈیٹا نرخ لاگو ہو سکتے ہیں۔
- “%1$s” کو تھپتھپا کر، آپ نشاندہی کر رہے ہیں کہ آپ ہماری %2$s کو قبول کرتے ہیں۔ ایک SMS بھیجا جا سکتا ہے۔ پیغام اور ڈیٹا نرخ لاگو ہو سکتے ہیں۔
- “%1$s” کو تھپتھپا کر، آپ نشاندہی کر رہے ہیں کہ آپ ہماری %2$s کو قبول کرتے ہیں۔ ایک SMS بھیجا جا سکتا ہے۔ پیغام اور ڈیٹا نرخ لاگو ہو سکتے ہیں۔
diff --git a/auth/src/main/res/values-v26/styles.xml b/auth/src/main/res/values-v26/styles.xml
index 08dc27746..96c087089 100755
--- a/auth/src/main/res/values-v26/styles.xml
+++ b/auth/src/main/res/values-v26/styles.xml
@@ -15,11 +15,7 @@
-
-
-
-
+
+
+
+
+
+
diff --git a/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java b/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java
index 1476505e4..e359e5a1b 100644
--- a/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java
+++ b/auth/src/test/java/com/firebase/ui/auth/AuthUITest.java
@@ -20,32 +20,32 @@
import com.firebase.ui.auth.testhelpers.TestConstants;
import com.firebase.ui.auth.testhelpers.TestHelper;
import com.firebase.ui.auth.util.ExtraConstants;
-import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.EmailAuthProvider;
-import com.google.firebase.auth.FirebaseAuth;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import static junit.framework.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
@RunWith(RobolectricTestRunner.class)
public class AuthUITest {
+ private AuthUI mAuthUi;
+
@Before
public void setUp() {
TestHelper.initialize();
- AuthUI.sDefaultAuth = mock(FirebaseAuth.class);
+ mAuthUi = AuthUI.getInstance(TestHelper.MOCK_APP);
}
@Test
public void testCreateStartIntent_shouldHaveEmailAsDefaultProvider() {
- FlowParameters flowParameters = AuthUI
- .getInstance()
+ FlowParameters flowParameters = mAuthUi
.createSignInIntentBuilder()
.build()
.getParcelableExtra(ExtraConstants.FLOW_PARAMS);
@@ -56,7 +56,7 @@ public void testCreateStartIntent_shouldHaveEmailAsDefaultProvider() {
@Test(expected = IllegalArgumentException.class)
public void testCreateStartIntent_shouldOnlyAllowOneInstanceOfAnIdp() {
- SignInIntentBuilder startIntent = AuthUI.getInstance().createSignInIntentBuilder();
+ SignInIntentBuilder startIntent = mAuthUi.createSignInIntentBuilder();
startIntent.setAvailableProviders(Arrays.asList(
new IdpConfig.EmailBuilder().build(),
new IdpConfig.EmailBuilder().build()));
@@ -64,21 +64,142 @@ public void testCreateStartIntent_shouldOnlyAllowOneInstanceOfAnIdp() {
@Test
public void testCreatingStartIntent() {
- FlowParameters flowParameters = AuthUI.getInstance()
+ FlowParameters flowParameters = mAuthUi
.createSignInIntentBuilder()
.setAvailableProviders(Arrays.asList(
new IdpConfig.EmailBuilder().build(),
new IdpConfig.GoogleBuilder().build(),
new IdpConfig.FacebookBuilder().build()))
- .setTosUrl(TestConstants.TOS_URL)
- .setPrivacyPolicyUrl(TestConstants.PRIVACY_URL)
+ .setTosAndPrivacyPolicyUrls(TestConstants.TOS_URL, TestConstants.PRIVACY_URL)
.build()
.getParcelableExtra(ExtraConstants.FLOW_PARAMS);
assertEquals(3, flowParameters.providerInfo.size());
- assertEquals(FirebaseApp.getInstance().getName(), flowParameters.appName);
+ assertEquals(TestHelper.MOCK_APP.getName(), flowParameters.appName);
assertEquals(TestConstants.TOS_URL, flowParameters.termsOfServiceUrl);
assertEquals(TestConstants.PRIVACY_URL, flowParameters.privacyPolicyUrl);
assertEquals(AuthUI.getDefaultTheme(), flowParameters.themeId);
}
+
+ @Test(expected = NullPointerException.class)
+ public void testCreatingStartIntent_withNullTos_expectEnforcesNonNullTosUrl() {
+ SignInIntentBuilder startIntent = mAuthUi.createSignInIntentBuilder();
+ startIntent.setTosAndPrivacyPolicyUrls(null, TestConstants.PRIVACY_URL);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCreatingStartIntent_withNullPp_expectEnforcesNonNullPpUrl() {
+ SignInIntentBuilder startIntent = mAuthUi.createSignInIntentBuilder();
+ startIntent.setTosAndPrivacyPolicyUrls(TestConstants.TOS_URL, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPhoneBuilder_withBlacklistedDefaultNumberCode_expectIllegalArgumentException() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("+1123456789")
+ .setBlacklistedCountries(Arrays.asList("+1"))
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPhoneBuilder_withBlacklistedDefaultIso_expectIllegalArgumentException() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("us", "123456789")
+ .setBlacklistedCountries(Arrays.asList("us"))
+ .build();
+ }
+
+ @Test
+ public void testPhoneBuilder_withWhitelistedDefaultIso_expectSuccess() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("us", "123456789")
+ .setWhitelistedCountries(Arrays.asList("us"))
+ .build();
+ }
+
+ @Test
+ public void testPhoneBuilder_withWhitelistedDefaultNumberCode_expectSuccess() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("+1123456789")
+ .setWhitelistedCountries(Arrays.asList("+1"))
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPhoneBuilder_whiteInvalidDefaultNumberCode_expectIllegalArgumentException() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("+1123456789")
+ .setWhitelistedCountries(Arrays.asList("gr"))
+ .build();
+ }
+
+ @Test
+ public void testPhoneBuilder_withValidDefaultNumberCode_expectSuccess() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("+1123456789")
+ .setWhitelistedCountries(Arrays.asList("ca"))
+ .build();
+ }
+
+ @Test
+ public void testPhoneBuilder_withBlacklistedCountryWithSameCountryCode_expectSucess() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("+1123456789")
+ .setBlacklistedCountries(Arrays.asList("ca"))
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPhoneBuilder_withInvalidDefaultIso_expectIllegalArgumentException() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("us", "123456789")
+ .setWhitelistedCountries(Arrays.asList("ca"))
+ .build();
+ }
+
+ @Test
+ public void testPhoneBuilder_withValidDefaultIso_expectSucess() {
+ new IdpConfig.PhoneBuilder()
+ .setDefaultNumber("us", "123456789")
+ .setBlacklistedCountries(Arrays.asList("ca"))
+ .build();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testPhoneBuilder_setBothBlacklistedAndWhitelistedCountries_expectIllegalStateException() {
+ List countries = Arrays.asList("ca");
+ new IdpConfig.PhoneBuilder()
+ .setBlacklistedCountries(countries)
+ .setWhitelistedCountries(countries)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPhoneBuilder_passEmptyListForWhitelistedCountries_expectIllegalArgumentException() {
+ new IdpConfig.PhoneBuilder()
+ .setWhitelistedCountries(new ArrayList())
+ .build();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testPhoneBuilder_passNullForWhitelistedCountries_expectNullPointerException() {
+ new IdpConfig.PhoneBuilder()
+ .setWhitelistedCountries(null)
+ .build();
+ }
+
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPhoneBuilder_passEmptyListForBlacklistedCountries_expectIllegalArgumentException() {
+ new IdpConfig.PhoneBuilder()
+ .setBlacklistedCountries(new ArrayList())
+ .build();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testPhoneBuilder_passNullForBlacklistedCountries_expectNullPointerException() {
+ new IdpConfig.PhoneBuilder()
+ .setBlacklistedCountries(null)
+ .build();
+ }
}
diff --git a/auth/src/test/java/com/firebase/ui/auth/testhelpers/AuthHelperShadow.java b/auth/src/test/java/com/firebase/ui/auth/testhelpers/AuthHelperShadow.java
deleted file mode 100644
index 5f783e04a..000000000
--- a/auth/src/test/java/com/firebase/ui/auth/testhelpers/AuthHelperShadow.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.firebase.ui.auth.testhelpers;
-
-import com.firebase.ui.auth.util.AuthHelper;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.auth.FirebaseUser;
-import com.google.firebase.auth.PhoneAuthProvider;
-
-import org.mockito.Mockito;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-import static org.mockito.Mockito.when;
-
-@Implements(AuthHelper.class)
-public class AuthHelperShadow {
-
- private static FirebaseAuth sFirebaseAuth;
- private static FirebaseUser sFirebaseUser;
- private static PhoneAuthProvider sPhoneAuthProvider;
-
- public AuthHelperShadow() {}
-
- @Implementation
- public static FirebaseAuth getFirebaseAuth() {
- if (sFirebaseAuth == null) {
- sFirebaseAuth = Mockito.mock(FirebaseAuth.class);
- when(sFirebaseAuth.getCurrentUser()).thenReturn(sFirebaseUser);
- }
-
- return sFirebaseAuth;
- }
-
- @Implementation
- public static FirebaseUser getCurrentUser() {
- if (sFirebaseUser == null) {
- sFirebaseUser = TestHelper.getMockFirebaseUser();
- }
-
- return sFirebaseUser;
- }
-
- @Implementation
- public static PhoneAuthProvider getPhoneAuthProvider() {
- if (sPhoneAuthProvider == null) {
- sPhoneAuthProvider = Mockito.mock(PhoneAuthProvider.class);
- }
-
- return sPhoneAuthProvider;
- }
-
-}
diff --git a/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAdditionalUserInfo.java b/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAdditionalUserInfo.java
new file mode 100644
index 000000000..4ed653543
--- /dev/null
+++ b/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAdditionalUserInfo.java
@@ -0,0 +1,44 @@
+package com.firebase.ui.auth.testhelpers;
+
+import android.os.Parcel;
+
+import com.google.firebase.auth.AdditionalUserInfo;
+
+import java.util.Map;
+
+public final class FakeAdditionalUserInfo implements AdditionalUserInfo {
+ public static final AdditionalUserInfo INSTANCE = new FakeAdditionalUserInfo();
+
+ // Singleton
+ private FakeAdditionalUserInfo() {}
+
+ @Override
+ public String getProviderId() {
+ return null;
+ }
+
+ @Override
+ public Map getProfile() {
+ return null;
+ }
+
+ @Override
+ public String getUsername() {
+ return null;
+ }
+
+ @Override
+ public boolean isNewUser() {
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ throw new IllegalStateException("Don't try to parcel FakeAuthResult!");
+ }
+}
diff --git a/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAuthResult.java b/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAuthResult.java
index d7a3ec861..24a5af6d6 100644
--- a/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAuthResult.java
+++ b/auth/src/test/java/com/firebase/ui/auth/testhelpers/FakeAuthResult.java
@@ -42,7 +42,7 @@ public FirebaseUser getUser() {
@Override
public AdditionalUserInfo getAdditionalUserInfo() {
- return null;
+ return FakeAdditionalUserInfo.INSTANCE;
}
@Override
diff --git a/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java b/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java
index 37f282a83..45a79924f 100644
--- a/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java
+++ b/auth/src/test/java/com/firebase/ui/auth/testhelpers/TestHelper.java
@@ -14,48 +14,45 @@
package com.firebase.ui.auth.testhelpers;
-import android.app.Activity;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Resources;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.AuthUI.IdpConfig;
import com.firebase.ui.auth.R;
import com.firebase.ui.auth.data.model.FlowParameters;
-import com.firebase.ui.auth.ui.credentials.CredentialSaveActivity;
-import com.firebase.ui.auth.util.ExtraConstants;
-import com.firebase.ui.auth.util.data.ProviderUtils;
-import com.google.android.gms.auth.api.credentials.Credential;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FacebookAuthProvider;
+import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
-import org.junit.Assert;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowActivity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-public class TestHelper {
- private static final String APPLICATION_ID = "testAppId";
- private static final String API_KEY = "fakeKey";
+public final class TestHelper {
+ public static final FirebaseApp MOCK_APP;
+
+ static {
+ FirebaseApp app = mock(FirebaseApp.class);
+ when(app.get(eq(FirebaseAuth.class))).thenReturn(mock(FirebaseAuth.class));
+ when(app.getApplicationContext()).thenReturn(RuntimeEnvironment.application);
+ when(app.getName()).thenReturn(FirebaseApp.DEFAULT_APP_NAME);
+ MOCK_APP = app;
+ }
public static void initialize() {
spyContextAndResources();
@@ -72,26 +69,24 @@ private static void spyContextAndResources() {
when(RuntimeEnvironment.application.getResources()).thenReturn(spiedResources);
}
- private static FirebaseApp initializeApp(Context context) {
- try {
- return FirebaseApp.initializeApp(
- context,
- new FirebaseOptions.Builder()
- .setApiKey(API_KEY)
- .setApplicationId(APPLICATION_ID)
- .build(),
- FirebaseApp.DEFAULT_APP_NAME);
- } catch (IllegalStateException e) {
- return FirebaseApp.getInstance(FirebaseApp.DEFAULT_APP_NAME);
- }
+ private static void initializeApp(Context context) {
+ if (!FirebaseApp.getApps(context).isEmpty()) return;
+
+ FirebaseApp.initializeApp(context, new FirebaseOptions.Builder()
+ .setApiKey("fake")
+ .setApplicationId("fake")
+ .build());
}
private static void initializeProviders() {
Context context = RuntimeEnvironment.application;
+ when(context.getString(R.string.firebase_web_host)).thenReturn("abc");
when(context.getString(R.string.default_web_client_id)).thenReturn("abc");
when(context.getString(R.string.facebook_application_id)).thenReturn("abc");
when(context.getString(R.string.twitter_consumer_key)).thenReturn("abc");
when(context.getString(R.string.twitter_consumer_secret)).thenReturn("abc");
+ when(context.getString(R.string.github_client_id)).thenReturn("abc");
+ when(context.getString(R.string.github_client_secret)).thenReturn("abc");
}
public static FirebaseUser getMockFirebaseUser() {
@@ -105,6 +100,11 @@ public static FirebaseUser getMockFirebaseUser() {
}
public static FlowParameters getFlowParameters(Collection providerIds) {
+ return getFlowParameters(providerIds, false);
+ }
+
+ public static FlowParameters getFlowParameters(Collection providerIds,
+ boolean enableAnonymousUpgrade) {
List idpConfigs = new ArrayList<>();
for (String providerId : providerIds) {
switch (providerId) {
@@ -117,6 +117,9 @@ public static FlowParameters getFlowParameters(Collection providerIds) {
case TwitterAuthProvider.PROVIDER_ID:
idpConfigs.add(new IdpConfig.TwitterBuilder().build());
break;
+ case GithubAuthProvider.PROVIDER_ID:
+ idpConfigs.add(new IdpConfig.GitHubBuilder().build());
+ break;
case EmailAuthProvider.PROVIDER_ID:
idpConfigs.add(new IdpConfig.EmailBuilder().build());
break;
@@ -135,39 +138,9 @@ public static FlowParameters getFlowParameters(Collection providerIds) {
null,
null,
true,
- true);
+ true,
+ enableAnonymousUpgrade);
}
- public static void verifyCredentialSaveStarted(@NonNull Activity activity,
- @Nullable String providerId,
- @Nullable String email,
- @Nullable String password,
- @Nullable String phoneNumber) {
- ShadowActivity shadowActivity = Shadows.shadowOf(activity);
- Intent startedIntent = shadowActivity.getNextStartedActivity();
-
- // Verify that CredentialSaveActivity is next up
- Assert.assertEquals(startedIntent.getComponent().getClassName(),
- CredentialSaveActivity.class.getName());
-
- // Check the credential passed
- Credential credential = startedIntent.getParcelableExtra(ExtraConstants.CREDENTIAL);
-
- // Check the password
- assertEquals(credential.getPassword(), password);
-
- // Non-password credentials have a provider ID
- if (TextUtils.isEmpty(password)) {
- assertEquals(credential.getAccountType(),
- ProviderUtils.providerIdToAccountType(providerId));
- }
-
- // ID can either be email or phone number
- if (!TextUtils.isEmpty(phoneNumber)) {
- assertEquals(credential.getId(), phoneNumber);
- } else {
- assertEquals(credential.getId(), email);
- }
- }
}
diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java b/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java
index 6aee3400b..50b8ccc9b 100644
--- a/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java
+++ b/auth/src/test/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivityTest.java
@@ -15,7 +15,6 @@
package com.firebase.ui.auth.ui.idp;
import android.content.Intent;
-import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
@@ -64,8 +63,6 @@ public void testAllProvidersArePopulated() {
assertEquals(providers.size(),
((LinearLayout) authMethodPickerActivity.findViewById(R.id.btn_holder))
.getChildCount());
- Button emailButton = authMethodPickerActivity.findViewById(R.id.email_button);
- assertEquals(View.VISIBLE, emailButton.getVisibility());
}
@Test
diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/phone/CountryListLoadTaskTests.java b/auth/src/test/java/com/firebase/ui/auth/ui/phone/CountryListLoadTaskTests.java
deleted file mode 100644
index d189f6b30..000000000
--- a/auth/src/test/java/com/firebase/ui/auth/ui/phone/CountryListLoadTaskTests.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2015 Twitter, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Modifications copyright (C) 2017 Google Inc
- */
-
-package com.firebase.ui.auth.ui.phone;
-
-import com.firebase.ui.auth.data.client.CountryListLoadTask;
-import com.firebase.ui.auth.data.model.CountryInfo;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-@RunWith(RobolectricTestRunner.class)
-public class CountryListLoadTaskTests {
- private static final ArrayList COUNTRY_LIST = new ArrayList<>();
-
- static {
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AF"), 93));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AX"), 358));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AL"), 355));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "DZ"), 213));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AS"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AD"), 376));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AO"), 244));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AI"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AG"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AR"), 54));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AM"), 374));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AW"), 297));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AC"), 247));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AU"), 61));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AT"), 43));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AZ"), 994));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BS"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BH"), 973));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BD"), 880));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BB"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BY"), 375));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BE"), 32));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BZ"), 501));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BJ"), 229));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BM"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BT"), 975));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BO"), 591));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BA"), 387));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BW"), 267));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BR"), 55));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IO"), 246));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VG"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BN"), 673));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BG"), 359));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BF"), 226));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BI"), 257));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KH"), 855));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CM"), 237));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CA"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CV"), 238));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BQ"), 599));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KY"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CF"), 236));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TD"), 235));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CL"), 56));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CN"), 86));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CX"), 61));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CC"), 61));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CO"), 57));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KM"), 269));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CD"), 243));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CG"), 242));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CK"), 682));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CR"), 506));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CI"), 225));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "HR"), 385));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CU"), 53));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CW"), 599));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CY"), 357));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CZ"), 420));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "DK"), 45));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "DJ"), 253));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "DM"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "DO"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TL"), 670));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "EC"), 593));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "EG"), 20));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SV"), 503));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GQ"), 240));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ER"), 291));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "EE"), 372));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ET"), 251));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "FK"), 500));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "FO"), 298));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "FJ"), 679));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "FI"), 358));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "FR"), 33));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GF"), 594));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PF"), 689));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GA"), 241));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GM"), 220));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GE"), 995));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "DE"), 49));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GH"), 233));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GI"), 350));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GR"), 30));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GL"), 299));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GD"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GP"), 590));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GU"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GT"), 502));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GG"), 44));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GN"), 224));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GW"), 245));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GY"), 592));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "HT"), 509));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "HM"), 672));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "HN"), 504));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "HK"), 852));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "HU"), 36));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IS"), 354));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IN"), 91));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ID"), 62));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IR"), 98));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IQ"), 964));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IE"), 353));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IM"), 44));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IL"), 972));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "IT"), 39));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "JM"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "JP"), 81));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "JE"), 44));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "JO"), 962));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KZ"), 7));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KE"), 254));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KI"), 686));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "XK"), 381));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KW"), 965));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KG"), 996));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LA"), 856));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LV"), 371));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LB"), 961));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LS"), 266));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LR"), 231));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LY"), 218));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LI"), 423));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LT"), 370));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LU"), 352));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MO"), 853));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MK"), 389));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MG"), 261));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MW"), 265));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MY"), 60));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MV"), 960));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ML"), 223));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MT"), 356));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MH"), 692));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MQ"), 596));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MR"), 222));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MU"), 230));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "YT"), 262));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MX"), 52));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "FM"), 691));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MD"), 373));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MC"), 377));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MN"), 976));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ME"), 382));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MS"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MA"), 212));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MZ"), 258));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MM"), 95));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NA"), 264));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NR"), 674));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NP"), 977));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NL"), 31));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NC"), 687));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NZ"), 64));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NI"), 505));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NE"), 227));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NG"), 234));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NU"), 683));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NF"), 672));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KP"), 850));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MP"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "NO"), 47));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "OM"), 968));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PK"), 92));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PW"), 680));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PS"), 970));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PA"), 507));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PG"), 675));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PY"), 595));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PE"), 51));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PH"), 63));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PL"), 48));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PT"), 351));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PR"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "QA"), 974));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "RE"), 262));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "RO"), 40));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "RU"), 7));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "RW"), 250));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "BL"), 590));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SH"), 290));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KN"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LC"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "MF"), 590));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "PM"), 508));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VC"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "WS"), 685));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SM"), 378));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ST"), 239));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SA"), 966));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SN"), 221));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "RS"), 381));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SC"), 248));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SL"), 232));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SG"), 65));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SX"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SK"), 421));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SI"), 386));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SB"), 677));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SO"), 252));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ZA"), 27));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GS"), 500));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "KR"), 82));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SS"), 211));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ES"), 34));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "LK"), 94));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SD"), 249));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SR"), 597));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SJ"), 47));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SZ"), 268));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SE"), 46));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "CH"), 41));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "SY"), 963));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TW"), 886));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TJ"), 992));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TZ"), 255));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TH"), 66));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TG"), 228));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TK"), 690));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TO"), 676));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TT"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TN"), 216));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TR"), 90));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TM"), 993));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TC"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "TV"), 688));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VI"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "UG"), 256));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "UA"), 380));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "AE"), 971));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "GB"), 44));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "US"), 1));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "UY"), 598));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "UZ"), 998));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VU"), 678));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VA"), 379));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VE"), 58));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "VN"), 84));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "WF"), 681));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "EH"), 212));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "YE"), 967));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ZM"), 260));
- COUNTRY_LIST.add(new CountryInfo(new Locale("", "ZW"), 263));
- }
-
- private CountryListLoadTask mTask;
- private CountryListLoadTask.Listener mListener;
-
- @Before
- public void setUp() {
- // Create task and mock dependencies
- mListener = mock(CountryListLoadTask.Listener.class);
- mTask = new CountryListLoadTask(mListener);
- }
-
- @Test
- public void testExecute() {
- mTask.execute();
-
- try {
- final List result = mTask.get();
- Collections.sort(COUNTRY_LIST);
- assertEquals(COUNTRY_LIST, result);
- } catch (InterruptedException e) {
- fail("Should not throw InterruptedException");
- } catch (ExecutionException e) {
- fail("Should not throw ExecutionException");
- }
- }
-
- @Test
- public void testOnPostExecute_nullListener() {
- mTask = new CountryListLoadTask(null);
- try {
- mTask.onPostExecute(COUNTRY_LIST);
- } catch (NullPointerException ex) {
- fail("Should not throw NullPointerException");
- }
- }
-
- @Test
- public void testOnPostExecute() {
- mTask.onPostExecute(COUNTRY_LIST);
- verify(mListener).onLoadComplete(COUNTRY_LIST);
- }
-}
diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneActivityTest.java b/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneActivityTest.java
deleted file mode 100644
index 4a2c075b0..000000000
--- a/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneActivityTest.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.firebase.ui.auth.ui.phone;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.design.widget.TextInputLayout;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.firebase.ui.auth.R;
-import com.firebase.ui.auth.data.model.CountryInfo;
-import com.firebase.ui.auth.testhelpers.AuthHelperShadow;
-import com.firebase.ui.auth.testhelpers.AutoCompleteTask;
-import com.firebase.ui.auth.testhelpers.FakeAuthResult;
-import com.firebase.ui.auth.testhelpers.TestHelper;
-import com.firebase.ui.auth.util.ExtraConstants;
-import com.firebase.ui.auth.util.FirebaseAuthError;
-import com.google.firebase.auth.AuthCredential;
-import com.google.firebase.auth.AuthResult;
-import com.google.firebase.auth.FirebaseAuthException;
-import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
-import com.google.firebase.auth.PhoneAuthCredential;
-import com.google.firebase.auth.PhoneAuthProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
-
-import java.util.Collections;
-import java.util.Locale;
-import java.util.concurrent.TimeUnit;
-
-import static com.firebase.ui.auth.ui.phone.PhoneActivity.AUTO_RETRIEVAL_TIMEOUT_MILLIS;
-import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.CA_COUNTRY_CODE;
-import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.CA_ISO2;
-import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.PHONE;
-import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.PHONE_NO_COUNTRY_CODE;
-import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.YE_COUNTRY_CODE;
-import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.YE_RAW_PHONE;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-@RunWith(RobolectricTestRunner.class)
-public class PhoneActivityTest {
- private PhoneActivity mActivity;
- private TextInputLayout mPhoneLayout;
- private Button mSendCodeButton;
- private EditText mPhoneEditText;
- private CountryListSpinner mCountryListSpinner;
-
- @Captor
- ArgumentCaptor callbacksArgumentCaptor;
- @Mock
- PhoneAuthProvider.ForceResendingToken forceResendingToken;
- @Mock
- PhoneAuthCredential credential;
-
- private String verificationId = "hjksdf737hc";
-
- private PhoneActivity createActivity() {
- Intent startIntent = PhoneActivity.createIntent(
- RuntimeEnvironment.application,
- TestHelper.getFlowParameters(
- Collections.singletonList(PhoneAuthProvider.PROVIDER_ID)), null);
- return Robolectric.buildActivity(PhoneActivity.class, startIntent)
- .create(new Bundle()).start().visible().get();
- }
-
- @Before
- public void setUp() {
- TestHelper.initialize();
- initMocks(this);
- mActivity = createActivity();
- mPhoneEditText = mActivity.findViewById(R.id.phone_number);
- mPhoneLayout = mActivity.findViewById(R.id.phone_layout);
- mSendCodeButton = mActivity.findViewById(R.id.send_code);
- mCountryListSpinner = mActivity.findViewById(R.id.country_list);
- }
-
- @Test
- public void testDefaultFullPhoneNumber_prePopulatesPhoneNumberInBundle() {
- Bundle fullPhoneParams = new Bundle();
- fullPhoneParams.putString(ExtraConstants.PHONE, YE_RAW_PHONE);
- Intent startIntent = PhoneActivity.createIntent(
- RuntimeEnvironment.application,
- TestHelper.getFlowParameters(
- Collections.singletonList(PhoneAuthProvider.PROVIDER_ID)),
- fullPhoneParams);
-
- mActivity = Robolectric.buildActivity(PhoneActivity.class, startIntent)
- .create(new Bundle()).start().visible().get();
-
- VerifyPhoneNumberFragment verifyPhoneNumberFragment = (VerifyPhoneNumberFragment)
- mActivity.getSupportFragmentManager()
- .findFragmentByTag(VerifyPhoneNumberFragment.TAG);
- assertNotNull(verifyPhoneNumberFragment);
- mPhoneEditText = mActivity.findViewById(R.id.phone_number);
- mCountryListSpinner = mActivity.findViewById(R.id.country_list);
-
- assertEquals(PHONE_NO_COUNTRY_CODE, mPhoneEditText.getText().toString());
- assertEquals(YE_COUNTRY_CODE,
- String.valueOf((mCountryListSpinner.getSelectedCountryInfo()).getCountryCode()));
- }
-
- @Test
- public void testDefaultCountryCodeAndNationalNumber_prePopulatesPhoneNumberInBundle() {
- Bundle phoneParams = new Bundle();
- phoneParams.putString(ExtraConstants.COUNTRY_ISO, CA_ISO2);
- phoneParams.putString(ExtraConstants.NATIONAL_NUMBER, PHONE_NO_COUNTRY_CODE);
- Intent startIntent = PhoneActivity.createIntent(
- RuntimeEnvironment.application,
- TestHelper.getFlowParameters(
- Collections.singletonList(PhoneAuthProvider.PROVIDER_ID)),
- phoneParams);
-
- mActivity = Robolectric.buildActivity(PhoneActivity.class, startIntent)
- .create(new Bundle()).start().visible().get();
-
- VerifyPhoneNumberFragment verifyPhoneNumberFragment = (VerifyPhoneNumberFragment)
- mActivity.getSupportFragmentManager()
- .findFragmentByTag(VerifyPhoneNumberFragment.TAG);
- assertNotNull(verifyPhoneNumberFragment);
- mPhoneEditText = mActivity.findViewById(R.id.phone_number);
- mCountryListSpinner = mActivity.findViewById(R.id.country_list);
-
- assertEquals(PHONE_NO_COUNTRY_CODE, mPhoneEditText.getText().toString());
- assertEquals(CA_COUNTRY_CODE,
- String.valueOf((mCountryListSpinner.getSelectedCountryInfo()).getCountryCode()));
- assertEquals(new Locale("", CA_ISO2),
- ((CountryInfo) mCountryListSpinner.getSelectedCountryInfo()).getLocale());
- }
-
- @Test
- public void testBadPhoneNumber_showsInlineError() {
- VerifyPhoneNumberFragment verifyPhoneNumberFragment = (VerifyPhoneNumberFragment)
- mActivity.getSupportFragmentManager()
- .findFragmentByTag(VerifyPhoneNumberFragment.TAG);
- assertNotNull(verifyPhoneNumberFragment);
-
- mSendCodeButton.performClick();
- assertEquals(mPhoneLayout.getError(), mActivity.getString(R.string.fui_invalid_phone_number));
-
- mCountryListSpinner.performClick();
- assertNull(mPhoneLayout.getError());
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testVerifyPhoneNumberInvalidPhoneException_showsInlineError() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
-
- mActivity.verifyPhoneNumber(PHONE, false);
- //was dialog displayed
- assertEquals(
- mActivity.getString(R.string.fui_verifying),
- mActivity.mProgressDialog.mMessageView.getText());
-
- //was upstream method invoked
- verify(AuthHelperShadow.getPhoneAuthProvider()).verifyPhoneNumber(
- eq(PHONE),
- eq(AUTO_RETRIEVAL_TIMEOUT_MILLIS),
- eq(TimeUnit.MILLISECONDS),
- eq(mActivity),
- callbacksArgumentCaptor.capture(),
- (PhoneAuthProvider.ForceResendingToken) isNull());
-
- PhoneAuthProvider.OnVerificationStateChangedCallbacks onVerificationStateChangedCallbacks
- = callbacksArgumentCaptor.getValue();
- onVerificationStateChangedCallbacks.onVerificationFailed(
- new FirebaseAuthException(
- FirebaseAuthError.ERROR_INVALID_PHONE_NUMBER.toString(),
- "any_message"));
-
- //was error displayed
- assertEquals(mPhoneLayout.getError(), mActivity.getString(R.string.fui_invalid_phone_number));
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testVerifyPhoneNumberNoMsgException_showsAlertDialog() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
-
- mActivity.verifyPhoneNumber(PHONE, false);
- verify(AuthHelperShadow.getPhoneAuthProvider()).verifyPhoneNumber(
- eq(PHONE),
- eq(AUTO_RETRIEVAL_TIMEOUT_MILLIS),
- eq(TimeUnit.MILLISECONDS),
- eq(mActivity),
- callbacksArgumentCaptor.capture(),
- (PhoneAuthProvider.ForceResendingToken) isNull());
-
- PhoneAuthProvider.OnVerificationStateChangedCallbacks onVerificationStateChangedCallbacks
- = callbacksArgumentCaptor.getValue();
-
- onVerificationStateChangedCallbacks.onVerificationFailed(
- new FirebaseAuthException("some_code", "custom_message"));
- assertTrue(mActivity.getAlertDialog().isShowing());
- assertEquals(RuntimeEnvironment.application.getString(R.string.fui_error_unknown),
- getAlertDialogMessage());
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testVerifyPhoneNumber_success() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
- testSendConfirmationCode();
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testSubmitCode_badCodeShowsAlertDialog() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
- when(AuthHelperShadow.getFirebaseAuth().signInWithCredential(any(AuthCredential.class)))
- .thenReturn(new AutoCompleteTask(
- null, true,
- new FirebaseAuthInvalidCredentialsException(
- FirebaseAuthError.ERROR_INVALID_VERIFICATION_CODE.toString(),
- "any_msg")));
- testSendConfirmationCode();
- SpacedEditText mConfirmationCodeEditText = mActivity.findViewById(R.id.confirmation_code);
- Button mSubmitConfirmationButton = mActivity.findViewById(R.id.submit_confirmation_code);
-
- mConfirmationCodeEditText.setText("123456");
- mSubmitConfirmationButton.performClick();
- assertEquals(mActivity.getString(R.string.fui_incorrect_code_dialog_body),
- getAlertDialogMessage());
-
- //test bad code cleared on clicking OK in alert
- android.support.v7.app.AlertDialog a = mActivity.getAlertDialog();
- Button ok = a.findViewById(android.R.id.button1);
- ok.performClick();
- assertEquals("- - - - - -", mConfirmationCodeEditText.getText().toString());
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testresendCode_invokesUpstream() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
- testSendConfirmationCode();
-
- //test resend code invisible
- TextView r = mActivity.findViewById(R.id.resend_code);
- assertEquals(View.GONE, r.getVisibility());
-
- //assert resend visible after timeout
- SubmitConfirmationCodeFragment fragment = (SubmitConfirmationCodeFragment) mActivity
- .getSupportFragmentManager().findFragmentByTag(SubmitConfirmationCodeFragment.TAG);
- fragment.getCountdownTimer().onFinish();
- assertEquals(View.VISIBLE, r.getVisibility());
- r.performClick();
-
- //assert resend invisible
- assertEquals(View.GONE, r.getVisibility());
-
- //verify resend code was called
- verify(AuthHelperShadow.getPhoneAuthProvider()).verifyPhoneNumber(
- eq(PHONE),
- eq(AUTO_RETRIEVAL_TIMEOUT_MILLIS),
- eq(TimeUnit.MILLISECONDS),
- eq(mActivity),
- callbacksArgumentCaptor.capture(),
- eq(forceResendingToken));
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testAutoVerify() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
- reset(AuthHelperShadow.getFirebaseAuth());
-
- when(AuthHelperShadow.getCurrentUser().getPhoneNumber()).thenReturn(PHONE);
- when(AuthHelperShadow.getCurrentUser().getEmail()).thenReturn(null);
- when(AuthHelperShadow.getFirebaseAuth().signInWithCredential(any(AuthCredential.class)))
- .thenReturn(new AutoCompleteTask<>(FakeAuthResult.INSTANCE, true, null));
- mActivity.verifyPhoneNumber(PHONE, false);
- verify(AuthHelperShadow.getPhoneAuthProvider()).verifyPhoneNumber(
- eq(PHONE),
- eq(AUTO_RETRIEVAL_TIMEOUT_MILLIS),
- eq(TimeUnit.MILLISECONDS),
- eq(mActivity),
- callbacksArgumentCaptor.capture(),
- (PhoneAuthProvider.ForceResendingToken) isNull());
-
- PhoneAuthProvider.OnVerificationStateChangedCallbacks onVerificationStateChangedCallbacks
- = callbacksArgumentCaptor.getValue();
-
- onVerificationStateChangedCallbacks.onVerificationCompleted(credential);
- verify(AuthHelperShadow.getFirebaseAuth()).signInWithCredential(any(AuthCredential.class));
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testSMSAutoRetrieval() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
- when(credential.getSmsCode()).thenReturn("123456");
-
- when(AuthHelperShadow.getCurrentUser().getPhoneNumber()).thenReturn(PHONE);
- when(AuthHelperShadow.getCurrentUser().getEmail()).thenReturn(null);
-
- when(AuthHelperShadow.getFirebaseAuth().signInWithCredential(any(AuthCredential.class)))
- .thenReturn(new AutoCompleteTask<>(FakeAuthResult.INSTANCE, true, null));
- PhoneAuthProvider.OnVerificationStateChangedCallbacks callbacks =
- testSendConfirmationCode();
- callbacks.onVerificationCompleted(credential);
- SpacedEditText mConfirmationCodeEditText = mActivity.findViewById(R.id.confirmation_code);
-
- //verify confirmation code set
- assertEquals("1 2 3 4 5 6", mConfirmationCodeEditText.getText().toString());
- //verify credential saves
- verify(AuthHelperShadow.getFirebaseAuth()).signInWithCredential(credential);
- }
-
- @Test
- @Config(shadows = {AuthHelperShadow.class})
- public void testEditPhoneNumber_togglesFragments() {
- reset(AuthHelperShadow.getPhoneAuthProvider());
- testSendConfirmationCode();
- TextView mEditPhoneTextView = mActivity.findViewById(R.id.edit_phone_number);
- mEditPhoneTextView.performClick();
- VerifyPhoneNumberFragment verifyPhoneNumberFragment = (VerifyPhoneNumberFragment)
- mActivity.getSupportFragmentManager()
- .findFragmentByTag(VerifyPhoneNumberFragment.TAG);
- SubmitConfirmationCodeFragment submitConfirmationCodeFragment =
- (SubmitConfirmationCodeFragment) mActivity.getSupportFragmentManager()
- .findFragmentByTag(SubmitConfirmationCodeFragment.TAG);
-
- assertNotNull(verifyPhoneNumberFragment);
-
- assertNull(submitConfirmationCodeFragment);
- }
-
- private PhoneAuthProvider.OnVerificationStateChangedCallbacks testSendConfirmationCode() {
- mActivity.verifyPhoneNumber(PHONE, false);
- verify(AuthHelperShadow.getPhoneAuthProvider()).verifyPhoneNumber(
- eq(PHONE),
- eq(AUTO_RETRIEVAL_TIMEOUT_MILLIS),
- eq(TimeUnit.MILLISECONDS),
- eq(mActivity),
- callbacksArgumentCaptor.capture(),
- (PhoneAuthProvider.ForceResendingToken) isNull());
-
- PhoneAuthProvider.OnVerificationStateChangedCallbacks onVerificationStateChangedCallbacks
- = callbacksArgumentCaptor.getValue();
-
- onVerificationStateChangedCallbacks.onCodeSent(verificationId, forceResendingToken);
-
- //Force postDelayed runnables to completed on looper
- ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
-
- SubmitConfirmationCodeFragment fragment = (SubmitConfirmationCodeFragment) mActivity
- .getSupportFragmentManager().findFragmentByTag(SubmitConfirmationCodeFragment.TAG);
- assertNotNull(fragment);
-
- SpacedEditText mConfirmationCodeEditText = mActivity
- .findViewById(R.id.confirmation_code);
- assertTrue(mConfirmationCodeEditText.isFocused());
-
- return onVerificationStateChangedCallbacks;
- }
-
- private String getAlertDialogMessage() {
- android.support.v7.app.AlertDialog a = mActivity.getAlertDialog();
- assertTrue(a.isShowing());
- return ((TextView) (a.findViewById(android.R.id.message))).getText().toString();
- }
-}
diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneTestConstants.java b/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneTestConstants.java
index a845c90fe..25cea931e 100644
--- a/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneTestConstants.java
+++ b/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneTestConstants.java
@@ -24,8 +24,6 @@ public class PhoneTestConstants {
public static final String PHONE_NO_COUNTRY_CODE = "23456789";
public static final String US_COUNTRY_CODE = "1";
public static final String US_ISO2 = "US";
- public static final String CA_ISO2 = "CA";
- public static final String CA_COUNTRY_CODE = "1";
public static final String YE_COUNTRY_CODE = "967";
public static final String YE_ISO2 = "YE";
}
diff --git a/auth/src/test/java/com/firebase/ui/auth/viewmodel/LinkingSocialProviderResponseHandlerTest.java b/auth/src/test/java/com/firebase/ui/auth/viewmodel/LinkingSocialProviderResponseHandlerTest.java
new file mode 100644
index 000000000..068f9c38a
--- /dev/null
+++ b/auth/src/test/java/com/firebase/ui/auth/viewmodel/LinkingSocialProviderResponseHandlerTest.java
@@ -0,0 +1,249 @@
+package com.firebase.ui.auth.viewmodel;
+
+import android.arch.lifecycle.Observer;
+
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.data.model.FlowParameters;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.data.model.User;
+import com.firebase.ui.auth.testhelpers.AutoCompleteTask;
+import com.firebase.ui.auth.testhelpers.AutoContinueTask;
+import com.firebase.ui.auth.testhelpers.FakeAuthResult;
+import com.firebase.ui.auth.testhelpers.ResourceMatchers;
+import com.firebase.ui.auth.testhelpers.TestConstants;
+import com.firebase.ui.auth.testhelpers.TestHelper;
+import com.firebase.ui.auth.util.data.AuthOperationManager;
+import com.firebase.ui.auth.util.data.ProviderUtils;
+import com.firebase.ui.auth.viewmodel.idp.LinkingSocialProviderResponseHandler;
+import com.google.firebase.auth.AuthCredential;
+import com.google.firebase.auth.FacebookAuthProvider;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.auth.GoogleAuthCredential;
+import com.google.firebase.auth.GoogleAuthProvider;
+import com.google.firebase.auth.PhoneAuthCredential;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit tests for {@link LinkingSocialProviderResponseHandler}.
+ *
+ * This handler is used by WelcomeBackIdpPrompt. This prompt handles the case where a user attempts
+ * to log in with an IDP, but there is a user that has a different IDP with the same email.
+ *
+ * In this case, the handler will link the provider to the existing firebase user. When the user
+ * is anonymous, a triple linking case occurs.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class LinkingSocialProviderResponseHandlerTest {
+
+ @Mock FirebaseAuth mMockAuth;
+ @Mock FirebaseAuth mScratchMockAuth;
+
+ @Mock FirebaseUser mMockUser;
+ @Mock PhoneAuthCredential mCredential;
+ @Mock Observer> mResponseObserver;
+
+ private LinkingSocialProviderResponseHandler mHandler;
+
+
+ @Before
+ public void setUp() {
+ TestHelper.initialize();
+ MockitoAnnotations.initMocks(this);
+
+ mHandler = new LinkingSocialProviderResponseHandler(RuntimeEnvironment.application);
+ FlowParameters testParams = TestHelper.getFlowParameters(Collections.singletonList(
+ GoogleAuthProvider.PROVIDER_ID));
+ mHandler.initializeForTesting(testParams, mMockAuth, null, null);
+ }
+
+ @Test
+ public void testSignIn_withSameIdp_expectSuccess() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+
+ // Fake social response from Google
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .setToken(TestConstants.TOKEN)
+ .build();
+
+ when(mMockAuth.signInWithCredential(any(AuthCredential.class)))
+ .thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
+
+ mHandler.startSignIn(response);
+
+ verify(mMockAuth).signInWithCredential(any(GoogleAuthCredential.class));
+
+ InOrder inOrder = inOrder(mResponseObserver);
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isLoading()));
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isSuccess()));
+ }
+
+
+ @Test
+ public void testSignIn_anonymousUpgradeEnabledWithSameIdp_expectMergeFailure() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+ setupAnonymousUpgrade();
+
+ // Fake social response from Google
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .setToken(TestConstants.TOKEN)
+ .build();
+
+ mHandler.startSignIn(response);
+
+ // Since we are signing in with the same IDP and anonymous upgrade is enabled, a merge
+ // failure should occur without any RPC calls
+
+ AuthCredential credential = GoogleAuthProvider.getCredential(TestConstants.TOKEN, null);
+
+ InOrder inOrder = inOrder(mResponseObserver);
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isLoading()));
+
+ ArgumentCaptor> resolveCaptor =
+ ArgumentCaptor.forClass(Resource.class);
+ inOrder.verify(mResponseObserver).onChanged(resolveCaptor.capture());
+
+ FirebaseAuthAnonymousUpgradeException e =
+ (FirebaseAuthAnonymousUpgradeException) resolveCaptor.getValue().getException();
+
+ GoogleAuthCredential responseCredential =
+ (GoogleAuthCredential) e.getResponse().getCredentialForLinking();
+
+ assertThat(responseCredential.getProvider()).isEqualTo(credential.getProvider());
+ assertThat(responseCredential.getSignInMethod()).isEqualTo(credential.getSignInMethod());
+
+ }
+
+ @Test
+ public void testSignIn_withDifferentIdp_expectSuccess() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+
+ // We're going to fake a sign in with facebook, where the email belongs
+ // to an existing account with a Google provider.
+
+ // Fake social response from Google
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .setToken(TestConstants.TOKEN)
+ .build();
+
+ // Set facebook credential
+ AuthCredential facebookAuthCredential =
+ FacebookAuthProvider.getCredential(TestConstants.TOKEN);
+ mHandler.setRequestedSignInCredentialForEmail(facebookAuthCredential, TestConstants.EMAIL);
+
+
+ // mock sign in with Google credential to always work
+ when(mMockAuth.signInWithCredential(any(GoogleAuthCredential.class)))
+ .thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
+
+ // Mock linking with Facebook to always work
+ when(FakeAuthResult.INSTANCE.getUser().linkWithCredential(facebookAuthCredential))
+ .thenReturn(new AutoContinueTask<>(FakeAuthResult.INSTANCE,
+ FakeAuthResult.INSTANCE,
+ true,
+ null));
+
+ mHandler.startSignIn(response);
+
+ verify(mMockAuth).signInWithCredential(any(GoogleAuthCredential.class));
+ verify(FakeAuthResult.INSTANCE.getUser()).linkWithCredential(facebookAuthCredential);
+
+ InOrder inOrder = inOrder(mResponseObserver);
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isLoading()));
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isSuccess()));
+ }
+
+ @Test
+ public void testSignIn_anonymousUpgradeEnabledWithDifferentIdp_expectMergeFailure() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+ setupAnonymousUpgrade();
+
+ // We're going to fake a sign in with facebook, where the email belongs
+ // to an existing account with a Google provider.
+ // We need to link Facebook to this account, and then a merge failure should occur
+ // so that the developer can handle it.
+ // Before we can link, they need to sign in with Google to prove they own the account.
+
+ // Fake social response from Google
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .setToken(TestConstants.TOKEN)
+ .build();
+
+ // Set facebook credential
+ AuthCredential facebookAuthCredential =
+ FacebookAuthProvider.getCredential(TestConstants.TOKEN);
+ mHandler.setRequestedSignInCredentialForEmail(facebookAuthCredential, TestConstants.EMAIL);
+
+ when(mScratchMockAuth.signInWithCredential(any(GoogleAuthCredential.class)))
+ .thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
+
+ // Mock linking with Facebook to always work
+ when(FakeAuthResult.INSTANCE.getUser().linkWithCredential(facebookAuthCredential))
+ .thenReturn(new AutoContinueTask<>(FakeAuthResult.INSTANCE,
+ FakeAuthResult.INSTANCE,
+ true,
+ null));
+
+ mHandler.startSignIn(response);
+
+ verify(mScratchMockAuth).signInWithCredential(any(GoogleAuthCredential.class));
+ verify(FakeAuthResult.INSTANCE.getUser()).linkWithCredential(facebookAuthCredential);
+
+ InOrder inOrder = inOrder(mResponseObserver);
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isLoading()));
+
+ ArgumentCaptor> resolveCaptor =
+ ArgumentCaptor.forClass(Resource.class);
+ inOrder.verify(mResponseObserver).onChanged(resolveCaptor.capture());
+
+ // Merge failure should occur after successful linking
+ FirebaseAuthAnonymousUpgradeException e =
+ (FirebaseAuthAnonymousUpgradeException) resolveCaptor.getValue().getException();
+
+ AuthCredential credential = ProviderUtils.getAuthCredential(response);
+ GoogleAuthCredential responseCredential =
+ (GoogleAuthCredential) e.getResponse().getCredentialForLinking();
+
+ assertThat(responseCredential.getProvider()).isEqualTo(credential.getProvider());
+ assertThat(responseCredential.getSignInMethod()).isEqualTo(credential.getSignInMethod());
+
+ }
+
+ private void setupAnonymousUpgrade() {
+ FlowParameters testParams = TestHelper.getFlowParameters(Collections.singletonList(
+ GoogleAuthProvider.PROVIDER_ID), true);
+ mHandler.initializeForTesting(testParams, mMockAuth, null, null);
+ when(mMockAuth.getCurrentUser()).thenReturn(mMockUser);
+ when(mMockUser.isAnonymous()).thenReturn(true);
+ AuthOperationManager.getInstance().mScratchAuth = mScratchMockAuth;
+ }
+}
diff --git a/auth/src/test/java/com/firebase/ui/auth/viewmodel/PhoneProviderResponseHandlerTest.java b/auth/src/test/java/com/firebase/ui/auth/viewmodel/PhoneProviderResponseHandlerTest.java
new file mode 100644
index 000000000..dd55f1937
--- /dev/null
+++ b/auth/src/test/java/com/firebase/ui/auth/viewmodel/PhoneProviderResponseHandlerTest.java
@@ -0,0 +1,140 @@
+package com.firebase.ui.auth.viewmodel;
+
+
+import android.arch.lifecycle.Observer;
+
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
+import com.firebase.ui.auth.IdpResponse;
+import com.firebase.ui.auth.data.model.FlowParameters;
+import com.firebase.ui.auth.data.model.Resource;
+import com.firebase.ui.auth.data.model.User;
+import com.firebase.ui.auth.testhelpers.AutoCompleteTask;
+import com.firebase.ui.auth.testhelpers.FakeAuthResult;
+import com.firebase.ui.auth.testhelpers.ResourceMatchers;
+import com.firebase.ui.auth.testhelpers.TestConstants;
+import com.firebase.ui.auth.testhelpers.TestHelper;
+import com.firebase.ui.auth.viewmodel.phone.PhoneProviderResponseHandler;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseAuthUserCollisionException;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.auth.GoogleAuthCredential;
+import com.google.firebase.auth.PhoneAuthCredential;
+import com.google.firebase.auth.PhoneAuthProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit tests for {@link PhoneProviderResponseHandler}.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class PhoneProviderResponseHandlerTest {
+
+ @Mock FirebaseAuth mMockAuth;
+ @Mock FirebaseUser mMockUser;
+ @Mock PhoneAuthCredential mCredential;
+ @Mock Observer> mResponseObserver;
+
+ private PhoneProviderResponseHandler mHandler;
+
+ @Before
+ public void setUp() {
+ TestHelper.initialize();
+ MockitoAnnotations.initMocks(this);
+
+ mHandler = new PhoneProviderResponseHandler(RuntimeEnvironment.application);
+ FlowParameters testParams = TestHelper.getFlowParameters(Collections.singletonList(
+ PhoneAuthProvider.PROVIDER_ID));
+ mHandler.initializeForTesting(testParams, mMockAuth, null, null);
+ }
+
+ @Test
+ public void testSignIn_withValidCredentialAndNewUser_expectSuccess() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+
+ when(mMockAuth.signInWithCredential(mCredential))
+ .thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
+
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ PhoneAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .build();
+
+ mHandler.startSignIn(mCredential, response);
+ verify(mMockAuth).signInWithCredential(mCredential);
+ verify(mResponseObserver).onChanged(argThat(ResourceMatchers.isSuccess()));
+ }
+
+ @Test
+ public void testSignIn_autoUpgradeAnonymousEnabledWithNewUser_expectSuccess() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+ setupAnonymousUpgrade();
+
+ when(mMockAuth.getCurrentUser().linkWithCredential(mCredential))
+ .thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
+
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ PhoneAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .build();
+
+ mHandler.startSignIn(mCredential, response);
+
+ verify(mMockAuth.getCurrentUser()).linkWithCredential(mCredential);
+ verify(mResponseObserver).onChanged(argThat(ResourceMatchers.isSuccess()));
+ }
+
+
+ @Test
+ public void testSignIn_autoUpgradeAnonymousEnabledWithExistingUser_expectMergeFailure() {
+ mHandler.getOperation().observeForever(mResponseObserver);
+ setupAnonymousUpgrade();
+
+ when(mMockAuth.getCurrentUser().linkWithCredential(mCredential))
+ .thenReturn(AutoCompleteTask.forFailure(
+ new FirebaseAuthUserCollisionException("foo", "bar", mCredential)));
+
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ PhoneAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .build();
+
+ mHandler.startSignIn(mCredential, response);
+
+ verify(mMockAuth.getCurrentUser()).linkWithCredential(mCredential);
+
+ InOrder inOrder = inOrder(mResponseObserver);
+ inOrder.verify(mResponseObserver)
+ .onChanged(argThat(ResourceMatchers.isLoading()));
+
+ ArgumentCaptor> resolveCaptor =
+ ArgumentCaptor.forClass(Resource.class);
+ inOrder.verify(mResponseObserver).onChanged(resolveCaptor.capture());
+
+ FirebaseAuthAnonymousUpgradeException e =
+ (FirebaseAuthAnonymousUpgradeException) resolveCaptor.getValue().getException();
+
+ assertThat(e.getResponse().getCredentialForLinking()).isNotNull();
+ }
+
+ private void setupAnonymousUpgrade() {
+ FlowParameters testParams = TestHelper.getFlowParameters(Collections.singletonList(
+ PhoneAuthProvider.PROVIDER_ID), true);
+ mHandler.initializeForTesting(testParams, mMockAuth, null, null);
+ when(mMockAuth.getCurrentUser()).thenReturn(mMockUser);
+ when(mMockUser.isAnonymous()).thenReturn(true);
+ }
+}
diff --git a/auth/src/test/java/com/firebase/ui/auth/viewmodel/SocialProviderResponseHandlerTest.java b/auth/src/test/java/com/firebase/ui/auth/viewmodel/SocialProviderResponseHandlerTest.java
index e5f1348b6..36bf76bee 100644
--- a/auth/src/test/java/com/firebase/ui/auth/viewmodel/SocialProviderResponseHandlerTest.java
+++ b/auth/src/test/java/com/firebase/ui/auth/viewmodel/SocialProviderResponseHandlerTest.java
@@ -4,6 +4,7 @@
import android.arch.lifecycle.Observer;
import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.FirebaseAuthAnonymousUpgradeException;
import com.firebase.ui.auth.IdpResponse;
import com.firebase.ui.auth.data.model.FlowParameters;
import com.firebase.ui.auth.data.model.IntentRequiredException;
@@ -15,6 +16,8 @@
import com.firebase.ui.auth.testhelpers.ResourceMatchers;
import com.firebase.ui.auth.testhelpers.TestConstants;
import com.firebase.ui.auth.testhelpers.TestHelper;
+import com.firebase.ui.auth.ui.email.WelcomeBackPasswordPrompt;
+import com.firebase.ui.auth.ui.idp.WelcomeBackIdpPrompt;
import com.firebase.ui.auth.viewmodel.idp.SocialProviderResponseHandler;
import com.firebase.ui.auth.viewmodel.smartlock.SmartLockHandler;
import com.google.firebase.auth.AuthCredential;
@@ -23,9 +26,9 @@
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
+import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.SignInMethodQueryResult;
-import com.google.firebase.auth.UserProfileChangeRequest;
import org.junit.Before;
import org.junit.Test;
@@ -37,8 +40,10 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.Arrays;
import java.util.Collections;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.inOrder;
@@ -51,6 +56,7 @@
@RunWith(RobolectricTestRunner.class)
public class SocialProviderResponseHandlerTest {
@Mock FirebaseAuth mMockAuth;
+ @Mock FirebaseUser mUser;
@Mock Observer> mResultObserver;
private SocialProviderResponseHandler mHandler;
@@ -73,8 +79,6 @@ public void testSignInIdp_success() {
when(mMockAuth.signInWithCredential(any(AuthCredential.class)))
.thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
- when(FakeAuthResult.INSTANCE.getUser().updateProfile(any(UserProfileChangeRequest.class)))
- .thenReturn(AutoCompleteTask.forSuccess(null));
IdpResponse response = new IdpResponse.Builder(new User.Builder(
GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
@@ -83,8 +87,9 @@ public void testSignInIdp_success() {
mHandler.startSignIn(response);
- InOrder inOrder = inOrder(mResultObserver);
+ verify(mMockAuth).signInWithCredential(any(AuthCredential.class));
+ InOrder inOrder = inOrder(mResultObserver);
inOrder.verify(mResultObserver)
.onChanged(argThat(ResourceMatchers.isLoading()));
inOrder.verify(mResultObserver)
@@ -132,8 +137,10 @@ public void testSignInIdp_resolution() {
mHandler.startSignIn(response);
- InOrder inOrder = inOrder(mResultObserver);
+ verify(mMockAuth).signInWithCredential(any(AuthCredential.class));
+ verify(mMockAuth).fetchSignInMethodsForEmail(any(String.class));
+ InOrder inOrder = inOrder(mResultObserver);
inOrder.verify(mResultObserver)
.onChanged(argThat(ResourceMatchers.isLoading()));
@@ -150,4 +157,166 @@ public void testSignInIdp_resolution() {
inOrder.verify(mResultObserver)
.onChanged(argThat(ResourceMatchers.isSuccess()));
}
+
+
+ @Test
+ public void testSignInIdp_anonymousUserUpgradeEnabledAndNewUser_expectSuccess() {
+ mHandler.getOperation().observeForever(mResultObserver);
+ setupAnonymousUpgrade();
+
+ when(mMockAuth.getCurrentUser().linkWithCredential(any(AuthCredential.class)))
+ .thenReturn(AutoCompleteTask.forSuccess(FakeAuthResult.INSTANCE));
+
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .setToken(TestConstants.TOKEN)
+ .build();
+
+ mHandler.startSignIn(response);
+
+ verify(mMockAuth.getCurrentUser()).linkWithCredential(any(AuthCredential.class));
+
+ InOrder inOrder = inOrder(mResultObserver);
+ inOrder.verify(mResultObserver)
+ .onChanged(argThat(ResourceMatchers.isLoading()));
+ inOrder.verify(mResultObserver)
+ .onChanged(argThat(ResourceMatchers.isSuccess()));
+ }
+
+ @Test
+ public void testSignInIdp_anonymousUserUpgradeEnabledAndExistingUserWithSameIdp_expectMergeFailure() {
+ mHandler.getOperation().observeForever(mResultObserver);
+ setupAnonymousUpgrade();
+
+ when(mMockAuth.getCurrentUser().linkWithCredential(any(AuthCredential.class)))
+ .thenReturn(AutoCompleteTask.forFailure(
+ new FirebaseAuthUserCollisionException("foo", "bar")));
+
+ // Case 1: Anon user signing in with a Google credential that belongs to an existing user.
+ when(mMockAuth.fetchSignInMethodsForEmail(any(String.class)))
+ .thenReturn(AutoCompleteTask.forSuccess(
+ new FakeSignInMethodQueryResult(Arrays.asList(
+ GoogleAuthProvider.GOOGLE_SIGN_IN_METHOD,
+ FacebookAuthProvider.FACEBOOK_SIGN_IN_METHOD))));
+
+
+ IdpResponse response = new IdpResponse.Builder(new User.Builder(
+ GoogleAuthProvider.PROVIDER_ID, TestConstants.EMAIL).build())
+ .setToken(TestConstants.TOKEN)
+ .build();
+
+ mHandler.startSignIn(response);
+
+ verify(mMockAuth.getCurrentUser()).linkWithCredential(any(AuthCredential.class));
+
+ InOrder inOrder = inOrder(mResultObserver);
+ inOrder.verify(mResultObserver)
+ .onChanged(argThat(ResourceMatchers.