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 c5fab10b3..728a3ee22 100644 --- a/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java +++ b/app/src/main/java/com/firebase/uidemo/auth/AuthUiActivity.java @@ -33,6 +33,8 @@ import com.google.firebase.auth.FirebaseAuth; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; @@ -69,6 +71,9 @@ public class AuthUiActivity extends AppCompatActivity { @BindView(R.id.facebook_provider) CheckBox mUseFacebookProvider; + @BindView(R.id.twitter_provider) + CheckBox mUseTwitterProvider; + @BindView(R.id.google_tos) RadioButton mUseGoogleTos; @@ -118,9 +123,16 @@ public void onCreate(Bundle savedInstanceState) { mUseFacebookProvider.setText(R.string.facebook_label_missing_config); } - if (!isGoogleConfigured() || !isFacebookConfigured()) { + if (!isTwitterConfigured()) { + mUseTwitterProvider.setChecked(false); + mUseTwitterProvider.setEnabled(false); + mUseTwitterProvider.setText(R.string.twitter_label_missing_config); + } + + if (!isGoogleConfigured() || !isFacebookConfigured() || !isTwitterConfigured()) { showSnackbar(R.string.configuration_required); } + } @OnClick(R.id.sign_in) @@ -204,6 +216,10 @@ private String[] getSelectedProviders() { selectedProviders.add(AuthUI.GOOGLE_PROVIDER); } + if (mUseTwitterProvider.isChecked()) { + selectedProviders.add(AuthUI.TWITTER_PROVIDER); + } + return selectedProviders.toArray(new String[selectedProviders.size()]); } @@ -228,6 +244,16 @@ private boolean isFacebookConfigured() { getResources().getString(R.string.facebook_application_id)); } + @MainThread + private boolean isTwitterConfigured() { + List twitterConfigs = Arrays.asList( + getResources().getString(R.string.twitter_consumer_key), + getResources().getString(R.string.twitter_consumer_secret) + ); + + return !twitterConfigs.contains(UNCHANGED_CONFIG_VALUE); + } + @MainThread private void showSnackbar(@StringRes int errorMessageRes) { Snackbar.make(mRootView, errorMessageRes, Snackbar.LENGTH_LONG).show(); diff --git a/app/src/main/res/layout/auth_ui_layout.xml b/app/src/main/res/layout/auth_ui_layout.xml index 19d28303a..f579da0ab 100644 --- a/app/src/main/res/layout/auth_ui_layout.xml +++ b/app/src/main/res/layout/auth_ui_layout.xml @@ -91,6 +91,12 @@ android:layout_height="wrap_content" android:text="@string/google_label" /> + + fbYOUR_APP_ID + + + + + CHANGE-ME + + + CHANGE-ME diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a654d6373..fb3c0dd8e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,6 +22,8 @@ Email Facebook Facebook - configuration missing + Twitter + Twitter - configuration missing Google Google - configuration missing Google TOS diff --git a/auth/README.md b/auth/README.md index 9aad39fde..06ad5faed 100644 --- a/auth/README.md +++ b/auth/README.md @@ -60,7 +60,7 @@ If instead your project uses Maven, add: ### Identity provider configuration -In order to use either Google or Facebook accounts with your app, ensure that +In order to use either Google, Facebook or Twitter accounts with your app, ensure that these authentication methods are first configured in the Firebase console. FirebaseUI client-side configuration for Google sign-in is then provided @@ -77,6 +77,18 @@ the [Facebook developer dashboard](https://developers.facebook.com): ``` +If support for Twitter Sign-in is also required, define the resource strings +twitter_consumer_key and twitter_consumer_secret to match the values of your Twitter app as +reported by the [Twitter application manager](https://dev.twitter.com/apps). + +``` + + YOURCONSUMERKEY + YOURCONSUMERSECRET + + +``` + ## Using FirebaseUI for Authentication Before invoking the FirebaseUI authentication flow, your app should check diff --git a/auth/build.gradle b/auth/build.gradle index 34e573514..0a473566c 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.library' apply plugin: 'checkstyle' +apply plugin: 'io.fabric' android { compileSdkVersion project.ext.compileSdk @@ -34,6 +35,9 @@ dependencies { testCompile "org.robolectric:robolectric:3.1.1" compile "com.android.support:appcompat-v7:${project.ext.support_library_version}" compile 'com.facebook.android:facebook-android-sdk:4.14.1' + compile("com.twitter.sdk.android:twitter:2.0.0@aar") { + transitive = true; + } compile "com.android.support:design:${project.ext.support_library_version}" compile "com.google.firebase:firebase-auth:${project.ext.firebase_version}" diff --git a/auth/src/main/AndroidManifest.xml b/auth/src/main/AndroidManifest.xml index 73cef5519..967e46ed4 100644 --- a/auth/src/main/AndroidManifest.xml +++ b/auth/src/main/AndroidManifest.xml @@ -79,6 +79,5 @@ - diff --git a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java index 3192443ee..46c245ee1 100644 --- a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java +++ b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java @@ -230,6 +230,11 @@ public class AuthUI { */ public static final String FACEBOOK_PROVIDER = "facebook"; + /** + * Provider identifier for Twitter, for use with {@link SignInIntentBuilder#setProviders}. + */ + public static final String TWITTER_PROVIDER = "twitter"; + /** * Default value for logo resource, omits the logo from the * {@link AuthMethodPickerActivity} @@ -243,7 +248,8 @@ public class AuthUI { Collections.unmodifiableSet(new HashSet<>(Arrays.asList( EMAIL_PROVIDER, GOOGLE_PROVIDER, - FACEBOOK_PROVIDER + FACEBOOK_PROVIDER, + TWITTER_PROVIDER ))); private static final IdentityHashMap INSTANCES = new IdentityHashMap<>(); diff --git a/auth/src/main/java/com/firebase/ui/auth/provider/TwitterProvider.java b/auth/src/main/java/com/firebase/ui/auth/provider/TwitterProvider.java new file mode 100644 index 000000000..33a48b8ab --- /dev/null +++ b/auth/src/main/java/com/firebase/ui/auth/provider/TwitterProvider.java @@ -0,0 +1,96 @@ +package com.firebase.ui.auth.provider; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.firebase.ui.auth.R; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.TwitterAuthProvider; +import com.twitter.sdk.android.Twitter; +import com.twitter.sdk.android.core.Callback; +import com.twitter.sdk.android.core.Result; +import com.twitter.sdk.android.core.TwitterAuthConfig; +import com.twitter.sdk.android.core.TwitterException; +import com.twitter.sdk.android.core.TwitterSession; +import com.twitter.sdk.android.core.identity.TwitterAuthClient; + +import io.fabric.sdk.android.Fabric; + +public class TwitterProvider extends Callback implements IDPProvider { + public static final String EXTRA_AUTH_TOKEN = "extra_auth_token"; + public static final String EXTRA_AUTH_SECRET = "extra_auth_secret"; + private static final String EXTRA_CONSUMER_KEY = "extra_consumer_key"; + private static final String EXTRA_CONSUMER_SECRET = "extra_consumer_secret"; + private IDPCallback mCallbackObject; + private TwitterAuthClient mTwitterAuthClient; + + public TwitterProvider(Context appContext, IDPProviderParcel twitterParcel) { + TwitterAuthConfig authConfig = new TwitterAuthConfig( + appContext.getString(R.string.twitter_consumer_key), + appContext.getString(R.string.twitter_consumer_secret)); + Fabric.with(appContext, new Twitter(authConfig)); + mTwitterAuthClient = new TwitterAuthClient(); + } + + public static IDPProviderParcel createTwitterParcel(String consumerKey, String consumerSecret) { + Bundle extra = new Bundle(); + extra.putString(EXTRA_CONSUMER_KEY, consumerKey); + extra.putString(EXTRA_CONSUMER_SECRET, consumerSecret); + return new IDPProviderParcel(TwitterAuthProvider.PROVIDER_ID, extra); + } + + @Override + public String getName(Context context) { + return context.getString(R.string.idp_name_twitter); + } + + @Override + public String getProviderId() { + return TwitterAuthProvider.PROVIDER_ID; + } + + @Override + public void setAuthenticationCallback(IDPCallback callback) { + this.mCallbackObject = callback; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + mTwitterAuthClient.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void startLogin(Activity activity) { + mTwitterAuthClient.authorize(activity, this); + } + + @Override + public void success(Result result) { + mCallbackObject.onSuccess(createIDPResponse(result.data)); + } + + @Override + public void failure(TwitterException exception) { + mCallbackObject.onFailure(new Bundle()); + } + + public static AuthCredential createAuthCredential(IDPResponse response) { + if (!response.getProviderType().equalsIgnoreCase(TwitterAuthProvider.PROVIDER_ID)){ + return null; + } + return TwitterAuthProvider.getCredential( + response.getResponse().getString(EXTRA_AUTH_TOKEN), + response.getResponse().getString(EXTRA_AUTH_SECRET)); + } + + + private IDPResponse createIDPResponse(TwitterSession twitterSession) { + Bundle response = new Bundle(); + response.putString(EXTRA_AUTH_TOKEN, twitterSession.getAuthToken().token); + response.putString(EXTRA_AUTH_SECRET, twitterSession.getAuthToken().secret); + return new IDPResponse(TwitterAuthProvider.PROVIDER_ID, twitterSession.getUserName(), response); + } + +} 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 6b185aa1b..dff22e46a 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 @@ -31,6 +31,7 @@ import com.firebase.ui.auth.provider.IDPProvider; import com.firebase.ui.auth.provider.IDPProviderParcel; import com.firebase.ui.auth.provider.IDPResponse; +import com.firebase.ui.auth.provider.TwitterProvider; import com.firebase.ui.auth.ui.ActivityHelper; import com.firebase.ui.auth.ui.FlowParameters; import com.firebase.ui.auth.ui.TaskFailureLogger; @@ -41,6 +42,7 @@ import com.google.firebase.auth.FacebookAuthProvider; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.auth.TwitterAuthProvider; import java.util.ArrayList; import java.util.List; @@ -97,6 +99,9 @@ private void populateIdpList(List providers) { case EmailAuthProvider.PROVIDER_ID: findViewById(R.id.email_provider).setVisibility(View.VISIBLE); break; + case TwitterAuthProvider.PROVIDER_ID: + mIdpProviders.add(new TwitterProvider(this, providerParcel)); + break; default: if (BuildConfig.DEBUG) { Log.d(TAG, "Encountered unknown IDPProvider parcel with type: " @@ -116,6 +121,10 @@ private void populateIdpList(List providers) { loginButton = getLayoutInflater() .inflate(R.layout.idp_button_facebook, btnHolder, false); break; + case TwitterAuthProvider.PROVIDER_ID: + loginButton = getLayoutInflater() + .inflate(R.layout.idp_button_twitter, btnHolder, false); + break; default: Log.e(TAG, "No button for provider " + provider.getProviderId()); } diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/IDPBaseActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/idp/IDPBaseActivity.java index 6de1ffd9a..5c0927726 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/IDPBaseActivity.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/IDPBaseActivity.java @@ -17,10 +17,12 @@ import com.firebase.ui.auth.provider.FacebookProvider; import com.firebase.ui.auth.provider.GoogleProvider; import com.firebase.ui.auth.provider.IDPResponse; +import com.firebase.ui.auth.provider.TwitterProvider; import com.firebase.ui.auth.ui.AppCompatBase; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.FacebookAuthProvider; import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.auth.TwitterAuthProvider; public class IDPBaseActivity extends AppCompatBase { protected AuthCredential createCredential(IDPResponse idpSignInResponse) { @@ -29,6 +31,10 @@ protected AuthCredential createCredential(IDPResponse idpSignInResponse) { } else if (idpSignInResponse.getProviderType().equalsIgnoreCase(GoogleAuthProvider .PROVIDER_ID)) { return GoogleProvider.createAuthCredential(idpSignInResponse); + } else if (idpSignInResponse + .getProviderType() + .equalsIgnoreCase(TwitterAuthProvider.PROVIDER_ID)) { + return TwitterProvider.createAuthCredential(idpSignInResponse); } return null; } diff --git a/auth/src/main/java/com/firebase/ui/auth/util/ProviderHelper.java b/auth/src/main/java/com/firebase/ui/auth/util/ProviderHelper.java index c1fd40647..0ca22dcdf 100644 --- a/auth/src/main/java/com/firebase/ui/auth/util/ProviderHelper.java +++ b/auth/src/main/java/com/firebase/ui/auth/util/ProviderHelper.java @@ -22,6 +22,7 @@ import com.firebase.ui.auth.provider.FacebookProvider; import com.firebase.ui.auth.provider.GoogleProvider; import com.firebase.ui.auth.provider.IDPProviderParcel; +import com.firebase.ui.auth.provider.TwitterProvider; import com.google.firebase.auth.EmailAuthProvider; import java.util.ArrayList; @@ -39,6 +40,10 @@ public static List getProviderParcels( } else if (provider.equalsIgnoreCase(AuthUI.GOOGLE_PROVIDER)) { providerInfo.add(GoogleProvider.createParcel( context.getString(R.string.default_web_client_id))); + } else if (provider.equalsIgnoreCase(AuthUI.TWITTER_PROVIDER)) { + providerInfo.add(TwitterProvider.createTwitterParcel( + context.getString(R.string.twitter_consumer_key), + context.getString(R.string.twitter_consumer_secret))); } else if (provider.equalsIgnoreCase(AuthUI.EMAIL_PROVIDER)) { providerInfo.add( new IDPProviderParcel(EmailAuthProvider.PROVIDER_ID, new Bundle()) diff --git a/auth/src/main/res/drawable/idp_button_background_twitter.xml b/auth/src/main/res/drawable/idp_button_background_twitter.xml new file mode 100644 index 000000000..d770e2213 --- /dev/null +++ b/auth/src/main/res/drawable/idp_button_background_twitter.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/auth/src/main/res/layout/idp_button_twitter.xml b/auth/src/main/res/layout/idp_button_twitter.xml new file mode 100644 index 000000000..fc16bc9ee --- /dev/null +++ b/auth/src/main/res/layout/idp_button_twitter.xml @@ -0,0 +1,6 @@ +