├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── auth │ │ ├── AnonymousAuthActivity.java │ │ ├── BaseActivity.java │ │ ├── EmailPasswordActivity.java │ │ ├── FacebookLoginActivity.java │ │ ├── GoogleSignInActivity.java │ │ ├── MainActivity.java │ │ ├── ManageUserActivity.java │ │ ├── PhoneAuthActivity.java │ │ └── TwitterLoginActivity.java │ └── res │ ├── layout │ ├── activity_anonymous_auth.xml │ ├── activity_emailpassword.xml │ ├── activity_facebook.xml │ ├── activity_google.xml │ ├── activity_main.xml │ ├── activity_manage_user.xml │ ├── activity_phone_auth.xml │ └── activity_twitter.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ ├── authentication.png │ └── ic_launcher.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Local configuration file (sdk path, etc) 17 | local.properties 18 | 19 | # Windows thumbnail db 20 | Thumbs.db 21 | 22 | # OSX files 23 | .DS_Store 24 | 25 | # Log Files 26 | *.log 27 | 28 | # Android Studio 29 | *.iml 30 | .gradle/ 31 | build/ 32 | captures/ 33 | .navigation/ 34 | 35 | # Intellij IDEA 36 | .idea/ 37 | 38 | # Eclipse project files 39 | .classpath 40 | .project 41 | 42 | # Proguard folder generated by Eclipse 43 | proguard/ 44 | 45 | # Eclipse Metadata 46 | .metadata/ 47 | 48 | # Keystore files 49 | *.jks 50 | 51 | .externalNativeBuild 52 | 53 | google-services.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firebase Authentication 2 | Firebase Authentication code guideline for Android developer 3 | 4 | ## Prerequisites 5 | * Supported Android 4.1 or newer 6 | * Android Studio 3.3.2 or higher 7 | * google-services.json in app-level folder 8 | 9 | ## Features 10 | * Sign-in with Email and Password 11 | * Verify user's email 12 | * Sign-in with Google log-in 13 | * Sign-in with Facebook log-in 14 | * Sign-in with Twitter log-in 15 | * Sign-in with Anonymous 16 | * Update user's profile 17 | * Update user's email 18 | * Update user's password 19 | * Send password reset 20 | * Delete a user 21 | 22 | ## Screenshots 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | ## Blog 32 | [Firebase Authentication](https://medium.com/@jirawatee/%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81-firebase-authentication-%E0%B8%95%E0%B8%B1%E0%B9%89%E0%B8%87%E0%B9%81%E0%B8%95%E0%B9%88-zero-%E0%B8%88%E0%B8%99%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99-hero-7dd5839d3588) 33 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion compileAndTargetSdk 5 | buildToolsVersion '30.0.3' 6 | 7 | defaultConfig { 8 | applicationId 'com.example.auth' 9 | minSdkVersion 21 10 | targetSdkVersion compileAndTargetSdk 11 | versionCode 1 12 | versionName '1.0' 13 | resConfigs ('en', 'xxxhdpi') 14 | ndk { 15 | abiFilters "x86", "x86_64", "arm64-v8a", "armeabi-v7a" 16 | } 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled true 22 | shrinkResources true 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | debug { 26 | splits.abi.enable = false 27 | splits.density.enable = false 28 | aaptOptions.cruncherEnabled = false 29 | } 30 | } 31 | 32 | dexOptions { 33 | preDexLibraries true 34 | maxProcessCount 8 35 | } 36 | } 37 | 38 | dependencies { 39 | implementation 'androidx.appcompat:appcompat:1.2.0' 40 | implementation 'com.google.android.material:material:1.3.0' 41 | implementation 'com.google.firebase:firebase-analytics:18.0.3' 42 | implementation 'com.google.firebase:firebase-auth:20.0.4' 43 | implementation 'com.google.android.gms:play-services-auth:19.0.0' 44 | implementation 'com.facebook.android:facebook-login:6.1.0' 45 | implementation('com.twitter.sdk.android:twitter:2.3.2') { 46 | transitive = true 47 | } 48 | } 49 | apply plugin: 'com.google.gms.google-services' -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes Signature 2 | -keepattributes *Annotation* 3 | -keepattributes EnclosingMethod 4 | -keepattributes InnerClasses 5 | 6 | # Required for Twitter Authentication 7 | # https://docs.fabric.io/android/twitter/twitter.html#set-up-kit 8 | -dontwarn com.squareup.okhttp.** 9 | -dontwarn com.google.appengine.api.urlfetch.** 10 | -dontwarn rx.** 11 | -dontwarn retrofit.** 12 | -dontwarn retrofit2.** 13 | -dontwarn okio.** 14 | -keep class com.squareup.okhttp.** { *; } 15 | -keep interface com.squareup.okhttp.** { *; } 16 | -keep class retrofit.** { *; } 17 | -keepclasseswithmembers class * { 18 | @retrofit.http.* ; 19 | } 20 | 21 | -assumenosideeffects class android.util.Log { 22 | public static boolean isLoggable(java.lang.String, int); 23 | public static int v(...); 24 | public static int i(...); 25 | public static int w(...); 26 | public static int d(...); 27 | public static int e(...); 28 | public static int wtf(...); 29 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 33 | 34 | 38 | 39 | 42 | 43 | 46 | 47 | 51 | 52 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/AnonymousAuthActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.text.TextUtils; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.EditText; 10 | import android.widget.TextView; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.appcompat.app.AlertDialog; 14 | 15 | import com.google.android.gms.tasks.OnCompleteListener; 16 | import com.google.android.gms.tasks.Task; 17 | import com.google.firebase.auth.AuthCredential; 18 | import com.google.firebase.auth.AuthResult; 19 | import com.google.firebase.auth.EmailAuthProvider; 20 | import com.google.firebase.auth.FirebaseAuth; 21 | import com.google.firebase.auth.FirebaseUser; 22 | 23 | /** 24 | * Activity to demonstrate anonymous login and account linking (with an email/password account). 25 | */ 26 | public class AnonymousAuthActivity extends BaseActivity implements View.OnClickListener { 27 | private static final String TAG = "AnonymousAuth"; 28 | private FirebaseAuth mAuth; 29 | private FirebaseAuth.AuthStateListener mAuthListener; 30 | private EditText mEmailField, mPasswordField; 31 | private TextView mTextViewProfile; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_anonymous_auth); 37 | 38 | mTextViewProfile = findViewById(R.id.profile); 39 | mEmailField = findViewById(R.id.field_email); 40 | mPasswordField = findViewById(R.id.field_password); 41 | 42 | findViewById(R.id.button_anonymous_sign_in).setOnClickListener(this); 43 | findViewById(R.id.button_anonymous_sign_out).setOnClickListener(this); 44 | findViewById(R.id.button_link_account).setOnClickListener(this); 45 | 46 | mAuth = FirebaseAuth.getInstance(); 47 | mAuthListener = new FirebaseAuth.AuthStateListener() { 48 | @Override 49 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 50 | FirebaseUser user = firebaseAuth.getCurrentUser(); 51 | if (user != null) { 52 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 53 | } else { 54 | Log.d(TAG, "onAuthStateChanged:signed_out"); 55 | } 56 | updateUI(user); 57 | } 58 | }; 59 | } 60 | 61 | @Override 62 | public void onStart() { 63 | super.onStart(); 64 | mAuth.addAuthStateListener(mAuthListener); 65 | } 66 | 67 | @Override 68 | public void onStop() { 69 | super.onStop(); 70 | if (mAuthListener != null) { 71 | mAuth.removeAuthStateListener(mAuthListener); 72 | } 73 | } 74 | 75 | private void signInAnonymously() { 76 | showProgressDialog(); 77 | mAuth.signInAnonymously().addOnCompleteListener(this, new OnCompleteListener() { 78 | @Override 79 | public void onComplete(@NonNull Task task) { 80 | Log.d(TAG, "signInAnonymously:onComplete:" + task.isSuccessful()); 81 | if (!task.isSuccessful()) { 82 | mTextViewProfile.setTextColor(Color.RED); 83 | mTextViewProfile.setText(task.getException().getMessage()); 84 | } else { 85 | mTextViewProfile.setTextColor(Color.DKGRAY); 86 | } 87 | hideProgressDialog(); 88 | } 89 | }); 90 | } 91 | 92 | private void signOut() { 93 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 94 | alert.setMessage(R.string.logout); 95 | alert.setCancelable(false); 96 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 97 | @Override 98 | public void onClick(DialogInterface dialogInterface, int i) { 99 | mAuth.signOut(); 100 | updateUI(null); 101 | } 102 | }); 103 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 104 | @Override 105 | public void onClick(DialogInterface dialogInterface, int i) { 106 | dialogInterface.dismiss(); 107 | } 108 | }); 109 | alert.show(); 110 | } 111 | 112 | private void linkAccount() { 113 | if (!validateLinkForm()) { 114 | return; 115 | } 116 | showProgressDialog(); 117 | 118 | String email = mEmailField.getText().toString(); 119 | String password = mPasswordField.getText().toString(); 120 | 121 | AuthCredential credential = EmailAuthProvider.getCredential(email, password); 122 | mAuth.getCurrentUser().linkWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener() { 123 | @Override 124 | public void onComplete(@NonNull Task task) { 125 | Log.d(TAG, "linkWithCredential:onComplete:" + task.isSuccessful()); 126 | if (!task.isSuccessful()) { 127 | mTextViewProfile.setTextColor(Color.RED); 128 | mTextViewProfile.setText(task.getException().getMessage()); 129 | } else { 130 | mTextViewProfile.setTextColor(Color.DKGRAY); 131 | } 132 | hideProgressDialog(); 133 | } 134 | }); 135 | } 136 | 137 | private boolean validateLinkForm() { 138 | if (TextUtils.isEmpty(mEmailField.getText().toString())) { 139 | mEmailField.setError("Required."); 140 | return false; 141 | } else if (TextUtils.isEmpty(mPasswordField.getText().toString())) { 142 | mPasswordField.setError("Required."); 143 | return false; 144 | } else { 145 | mEmailField.setError(null); 146 | return true; 147 | } 148 | } 149 | 150 | private void updateUI(FirebaseUser user) { 151 | boolean isSignedIn = (user != null); 152 | 153 | if (isSignedIn) { 154 | mTextViewProfile.setText("Email: " + user.getEmail()); 155 | mTextViewProfile.append("\n"); 156 | mTextViewProfile.append("Firebase ID: " + user.getUid()); 157 | } else { 158 | mTextViewProfile.setText(null); 159 | } 160 | 161 | findViewById(R.id.button_anonymous_sign_in).setEnabled(!isSignedIn); 162 | findViewById(R.id.button_anonymous_sign_out).setEnabled(isSignedIn); 163 | findViewById(R.id.button_link_account).setEnabled(isSignedIn); 164 | 165 | hideProgressDialog(); 166 | } 167 | 168 | @Override 169 | public void onClick(View v) { 170 | switch (v.getId()) { 171 | case R.id.button_anonymous_sign_in: 172 | signInAnonymously(); 173 | break; 174 | case R.id.button_anonymous_sign_out: 175 | signOut(); 176 | break; 177 | case R.id.button_link_account: 178 | linkAccount(); 179 | break; 180 | } 181 | } 182 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.app.ProgressDialog; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | public class BaseActivity extends AppCompatActivity { 7 | private ProgressDialog mProgressDialog; 8 | 9 | public void showProgressDialog() { 10 | if (mProgressDialog == null) { 11 | mProgressDialog = new ProgressDialog(this); 12 | mProgressDialog.setMessage(getString(R.string.loading)); 13 | mProgressDialog.setIndeterminate(true); 14 | } 15 | mProgressDialog.show(); 16 | } 17 | 18 | public void hideProgressDialog() { 19 | if (mProgressDialog != null && mProgressDialog.isShowing()) { 20 | mProgressDialog.dismiss(); 21 | } 22 | } 23 | 24 | @Override 25 | public void onStop() { 26 | super.onStop(); 27 | hideProgressDialog(); 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/EmailPasswordActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Color; 7 | import android.os.AsyncTask; 8 | import android.os.Bundle; 9 | import androidx.annotation.NonNull; 10 | import com.google.android.material.textfield.TextInputLayout; 11 | import androidx.appcompat.app.AlertDialog; 12 | import android.text.TextUtils; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.EditText; 16 | import android.widget.ImageView; 17 | import android.widget.TextView; 18 | import android.widget.Toast; 19 | 20 | import com.google.android.gms.tasks.OnCompleteListener; 21 | import com.google.android.gms.tasks.Task; 22 | import com.google.firebase.auth.AuthResult; 23 | import com.google.firebase.auth.FirebaseAuth; 24 | import com.google.firebase.auth.FirebaseUser; 25 | 26 | import java.io.InputStream; 27 | import java.net.URL; 28 | 29 | public class EmailPasswordActivity extends BaseActivity implements View.OnClickListener { 30 | private static final String TAG = "EmailPasswordActivity"; 31 | private EditText mEdtEmail, mEdtPassword; 32 | private FirebaseAuth mAuth; 33 | private FirebaseAuth.AuthStateListener mAuthListener; 34 | private ImageView mImageView; 35 | private TextView mTextViewProfile; 36 | private TextInputLayout mLayoutEmail, mLayoutPassword; 37 | 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_emailpassword); 42 | 43 | mTextViewProfile = findViewById(R.id.profile); 44 | mEdtEmail = findViewById(R.id.edt_email); 45 | mEdtPassword = findViewById(R.id.edt_password); 46 | mImageView = findViewById(R.id.logo); 47 | mLayoutEmail = findViewById(R.id.layout_email); 48 | mLayoutPassword = findViewById(R.id.layout_password); 49 | 50 | findViewById(R.id.email_sign_in_button).setOnClickListener(this); 51 | findViewById(R.id.email_create_account_button).setOnClickListener(this); 52 | findViewById(R.id.sign_out_button).setOnClickListener(this); 53 | findViewById(R.id.verify_button).setOnClickListener(this); 54 | 55 | mAuth = FirebaseAuth.getInstance(); 56 | mAuthListener = new FirebaseAuth.AuthStateListener() { 57 | @Override 58 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 59 | FirebaseUser user = firebaseAuth.getCurrentUser(); 60 | if (user != null) { 61 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 62 | } else { 63 | Log.d(TAG, "onAuthStateChanged:signed_out"); 64 | } 65 | updateUI(user); 66 | } 67 | }; 68 | } 69 | 70 | @Override 71 | public void onStart() { 72 | super.onStart(); 73 | mAuth.addAuthStateListener(mAuthListener); 74 | } 75 | 76 | @Override 77 | public void onStop() { 78 | super.onStop(); 79 | if (mAuthListener != null) { 80 | mAuth.removeAuthStateListener(mAuthListener); 81 | } 82 | } 83 | 84 | @Override 85 | public void onClick(View v) { 86 | switch (v.getId()) { 87 | case R.id.email_create_account_button: 88 | createAccount(mEdtEmail.getText().toString(), mEdtPassword.getText().toString()); 89 | break; 90 | case R.id.email_sign_in_button: 91 | signIn(mEdtEmail.getText().toString(), mEdtPassword.getText().toString()); 92 | break; 93 | case R.id.sign_out_button: 94 | signOut(); 95 | break; 96 | case R.id.verify_button: 97 | findViewById(R.id.verify_button).setEnabled(false); 98 | final FirebaseUser firebaseUser = mAuth.getCurrentUser(); 99 | firebaseUser.sendEmailVerification().addOnCompleteListener(this, new OnCompleteListener() { 100 | @Override 101 | public void onComplete(@NonNull Task task) { 102 | if (task.isSuccessful()) { 103 | Toast.makeText( 104 | EmailPasswordActivity.this, "Verification email sent to " + firebaseUser.getEmail(), Toast.LENGTH_LONG 105 | ).show(); 106 | } else { 107 | Toast.makeText(EmailPasswordActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show(); 108 | } 109 | findViewById(R.id.verify_button).setEnabled(true); 110 | } 111 | }); 112 | break; 113 | } 114 | } 115 | 116 | private void createAccount(String email, String password) { 117 | if (!validateForm()) { 118 | return; 119 | } 120 | showProgressDialog(); 121 | mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() { 122 | @Override 123 | public void onComplete(@NonNull Task task) { 124 | if (!task.isSuccessful()) { 125 | mTextViewProfile.setTextColor(Color.RED); 126 | mTextViewProfile.setText(task.getException().getMessage()); 127 | } else { 128 | mTextViewProfile.setTextColor(Color.DKGRAY); 129 | } 130 | hideProgressDialog(); 131 | } 132 | }); 133 | } 134 | 135 | private void signIn(String email, String password) { 136 | if (!validateForm()) { 137 | return; 138 | } 139 | showProgressDialog(); 140 | mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() { 141 | @Override 142 | public void onComplete(@NonNull Task task) { 143 | Log.d(TAG, "signInWithEmail:onComplete:" + task.isSuccessful()); 144 | if (!task.isSuccessful()) { 145 | mTextViewProfile.setTextColor(Color.RED); 146 | mTextViewProfile.setText(task.getException().getMessage()); 147 | } else { 148 | mTextViewProfile.setTextColor(Color.DKGRAY); 149 | } 150 | hideProgressDialog(); 151 | } 152 | }); 153 | } 154 | 155 | private void signOut() { 156 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 157 | alert.setMessage(R.string.logout); 158 | alert.setCancelable(false); 159 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 160 | @Override 161 | public void onClick(DialogInterface dialogInterface, int i) { 162 | mAuth.signOut(); 163 | updateUI(null); 164 | } 165 | }); 166 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 167 | @Override 168 | public void onClick(DialogInterface dialogInterface, int i) { 169 | dialogInterface.dismiss(); 170 | } 171 | }); 172 | alert.show(); 173 | } 174 | 175 | private boolean validateForm() { 176 | if (TextUtils.isEmpty(mEdtEmail.getText().toString())) { 177 | mLayoutEmail.setError("Required."); 178 | return false; 179 | } else if (TextUtils.isEmpty(mEdtPassword.getText().toString())) { 180 | mLayoutPassword.setError("Required."); 181 | return false; 182 | } else { 183 | mLayoutEmail.setError(null); 184 | mLayoutPassword.setError(null); 185 | return true; 186 | } 187 | } 188 | 189 | private void updateUI(FirebaseUser user) { 190 | if (user != null) { 191 | if (user.getPhotoUrl() != null) { 192 | new DownloadImageTask().execute(user.getPhotoUrl().toString()); 193 | } 194 | mTextViewProfile.setText("DisplayName: " + user.getDisplayName()); 195 | mTextViewProfile.append("\n\n"); 196 | mTextViewProfile.append("Email: " + user.getEmail()); 197 | mTextViewProfile.append("\n\n"); 198 | mTextViewProfile.append("Firebase ID: " + user.getUid()); 199 | mTextViewProfile.append("\n\n"); 200 | mTextViewProfile.append("Email Verification: " + user.isEmailVerified()); 201 | 202 | if (user.isEmailVerified()) { 203 | findViewById(R.id.verify_button).setVisibility(View.GONE); 204 | } else { 205 | findViewById(R.id.verify_button).setVisibility(View.VISIBLE); 206 | } 207 | 208 | findViewById(R.id.email_password_buttons).setVisibility(View.GONE); 209 | findViewById(R.id.email_password_fields).setVisibility(View.GONE); 210 | findViewById(R.id.signout_zone).setVisibility(View.VISIBLE); 211 | } else { 212 | mTextViewProfile.setText(null); 213 | 214 | findViewById(R.id.email_password_buttons).setVisibility(View.VISIBLE); 215 | findViewById(R.id.email_password_fields).setVisibility(View.VISIBLE); 216 | findViewById(R.id.signout_zone).setVisibility(View.GONE); 217 | } 218 | hideProgressDialog(); 219 | } 220 | 221 | private class DownloadImageTask extends AsyncTask { 222 | @Override 223 | protected Bitmap doInBackground(String... urls) { 224 | Bitmap mIcon = null; 225 | try { 226 | InputStream in = new URL(urls[0]).openStream(); 227 | mIcon = BitmapFactory.decodeStream(in); 228 | } catch (Exception e) { 229 | e.printStackTrace(); 230 | } 231 | return mIcon; 232 | } 233 | 234 | @Override 235 | protected void onPostExecute(Bitmap result) { 236 | if (result != null) { 237 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 24; 238 | mImageView.setImageBitmap(result); 239 | } 240 | } 241 | } 242 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/FacebookLoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Color; 8 | import android.os.AsyncTask; 9 | import android.os.Bundle; 10 | import androidx.annotation.NonNull; 11 | import androidx.appcompat.app.AlertDialog; 12 | import android.util.Log; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.TextView; 16 | 17 | import com.facebook.AccessToken; 18 | import com.facebook.CallbackManager; 19 | import com.facebook.FacebookCallback; 20 | import com.facebook.FacebookException; 21 | import com.facebook.login.LoginManager; 22 | import com.facebook.login.LoginResult; 23 | import com.facebook.login.widget.LoginButton; 24 | import com.google.android.gms.tasks.OnCompleteListener; 25 | import com.google.android.gms.tasks.Task; 26 | import com.google.firebase.auth.AuthCredential; 27 | import com.google.firebase.auth.AuthResult; 28 | import com.google.firebase.auth.FacebookAuthProvider; 29 | import com.google.firebase.auth.FirebaseAuth; 30 | import com.google.firebase.auth.FirebaseUser; 31 | 32 | import java.io.InputStream; 33 | import java.net.URL; 34 | 35 | public class FacebookLoginActivity extends BaseActivity implements View.OnClickListener { 36 | private static final String TAG = "FacebookLoginActivity"; 37 | private CallbackManager mCallbackManager; 38 | private FirebaseAuth mAuth; 39 | private FirebaseAuth.AuthStateListener mAuthListener; 40 | private ImageView mImageView; 41 | private TextView mTextViewProfile; 42 | 43 | @Override 44 | public void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setContentView(R.layout.activity_facebook); 47 | 48 | mImageView = findViewById(R.id.logo); 49 | mTextViewProfile = findViewById(R.id.profile); 50 | findViewById(R.id.button_facebook_signout).setOnClickListener(this); 51 | 52 | mAuth = FirebaseAuth.getInstance(); 53 | mAuthListener = new FirebaseAuth.AuthStateListener() { 54 | @Override 55 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 56 | FirebaseUser user = firebaseAuth.getCurrentUser(); 57 | if (user != null) { 58 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 59 | } else { 60 | Log.d(TAG, "onAuthStateChanged:signed_out"); 61 | } 62 | updateUI(user); 63 | } 64 | }; 65 | 66 | // Initialize Facebook Login button 67 | mCallbackManager = CallbackManager.Factory.create(); 68 | LoginButton loginButton = findViewById(R.id.button_facebook_login); 69 | loginButton.setReadPermissions("email", "public_profile"); 70 | loginButton.registerCallback(mCallbackManager, new FacebookCallback() { 71 | @Override 72 | public void onSuccess(LoginResult loginResult) { 73 | Log.d(TAG, "facebook:onSuccess:" + loginResult); 74 | handleFacebookAccessToken(loginResult.getAccessToken()); 75 | } 76 | 77 | @Override 78 | public void onCancel() { 79 | Log.d(TAG, "facebook:onCancel"); 80 | updateUI(null); 81 | } 82 | 83 | @Override 84 | public void onError(FacebookException error) { 85 | Log.d(TAG, "facebook:onError", error); 86 | updateUI(null); 87 | } 88 | }); 89 | } 90 | 91 | @Override 92 | public void onStart() { 93 | super.onStart(); 94 | mAuth.addAuthStateListener(mAuthListener); 95 | } 96 | 97 | @Override 98 | public void onStop() { 99 | super.onStop(); 100 | if (mAuthListener != null) { 101 | mAuth.removeAuthStateListener(mAuthListener); 102 | } 103 | } 104 | 105 | @Override 106 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 107 | super.onActivityResult(requestCode, resultCode, data); 108 | mCallbackManager.onActivityResult(requestCode, resultCode, data); 109 | } 110 | 111 | // auth_with_facebook 112 | private void handleFacebookAccessToken(AccessToken token) { 113 | Log.d(TAG, "handleFacebookAccessToken:" + token); 114 | showProgressDialog(); 115 | 116 | AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken()); 117 | mAuth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener() { 118 | @Override 119 | public void onComplete(@NonNull Task task) { 120 | Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful()); 121 | if (!task.isSuccessful()) { 122 | mTextViewProfile.setTextColor(Color.RED); 123 | mTextViewProfile.setText(task.getException().getMessage()); 124 | } else { 125 | mTextViewProfile.setTextColor(Color.DKGRAY); 126 | } 127 | hideProgressDialog(); 128 | } 129 | }); 130 | } 131 | 132 | private void signOut() { 133 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 134 | alert.setMessage(R.string.logout); 135 | alert.setCancelable(false); 136 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 137 | @Override 138 | public void onClick(DialogInterface dialogInterface, int i) { 139 | // Firebase sign out 140 | mAuth.signOut(); 141 | // Facebook sign out 142 | LoginManager.getInstance().logOut(); 143 | updateUI(null); 144 | } 145 | }); 146 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 147 | @Override 148 | public void onClick(DialogInterface dialogInterface, int i) { 149 | dialogInterface.dismiss(); 150 | } 151 | }); 152 | alert.show(); 153 | } 154 | 155 | private void updateUI(FirebaseUser user) { 156 | if (user != null) { 157 | if (user.getPhotoUrl() != null) { 158 | new DownloadImageTask().execute(user.getPhotoUrl().toString()); 159 | } 160 | mTextViewProfile.setText("DisplayName: " + user.getDisplayName()); 161 | mTextViewProfile.append("\n\n"); 162 | mTextViewProfile.append("Email: " + user.getEmail()); 163 | mTextViewProfile.append("\n\n"); 164 | mTextViewProfile.append("Firebase ID: " + user.getUid()); 165 | 166 | findViewById(R.id.button_facebook_login).setVisibility(View.GONE); 167 | findViewById(R.id.button_facebook_signout).setVisibility(View.VISIBLE); 168 | } else { 169 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 64; 170 | mImageView.setImageResource(R.mipmap.authentication); 171 | mTextViewProfile.setText(null); 172 | 173 | findViewById(R.id.button_facebook_login).setVisibility(View.VISIBLE); 174 | findViewById(R.id.button_facebook_signout).setVisibility(View.GONE); 175 | } 176 | hideProgressDialog(); 177 | } 178 | 179 | @Override 180 | public void onClick(View v) { 181 | switch (v.getId()) { 182 | case R.id.button_facebook_signout: 183 | signOut(); 184 | break; 185 | } 186 | } 187 | 188 | private class DownloadImageTask extends AsyncTask { 189 | @Override 190 | protected Bitmap doInBackground(String... urls) { 191 | Bitmap mIcon = null; 192 | try { 193 | InputStream in = new URL(urls[0]).openStream(); 194 | mIcon = BitmapFactory.decodeStream(in); 195 | } catch (Exception e) { 196 | e.printStackTrace(); 197 | } 198 | return mIcon; 199 | } 200 | @Override 201 | protected void onPostExecute(Bitmap result) { 202 | if (result != null) { 203 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 24; 204 | mImageView.setImageBitmap(result); 205 | } 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/GoogleSignInActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Color; 8 | import android.os.AsyncTask; 9 | import android.os.Bundle; 10 | import androidx.annotation.NonNull; 11 | import androidx.appcompat.app.AlertDialog; 12 | import android.util.Log; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import com.google.android.gms.auth.api.Auth; 19 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 20 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 21 | import com.google.android.gms.auth.api.signin.GoogleSignInResult; 22 | import com.google.android.gms.common.ConnectionResult; 23 | import com.google.android.gms.common.SignInButton; 24 | import com.google.android.gms.common.api.GoogleApiClient; 25 | import com.google.android.gms.common.api.ResultCallback; 26 | import com.google.android.gms.common.api.Status; 27 | import com.google.android.gms.tasks.OnCompleteListener; 28 | import com.google.android.gms.tasks.Task; 29 | import com.google.firebase.auth.AuthCredential; 30 | import com.google.firebase.auth.AuthResult; 31 | import com.google.firebase.auth.FirebaseAuth; 32 | import com.google.firebase.auth.FirebaseUser; 33 | import com.google.firebase.auth.GoogleAuthProvider; 34 | 35 | import java.io.InputStream; 36 | import java.net.URL; 37 | 38 | public class GoogleSignInActivity extends BaseActivity implements GoogleApiClient.OnConnectionFailedListener, View.OnClickListener{ 39 | private static final String TAG = "GoogleSignInActivity"; 40 | private static final int RC_SIGN_IN = 9001; 41 | private FirebaseAuth mAuth; 42 | private FirebaseAuth.AuthStateListener mAuthListener; 43 | private GoogleApiClient mGoogleApiClient; 44 | private ImageView mImageView; 45 | private TextView mTextViewProfile; 46 | 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setContentView(R.layout.activity_google); 51 | 52 | mImageView = findViewById(R.id.logo); 53 | mTextViewProfile = findViewById(R.id.profile); 54 | 55 | SignInButton signInButton = findViewById(R.id.sign_in_button); 56 | signInButton.setSize(SignInButton.SIZE_WIDE); 57 | signInButton.setOnClickListener(this); 58 | 59 | findViewById(R.id.sign_out_button).setOnClickListener(this); 60 | findViewById(R.id.disconnect_button).setOnClickListener(this); 61 | 62 | // Configure Google Sign In 63 | GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 64 | .requestIdToken(getString(R.string.default_web_client_id)) 65 | .requestEmail() 66 | .build(); 67 | 68 | mGoogleApiClient = new GoogleApiClient.Builder(this) 69 | .enableAutoManage(this, this) 70 | .addApi(Auth.GOOGLE_SIGN_IN_API, gso) 71 | .build(); 72 | 73 | mAuth = FirebaseAuth.getInstance(); 74 | mAuthListener = new FirebaseAuth.AuthStateListener() { 75 | @Override 76 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 77 | FirebaseUser user = firebaseAuth.getCurrentUser(); 78 | if (user != null) { 79 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 80 | } else { 81 | Log.d(TAG, "onAuthStateChanged:signed_out"); 82 | } 83 | updateUI(user); 84 | } 85 | }; 86 | } 87 | 88 | @Override 89 | public void onStart() { 90 | super.onStart(); 91 | mAuth.addAuthStateListener(mAuthListener); 92 | } 93 | 94 | @Override 95 | public void onStop() { 96 | super.onStop(); 97 | if (mAuthListener != null) { 98 | mAuth.removeAuthStateListener(mAuthListener); 99 | } 100 | } 101 | 102 | @Override 103 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 104 | super.onActivityResult(requestCode, resultCode, data); 105 | 106 | if (requestCode == RC_SIGN_IN) { 107 | GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); 108 | if (result.isSuccess()) { 109 | // Google Sign In was successful, authenticate with Firebase 110 | GoogleSignInAccount account = result.getSignInAccount(); 111 | firebaseAuthWithGoogle(account); 112 | } else { 113 | // Google Sign In failed, update UI appropriately 114 | updateUI(null); 115 | } 116 | } 117 | } 118 | 119 | private void firebaseAuthWithGoogle(GoogleSignInAccount acct) { 120 | Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId()); 121 | showProgressDialog(); 122 | 123 | AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null); 124 | mAuth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener() { 125 | @Override 126 | public void onComplete(@NonNull Task task) { 127 | Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful()); 128 | if (!task.isSuccessful()) { 129 | mTextViewProfile.setTextColor(Color.RED); 130 | mTextViewProfile.setText(task.getException().getMessage()); 131 | } else { 132 | mTextViewProfile.setTextColor(Color.DKGRAY); 133 | } 134 | hideProgressDialog(); 135 | } 136 | }); 137 | } 138 | 139 | private void signIn() { 140 | Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); 141 | startActivityForResult(signInIntent, RC_SIGN_IN); 142 | } 143 | 144 | private void signOut() { 145 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 146 | alert.setMessage(R.string.logout); 147 | alert.setCancelable(false); 148 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 149 | @Override 150 | public void onClick(DialogInterface dialogInterface, int i) { 151 | // Firebase sign out 152 | mAuth.signOut(); 153 | // Google sign out 154 | Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( 155 | new ResultCallback() { 156 | @Override 157 | public void onResult(@NonNull Status status) { 158 | updateUI(null); 159 | } 160 | } 161 | ); 162 | } 163 | }); 164 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 165 | @Override 166 | public void onClick(DialogInterface dialogInterface, int i) { 167 | dialogInterface.dismiss(); 168 | } 169 | }); 170 | alert.show(); 171 | } 172 | 173 | private void revokeAccess() { 174 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 175 | alert.setMessage(R.string.logout); 176 | alert.setCancelable(false); 177 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 178 | @Override 179 | public void onClick(DialogInterface dialogInterface, int i) { 180 | // Firebase sign out 181 | mAuth.signOut(); 182 | // Google revoke access 183 | Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback( 184 | new ResultCallback() { 185 | @Override 186 | public void onResult(@NonNull Status status) { 187 | updateUI(null); 188 | } 189 | } 190 | ); 191 | } 192 | }); 193 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 194 | @Override 195 | public void onClick(DialogInterface dialogInterface, int i) { 196 | dialogInterface.dismiss(); 197 | } 198 | }); 199 | alert.show(); 200 | } 201 | 202 | private void updateUI(FirebaseUser user) { 203 | if (user != null) { 204 | if (user.getPhotoUrl() != null) { 205 | new DownloadImageTask().execute(user.getPhotoUrl().toString()); 206 | } 207 | mTextViewProfile.setText("DisplayName: " + user.getDisplayName()); 208 | mTextViewProfile.append("\n\n"); 209 | mTextViewProfile.append("Email: " + user.getEmail()); 210 | mTextViewProfile.append("\n\n"); 211 | mTextViewProfile.append("Firebase ID: " + user.getUid()); 212 | 213 | findViewById(R.id.sign_in_button).setVisibility(View.GONE); 214 | findViewById(R.id.sign_out_and_disconnect).setVisibility(View.VISIBLE); 215 | } else { 216 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 64; 217 | mImageView.setImageResource(R.mipmap.authentication); 218 | mTextViewProfile.setText(null); 219 | findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE); 220 | findViewById(R.id.sign_out_and_disconnect).setVisibility(View.GONE); 221 | } 222 | hideProgressDialog(); 223 | } 224 | 225 | @Override 226 | public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 227 | Log.d(TAG, "onConnectionFailed:" + connectionResult); 228 | Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show(); 229 | } 230 | 231 | @Override 232 | public void onClick(View view) { 233 | switch (view.getId()) { 234 | case R.id.sign_in_button: 235 | signIn(); 236 | break; 237 | case R.id.sign_out_button: 238 | signOut(); 239 | break; 240 | case R.id.disconnect_button: 241 | revokeAccess(); 242 | break; 243 | } 244 | } 245 | 246 | private class DownloadImageTask extends AsyncTask { 247 | @Override 248 | protected Bitmap doInBackground(String... urls) { 249 | Bitmap mIcon = null; 250 | try { 251 | InputStream in = new URL(urls[0]).openStream(); 252 | mIcon = BitmapFactory.decodeStream(in); 253 | } catch (Exception e) { 254 | e.printStackTrace(); 255 | } 256 | return mIcon; 257 | } 258 | @Override 259 | protected void onPostExecute(Bitmap result) { 260 | if (result != null) { 261 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 24; 262 | mImageView.setImageBitmap(result); 263 | } 264 | } 265 | } 266 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.AdapterView; 11 | import android.widget.ArrayAdapter; 12 | import android.widget.ListView; 13 | import android.widget.TextView; 14 | 15 | public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { 16 | private static final Class[] CLASSES = new Class[]{ 17 | EmailPasswordActivity.class, 18 | GoogleSignInActivity.class, 19 | FacebookLoginActivity.class, 20 | TwitterLoginActivity.class, 21 | AnonymousAuthActivity.class, 22 | PhoneAuthActivity.class, 23 | ManageUserActivity.class 24 | }; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main); 30 | ListView listView = findViewById(R.id.list_view); 31 | 32 | MyArrayAdapter adapter = new MyArrayAdapter(this, android.R.layout.simple_list_item_1, CLASSES); 33 | listView.setAdapter(adapter); 34 | listView.setOnItemClickListener(this); 35 | } 36 | 37 | @Override 38 | public void onItemClick(AdapterView parent, View view, int position, long id) { 39 | Class clicked = CLASSES[position]; 40 | startActivity(new Intent(this, clicked)); 41 | } 42 | 43 | private static class MyArrayAdapter extends ArrayAdapter { 44 | private Context mContext; 45 | private Class[] mClasses; 46 | 47 | private MyArrayAdapter(Context context, int resource, Class[] objects) { 48 | super(context, resource, objects); 49 | mContext = context; 50 | mClasses = objects; 51 | } 52 | 53 | @Override 54 | public View getView(int position, View convertView, ViewGroup parent) { 55 | View view = convertView; 56 | 57 | if (convertView == null) { 58 | LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE); 59 | view = inflater.inflate(android.R.layout.simple_list_item_1, null); 60 | } 61 | ((TextView) view.findViewById(android.R.id.text1)).setText(mClasses[position].getSimpleName()); 62 | 63 | return view; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/ManageUserActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.graphics.Color; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import androidx.annotation.NonNull; 8 | import androidx.appcompat.app.AlertDialog; 9 | import android.text.TextUtils; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.EditText; 13 | import android.widget.TextView; 14 | 15 | import com.google.android.gms.tasks.OnCompleteListener; 16 | import com.google.android.gms.tasks.Task; 17 | import com.google.firebase.auth.FirebaseAuth; 18 | import com.google.firebase.auth.FirebaseUser; 19 | import com.google.firebase.auth.UserInfo; 20 | import com.google.firebase.auth.UserProfileChangeRequest; 21 | 22 | public class ManageUserActivity extends BaseActivity implements View.OnClickListener { 23 | private static final String TAG = "ManageUserActivity"; 24 | private EditText mEditTextName, mEditTextPhoto, mEditTextEmail, mEditTextPassword, mEditTextEmailReset; 25 | private FirebaseAuth mAuth; 26 | private FirebaseAuth.AuthStateListener mAuthListener; 27 | private TextView mTextViewProfile, mTextViewProvider; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_manage_user); 33 | 34 | mTextViewProfile = findViewById(R.id.profile); 35 | mTextViewProvider = findViewById(R.id.provider); 36 | mEditTextName = findViewById(R.id.field_name); 37 | mEditTextPhoto = findViewById(R.id.field_photo); 38 | mEditTextEmail = findViewById(R.id.field_email); 39 | mEditTextPassword = findViewById(R.id.field_password); 40 | mEditTextEmailReset = findViewById(R.id.field_email_reset); 41 | 42 | findViewById(R.id.update_profile_button).setOnClickListener(this); 43 | findViewById(R.id.update_email_button).setOnClickListener(this); 44 | findViewById(R.id.update_password_button).setOnClickListener(this); 45 | findViewById(R.id.send_password_reset_button).setOnClickListener(this); 46 | findViewById(R.id.delete_button).setOnClickListener(this); 47 | 48 | mAuth = FirebaseAuth.getInstance(); 49 | mAuthListener = new FirebaseAuth.AuthStateListener() { 50 | @Override 51 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 52 | FirebaseUser user = firebaseAuth.getCurrentUser(); 53 | if (user != null) { 54 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 55 | } else { 56 | Log.d(TAG, "onAuthStateChanged:signed_out"); 57 | } 58 | updateUI(user); 59 | } 60 | }; 61 | } 62 | 63 | @Override 64 | public void onStart() { 65 | super.onStart(); 66 | mAuth.addAuthStateListener(mAuthListener); 67 | } 68 | 69 | @Override 70 | public void onStop() { 71 | super.onStop(); 72 | if (mAuthListener != null) { 73 | mAuth.removeAuthStateListener(mAuthListener); 74 | } 75 | } 76 | 77 | @Override 78 | public void onClick(View view) { 79 | final FirebaseUser user = mAuth.getCurrentUser(); 80 | switch (view.getId()) { 81 | case R.id.update_profile_button: 82 | if (validateForm()) { 83 | updateNameAndPhoto(user); 84 | } 85 | break; 86 | case R.id.update_email_button: 87 | if (validateEmail(mEditTextEmail)) { 88 | updateEmail(user); 89 | } 90 | break; 91 | case R.id.update_password_button: 92 | if (validatePassword()) { 93 | updatePassword(user); 94 | } 95 | break; 96 | case R.id.send_password_reset_button: 97 | if (validateEmail(mEditTextEmailReset)) { 98 | sendPasswordReset(); 99 | } 100 | break; 101 | case R.id.delete_button: 102 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 103 | alert.setMessage("Delete " + user.getEmail() + "?"); 104 | alert.setCancelable(false); 105 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 106 | @Override 107 | public void onClick(DialogInterface dialogInterface, int i) { 108 | deleteUser(user); 109 | } 110 | }); 111 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 112 | @Override 113 | public void onClick(DialogInterface dialogInterface, int i) { 114 | dialogInterface.dismiss(); 115 | } 116 | }); 117 | alert.show(); 118 | break; 119 | } 120 | } 121 | 122 | private void updateUI(FirebaseUser user) { 123 | if (user != null) { 124 | // User's profile 125 | mTextViewProfile.setText("Firebase ID: " + user.getUid()); 126 | mTextViewProfile.append("\n"); 127 | mTextViewProfile.append("DisplayName: " + user.getDisplayName()); 128 | mTextViewProfile.append("\n"); 129 | mTextViewProfile.append("Email: " + user.getEmail()); 130 | mTextViewProfile.append("\n"); 131 | mTextViewProfile.append("Photo URL: " + user.getPhotoUrl()); 132 | 133 | // User's provider 134 | mTextViewProvider.setText(null); 135 | for (UserInfo profile : user.getProviderData()) { 136 | // Id of the provider (ex: google.com) 137 | mTextViewProvider.append("providerId: " + profile.getProviderId()); 138 | mTextViewProvider.append("\n"); 139 | 140 | // UID specific to the provider 141 | mTextViewProvider.append("UID: " + profile.getUid()); 142 | 143 | mTextViewProvider.append("\n"); 144 | mTextViewProvider.append("name: " + profile.getDisplayName()); 145 | mTextViewProvider.append("\n"); 146 | mTextViewProvider.append("email: " + profile.getEmail()); 147 | mTextViewProvider.append("\n"); 148 | mTextViewProvider.append("photoUrl: " + profile.getPhotoUrl()); 149 | if (!"password".equals(profile.getProviderId())) { 150 | mTextViewProvider.append("\n\n"); 151 | } 152 | } 153 | findViewById(R.id.provider_fields).setVisibility(View.VISIBLE); 154 | findViewById(R.id.update_profile_fields).setVisibility(View.VISIBLE); 155 | findViewById(R.id.update_email_fields).setVisibility(View.VISIBLE); 156 | findViewById(R.id.update_password_fields).setVisibility(View.VISIBLE); 157 | findViewById(R.id.send_password_reset_fields).setVisibility(View.VISIBLE); 158 | findViewById(R.id.delete_fields).setVisibility(View.VISIBLE); 159 | } else { 160 | mTextViewProfile.setText(R.string.signed_out); 161 | mTextViewProvider.setText(null); 162 | findViewById(R.id.provider_fields).setVisibility(View.GONE); 163 | findViewById(R.id.update_profile_fields).setVisibility(View.GONE); 164 | findViewById(R.id.update_email_fields).setVisibility(View.GONE); 165 | findViewById(R.id.update_password_fields).setVisibility(View.GONE); 166 | findViewById(R.id.send_password_reset_fields).setVisibility(View.GONE); 167 | findViewById(R.id.delete_fields).setVisibility(View.GONE); 168 | } 169 | hideProgressDialog(); 170 | } 171 | 172 | private void updateNameAndPhoto(FirebaseUser user) { 173 | showProgressDialog(); 174 | UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder() 175 | .setDisplayName(mEditTextName.getText().toString()) 176 | .setPhotoUri(Uri.parse(mEditTextPhoto.getText().toString())) 177 | .build(); 178 | user.updateProfile(profileUpdates).addOnCompleteListener(new OnCompleteListener() { 179 | @Override 180 | public void onComplete(@NonNull Task task) { 181 | if (task.isSuccessful()) { 182 | mTextViewProfile.setTextColor(Color.DKGRAY); 183 | mTextViewProfile.setText(getString(R.string.updated, "User profile")); 184 | } else { 185 | mTextViewProfile.setTextColor(Color.RED); 186 | mTextViewProfile.setText(task.getException().getMessage()); 187 | } 188 | hideProgressDialog(); 189 | } 190 | }); 191 | } 192 | 193 | private void updateEmail(FirebaseUser user) { 194 | showProgressDialog(); 195 | user.updateEmail(mEditTextEmail.getText().toString()).addOnCompleteListener(new OnCompleteListener() { 196 | @Override 197 | public void onComplete(@NonNull Task task) { 198 | if (task.isSuccessful()) { 199 | mTextViewProfile.setTextColor(Color.DKGRAY); 200 | mTextViewProfile.setText(getString(R.string.updated, "User email")); 201 | } else { 202 | mTextViewProfile.setTextColor(Color.RED); 203 | mTextViewProfile.setText(task.getException().getMessage()); 204 | } 205 | hideProgressDialog(); 206 | } 207 | }); 208 | } 209 | 210 | private void updatePassword(FirebaseUser user) { 211 | showProgressDialog(); 212 | user.updatePassword(mEditTextPassword.getText().toString()).addOnCompleteListener(new OnCompleteListener() { 213 | @Override 214 | public void onComplete(@NonNull Task task) { 215 | if (task.isSuccessful()) { 216 | if (task.isSuccessful()) { 217 | mTextViewProfile.setTextColor(Color.DKGRAY); 218 | mTextViewProfile.setText(getString(R.string.updated, "User password")); 219 | } else { 220 | mTextViewProfile.setTextColor(Color.RED); 221 | mTextViewProfile.setText(task.getException().getMessage()); 222 | } 223 | hideProgressDialog(); 224 | } 225 | } 226 | }); 227 | } 228 | 229 | private void sendPasswordReset() { 230 | showProgressDialog(); 231 | mAuth.sendPasswordResetEmail(mEditTextEmailReset.getText().toString()).addOnCompleteListener(new OnCompleteListener() { 232 | @Override 233 | public void onComplete(@NonNull Task task) { 234 | if (task.isSuccessful()) { 235 | mTextViewProfile.setTextColor(Color.DKGRAY); 236 | mTextViewProfile.setText("Email sent."); 237 | } else { 238 | mTextViewProfile.setTextColor(Color.RED); 239 | mTextViewProfile.setText(task.getException().getMessage()); 240 | } 241 | hideProgressDialog(); 242 | } 243 | }); 244 | } 245 | 246 | private void deleteUser(FirebaseUser user) { 247 | showProgressDialog(); 248 | user.delete().addOnCompleteListener(new OnCompleteListener() { 249 | @Override 250 | public void onComplete(@NonNull Task task) { 251 | if (task.isSuccessful()) { 252 | mTextViewProfile.setTextColor(Color.DKGRAY); 253 | mTextViewProfile.setText("User account deleted."); 254 | } else { 255 | mTextViewProfile.setTextColor(Color.RED); 256 | mTextViewProfile.setText(task.getException().getMessage()); 257 | } 258 | hideProgressDialog(); 259 | } 260 | }); 261 | } 262 | 263 | private boolean validateForm() { 264 | if (TextUtils.isEmpty(mEditTextName.getText().toString())) { 265 | mEditTextName.setError("Required."); 266 | return false; 267 | } else if (TextUtils.isEmpty(mEditTextPhoto.getText().toString())) { 268 | mEditTextPhoto.setError("Required."); 269 | return false; 270 | } else { 271 | mEditTextName.setError(null); 272 | return true; 273 | } 274 | } 275 | 276 | private boolean validateEmail(EditText edt) { 277 | String email = edt.getText().toString(); 278 | if (TextUtils.isEmpty(email)) { 279 | edt.setError("Required."); 280 | return false; 281 | } else if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) { 282 | edt.setError("Invalid."); 283 | return false; 284 | } else { 285 | edt.setError(null); 286 | return true; 287 | } 288 | } 289 | 290 | private boolean validatePassword() { 291 | String password = mEditTextPassword.getText().toString(); 292 | if (TextUtils.isEmpty(password)) { 293 | mEditTextPassword.setError("Required."); 294 | return false; 295 | } else { 296 | mEditTextPassword.setError(null); 297 | return true; 298 | } 299 | } 300 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/PhoneAuthActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.os.Bundle; 5 | import androidx.annotation.NonNull; 6 | import com.google.android.material.snackbar.Snackbar; 7 | import androidx.appcompat.app.AlertDialog; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import android.text.TextUtils; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Button; 13 | import android.widget.EditText; 14 | import android.widget.TextView; 15 | 16 | import com.google.android.gms.tasks.OnCompleteListener; 17 | import com.google.android.gms.tasks.Task; 18 | import com.google.firebase.FirebaseException; 19 | import com.google.firebase.FirebaseTooManyRequestsException; 20 | import com.google.firebase.auth.AuthResult; 21 | import com.google.firebase.auth.FirebaseAuth; 22 | import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException; 23 | import com.google.firebase.auth.FirebaseUser; 24 | import com.google.firebase.auth.PhoneAuthCredential; 25 | import com.google.firebase.auth.PhoneAuthProvider; 26 | 27 | import java.util.concurrent.TimeUnit; 28 | 29 | public class PhoneAuthActivity extends AppCompatActivity implements View.OnClickListener { 30 | private static final String KEY_VERIFY_IN_PROGRESS = "key_verify_in_progress"; 31 | 32 | private static final int STATE_INITIALIZED = 1; 33 | private static final int STATE_CODE_SENT = 2; 34 | private static final int STATE_VERIFY_FAILED = 3; 35 | private static final int STATE_VERIFY_SUCCESS = 4; 36 | private static final int STATE_SIGNIN_FAILED = 5; 37 | private static final int STATE_SIGNIN_SUCCESS = 6; 38 | 39 | private FirebaseAuth mAuth; 40 | 41 | private boolean mVerificationInProgress = false; 42 | private String mVerificationId; 43 | private PhoneAuthProvider.ForceResendingToken mResendToken; 44 | private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks; 45 | 46 | private ViewGroup mPhoneNumberViews; 47 | 48 | private TextView mTextViewProfile; 49 | 50 | private EditText mPhoneNumberField; 51 | private EditText mVerificationField; 52 | 53 | private Button mStartButton; 54 | private Button mVerifyButton; 55 | private Button mResendButton; 56 | private Button mSignOutButton; 57 | 58 | @Override 59 | protected void onCreate(Bundle savedInstanceState) { 60 | super.onCreate(savedInstanceState); 61 | setContentView(R.layout.activity_phone_auth); 62 | 63 | if (savedInstanceState != null) { 64 | onRestoreInstanceState(savedInstanceState); 65 | } 66 | mTextViewProfile = findViewById(R.id.profile); 67 | mPhoneNumberViews = findViewById(R.id.phone_auth_fields); 68 | 69 | mPhoneNumberField = findViewById(R.id.field_phone_number); 70 | mVerificationField = findViewById(R.id.field_verification_code); 71 | 72 | mStartButton = findViewById(R.id.button_start_verification); 73 | mVerifyButton = findViewById(R.id.button_verify_phone); 74 | mResendButton = findViewById(R.id.button_resend); 75 | mSignOutButton = findViewById(R.id.sign_out_button); 76 | 77 | mStartButton.setOnClickListener(this); 78 | mVerifyButton.setOnClickListener(this); 79 | mResendButton.setOnClickListener(this); 80 | mSignOutButton.setOnClickListener(this); 81 | 82 | mAuth = FirebaseAuth.getInstance(); 83 | 84 | // Initialize phone auth callbacks 85 | mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { 86 | @Override 87 | public void onVerificationCompleted(PhoneAuthCredential credential) { 88 | // This callback will be invoked in two situations: 89 | // 1 - Instant verification. In some cases the phone number can be instantly 90 | // verified without needing to send or enter a verification code. 91 | // 2 - Auto-retrieval. On some devices Google Play services can automatically 92 | // detect the incoming verification SMS and perform verificaiton without user action. 93 | mTextViewProfile.setText("onVerificationCompleted: " + credential); 94 | mVerificationInProgress = false; 95 | 96 | updateUI(STATE_VERIFY_SUCCESS, credential); 97 | signInWithPhoneAuthCredential(credential); 98 | } 99 | 100 | @Override 101 | public void onVerificationFailed(FirebaseException e) { 102 | mTextViewProfile.setText("onVerificationFailed: " + e.getMessage()); 103 | mVerificationInProgress = false; 104 | 105 | if (e instanceof FirebaseAuthInvalidCredentialsException) { 106 | mPhoneNumberField.setError("Invalid phone number."); 107 | } else if (e instanceof FirebaseTooManyRequestsException) { 108 | Snackbar.make(findViewById(android.R.id.content), "The SMS quota for the project has been exceeded", Snackbar.LENGTH_SHORT).show(); 109 | } 110 | updateUI(STATE_VERIFY_FAILED); 111 | } 112 | 113 | @Override 114 | public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) { 115 | // The SMS verification code has been sent to the provided phone number, we 116 | // now need to ask the user to enter the code and then construct a credential 117 | // by combining the code with a verification ID. 118 | 119 | mTextViewProfile.setText("onCodeSent: " + verificationId); 120 | 121 | // Save verification ID and resending token so we can use them later 122 | mVerificationId = verificationId; 123 | mResendToken = token; 124 | 125 | updateUI(STATE_CODE_SENT); 126 | } 127 | }; 128 | } 129 | 130 | @Override 131 | public void onStart() { 132 | super.onStart(); 133 | FirebaseUser currentUser = mAuth.getCurrentUser(); 134 | updateUI(currentUser); 135 | if (mVerificationInProgress && validatePhoneNumber()) { 136 | startPhoneNumberVerification(mPhoneNumberField.getText().toString()); 137 | } 138 | } 139 | 140 | @Override 141 | protected void onSaveInstanceState(Bundle outState) { 142 | super.onSaveInstanceState(outState); 143 | outState.putBoolean(KEY_VERIFY_IN_PROGRESS, mVerificationInProgress); 144 | } 145 | 146 | @Override 147 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 148 | super.onRestoreInstanceState(savedInstanceState); 149 | mVerificationInProgress = savedInstanceState.getBoolean(KEY_VERIFY_IN_PROGRESS); 150 | } 151 | 152 | private void startPhoneNumberVerification(String phoneNumber) { 153 | PhoneAuthProvider.getInstance().verifyPhoneNumber( 154 | phoneNumber, // Phone number to verify 155 | 60, // Timeout duration 156 | TimeUnit.SECONDS, // Unit of timeout 157 | this, // Activity (for callback binding) 158 | mCallbacks); // OnVerificationStateChangedCallbacks 159 | mVerificationInProgress = true; 160 | } 161 | 162 | private void verifyPhoneNumberWithCode(String verificationId, String code) { 163 | PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code); 164 | signInWithPhoneAuthCredential(credential); 165 | } 166 | 167 | private void resendVerificationCode(String phoneNumber, PhoneAuthProvider.ForceResendingToken token) { 168 | PhoneAuthProvider.getInstance().verifyPhoneNumber( 169 | phoneNumber, // Phone number to verify 170 | 60, // Timeout duration 171 | TimeUnit.SECONDS, // Unit of timeout 172 | this, // Activity (for callback binding) 173 | mCallbacks, // OnVerificationStateChangedCallbacks 174 | token); // ForceResendingToken from callbacks 175 | } 176 | 177 | private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) { 178 | mAuth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener() { 179 | @Override 180 | public void onComplete(@NonNull Task task) { 181 | if (task.isSuccessful()) { 182 | FirebaseUser user = task.getResult().getUser(); 183 | updateUI(STATE_SIGNIN_SUCCESS, user); 184 | } else { 185 | if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) { 186 | mVerificationField.setError(task.getException().getMessage()); 187 | } 188 | updateUI(STATE_SIGNIN_FAILED); 189 | } 190 | } 191 | }); 192 | } 193 | 194 | private void signOut() { 195 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 196 | alert.setMessage(R.string.logout); 197 | alert.setCancelable(false); 198 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 199 | @Override 200 | public void onClick(DialogInterface dialogInterface, int i) { 201 | mAuth.signOut(); 202 | updateUI(STATE_INITIALIZED); 203 | } 204 | }); 205 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 206 | @Override 207 | public void onClick(DialogInterface dialogInterface, int i) { 208 | dialogInterface.dismiss(); 209 | } 210 | }); 211 | alert.show(); 212 | } 213 | 214 | private void updateUI(int uiState) { 215 | updateUI(uiState, mAuth.getCurrentUser(), null); 216 | } 217 | 218 | private void updateUI(FirebaseUser user) { 219 | if (user != null) { 220 | updateUI(STATE_SIGNIN_SUCCESS, user); 221 | } else { 222 | updateUI(STATE_INITIALIZED); 223 | } 224 | } 225 | 226 | private void updateUI(int uiState, FirebaseUser user) { 227 | updateUI(uiState, user, null); 228 | } 229 | 230 | private void updateUI(int uiState, PhoneAuthCredential cred) { 231 | updateUI(uiState, null, cred); 232 | } 233 | 234 | private void updateUI(int uiState, FirebaseUser user, PhoneAuthCredential cred) { 235 | switch (uiState) { 236 | case STATE_INITIALIZED: 237 | enableViews(mStartButton, mPhoneNumberField); 238 | disableViews(mVerifyButton, mResendButton, mVerificationField); 239 | mTextViewProfile.setText(null); 240 | break; 241 | case STATE_CODE_SENT: 242 | enableViews(mVerifyButton, mResendButton, mPhoneNumberField, mVerificationField); 243 | disableViews(mStartButton); 244 | break; 245 | case STATE_VERIFY_FAILED: 246 | enableViews(mStartButton, mVerifyButton, mResendButton, mPhoneNumberField, mVerificationField); 247 | break; 248 | case STATE_VERIFY_SUCCESS: 249 | disableViews(mStartButton, mVerifyButton, mResendButton, mPhoneNumberField, mVerificationField); 250 | mTextViewProfile.append("\n" + getString(R.string.status_verification_succeeded)); 251 | 252 | // Set the verification text based on the credential 253 | if (cred != null) { 254 | if (cred.getSmsCode() != null) { 255 | mVerificationField.setText(cred.getSmsCode()); 256 | } else { 257 | mVerificationField.setText(R.string.instant_validation); 258 | } 259 | } 260 | break; 261 | case STATE_SIGNIN_FAILED: 262 | mTextViewProfile.setText(R.string.status_sign_in_failed); 263 | break; 264 | case STATE_SIGNIN_SUCCESS: 265 | // Np-op, handled by sign-in check 266 | break; 267 | } 268 | 269 | if (user == null) { 270 | mPhoneNumberViews.setVisibility(View.VISIBLE); 271 | mSignOutButton.setVisibility(View.GONE); 272 | } else { 273 | mPhoneNumberViews.setVisibility(View.GONE); 274 | mSignOutButton.setVisibility(View.VISIBLE); 275 | 276 | enableViews(mPhoneNumberField, mVerificationField); 277 | mPhoneNumberField.setText(null); 278 | mVerificationField.setText(null); 279 | 280 | mTextViewProfile.append( 281 | "\n\n" + getString(R.string.firebase_status_fmt, user.getUid()) 282 | + "\nDisplay: " + user.getDisplayName() 283 | + "\nEmail: " + user.getEmail() 284 | + "\nPhoneNumber: " + user.getPhoneNumber() 285 | + "\nPhotoUrl: " + user.getPhotoUrl() 286 | + "\nProviderId: " + user.getProviderId() 287 | ); 288 | } 289 | } 290 | 291 | private boolean validatePhoneNumber() { 292 | String phoneNumber = mPhoneNumberField.getText().toString(); 293 | if (TextUtils.isEmpty(phoneNumber)) { 294 | mPhoneNumberField.setError("Invalid phone number."); 295 | return false; 296 | } 297 | return true; 298 | } 299 | 300 | private void enableViews(View... views) { 301 | for (View v : views) { 302 | v.setEnabled(true); 303 | } 304 | } 305 | 306 | private void disableViews(View... views) { 307 | for (View v : views) { 308 | v.setEnabled(false); 309 | } 310 | } 311 | 312 | @Override 313 | public void onClick(View view) { 314 | switch (view.getId()) { 315 | case R.id.button_start_verification: 316 | if (!validatePhoneNumber()) { 317 | return; 318 | } 319 | startPhoneNumberVerification(mPhoneNumberField.getText().toString()); 320 | break; 321 | case R.id.button_verify_phone: 322 | String code = mVerificationField.getText().toString(); 323 | if (TextUtils.isEmpty(code)) { 324 | mVerificationField.setError("Cannot be empty."); 325 | return; 326 | } 327 | verifyPhoneNumberWithCode(mVerificationId, code); 328 | break; 329 | case R.id.button_resend: 330 | resendVerificationCode(mPhoneNumberField.getText().toString(), mResendToken); 331 | break; 332 | case R.id.sign_out_button: 333 | signOut(); 334 | break; 335 | } 336 | } 337 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/auth/TwitterLoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.auth; 2 | 3 | import android.content.DialogInterface; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Color; 8 | import android.os.AsyncTask; 9 | import android.os.Bundle; 10 | import androidx.annotation.NonNull; 11 | import androidx.appcompat.app.AlertDialog; 12 | import android.util.Log; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.TextView; 16 | 17 | import com.google.android.gms.tasks.OnCompleteListener; 18 | import com.google.android.gms.tasks.Task; 19 | import com.google.firebase.auth.AuthCredential; 20 | import com.google.firebase.auth.AuthResult; 21 | import com.google.firebase.auth.FirebaseAuth; 22 | import com.google.firebase.auth.FirebaseUser; 23 | import com.google.firebase.auth.TwitterAuthProvider; 24 | import com.twitter.sdk.android.Twitter; 25 | import com.twitter.sdk.android.core.Callback; 26 | import com.twitter.sdk.android.core.Result; 27 | import com.twitter.sdk.android.core.TwitterAuthConfig; 28 | import com.twitter.sdk.android.core.TwitterException; 29 | import com.twitter.sdk.android.core.TwitterSession; 30 | import com.twitter.sdk.android.core.identity.TwitterLoginButton; 31 | 32 | import java.io.InputStream; 33 | import java.net.URL; 34 | 35 | import io.fabric.sdk.android.Fabric; 36 | 37 | public class TwitterLoginActivity extends BaseActivity implements View.OnClickListener { 38 | private static final String TAG = "TwitterLoginActivity"; 39 | private FirebaseAuth mAuth; 40 | private FirebaseAuth.AuthStateListener mAuthListener; 41 | private ImageView mImageView; 42 | private TextView mTextViewProfile; 43 | private TwitterLoginButton mLoginButton; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | 49 | // Configure Twitter SDK 50 | TwitterAuthConfig authConfig = new TwitterAuthConfig( 51 | getString(R.string.twitter_consumer_key), 52 | getString(R.string.twitter_consumer_secret) 53 | ); 54 | Fabric.with(this, new Twitter(authConfig)); 55 | 56 | // Inflate layout (must be done after Twitter is configured) 57 | setContentView(R.layout.activity_twitter); 58 | 59 | mImageView = findViewById(R.id.logo); 60 | mTextViewProfile = findViewById(R.id.profile); 61 | findViewById(R.id.button_twitter_signout).setOnClickListener(this); 62 | 63 | mAuth = FirebaseAuth.getInstance(); 64 | mAuthListener = new FirebaseAuth.AuthStateListener() { 65 | @Override 66 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 67 | FirebaseUser user = firebaseAuth.getCurrentUser(); 68 | if (user != null) { 69 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 70 | } else { 71 | Log.d(TAG, "onAuthStateChanged:signed_out"); 72 | } 73 | updateUI(user); 74 | } 75 | }; 76 | 77 | // initialize_twitter_login 78 | mLoginButton = findViewById(R.id.button_twitter_login); 79 | mLoginButton.setCallback(new Callback() { 80 | @Override 81 | public void success(Result result) { 82 | Log.d(TAG, "twitterLogin:success" + result); 83 | handleTwitterSession(result.data); 84 | } 85 | 86 | @Override 87 | public void failure(TwitterException exception) { 88 | Log.w(TAG, "twitterLogin:failure", exception); 89 | updateUI(null); 90 | } 91 | }); 92 | } 93 | 94 | @Override 95 | public void onStart() { 96 | super.onStart(); 97 | mAuth.addAuthStateListener(mAuthListener); 98 | } 99 | 100 | @Override 101 | public void onStop() { 102 | super.onStop(); 103 | if (mAuthListener != null) { 104 | mAuth.removeAuthStateListener(mAuthListener); 105 | } 106 | } 107 | 108 | @Override 109 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 110 | super.onActivityResult(requestCode, resultCode, data); 111 | 112 | // Pass the activity result to the Twitter login button. 113 | mLoginButton.onActivityResult(requestCode, resultCode, data); 114 | } 115 | 116 | // auth_with_twitter 117 | private void handleTwitterSession(TwitterSession session) { 118 | Log.d(TAG, "handleTwitterSession:" + session); 119 | showProgressDialog(); 120 | 121 | AuthCredential credential = TwitterAuthProvider.getCredential( 122 | session.getAuthToken().token, 123 | session.getAuthToken().secret 124 | ); 125 | 126 | mAuth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener() { 127 | @Override 128 | public void onComplete(@NonNull Task task) { 129 | Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful()); 130 | if (!task.isSuccessful()) { 131 | mTextViewProfile.setTextColor(Color.RED); 132 | mTextViewProfile.setText(task.getException().getMessage()); 133 | } else { 134 | mTextViewProfile.setTextColor(Color.DKGRAY); 135 | } 136 | hideProgressDialog(); 137 | } 138 | }); 139 | } 140 | 141 | private void signOut() { 142 | AlertDialog.Builder alert = new AlertDialog.Builder(this); 143 | alert.setMessage(R.string.logout); 144 | alert.setCancelable(false); 145 | alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 146 | @Override 147 | public void onClick(DialogInterface dialogInterface, int i) { 148 | mAuth.signOut(); 149 | Twitter.logOut(); 150 | updateUI(null); 151 | } 152 | }); 153 | alert.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { 154 | @Override 155 | public void onClick(DialogInterface dialogInterface, int i) { 156 | dialogInterface.dismiss(); 157 | } 158 | }); 159 | alert.show(); 160 | } 161 | 162 | private void updateUI(FirebaseUser user) { 163 | if (user != null) { 164 | if (user.getPhotoUrl() != null) { 165 | new DownloadImageTask().execute(user.getPhotoUrl().toString()); 166 | } 167 | mTextViewProfile.setText("DisplayName: " + user.getDisplayName()); 168 | mTextViewProfile.append("\n\n"); 169 | mTextViewProfile.append("Email: " + user.getEmail()); 170 | mTextViewProfile.append("\n\n"); 171 | mTextViewProfile.append("Firebase ID: " + user.getUid()); 172 | 173 | findViewById(R.id.button_twitter_login).setVisibility(View.GONE); 174 | findViewById(R.id.button_twitter_signout).setVisibility(View.VISIBLE); 175 | } else { 176 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 64; 177 | mImageView.setImageResource(R.mipmap.authentication); 178 | mTextViewProfile.setText(null); 179 | 180 | findViewById(R.id.button_twitter_login).setVisibility(View.VISIBLE); 181 | findViewById(R.id.button_twitter_signout).setVisibility(View.GONE); 182 | } 183 | hideProgressDialog(); 184 | } 185 | 186 | @Override 187 | public void onClick(View v) { 188 | switch (v.getId()) { 189 | case R.id.button_twitter_signout: 190 | signOut(); 191 | break; 192 | } 193 | } 194 | 195 | private class DownloadImageTask extends AsyncTask { 196 | @Override 197 | protected Bitmap doInBackground(String... urls) { 198 | Bitmap mIcon = null; 199 | try { 200 | InputStream in = new URL(urls[0]).openStream(); 201 | mIcon = BitmapFactory.decodeStream(in); 202 | } catch (Exception e) { 203 | e.printStackTrace(); 204 | } 205 | return mIcon; 206 | } 207 | 208 | @Override 209 | protected void onPostExecute(Bitmap result) { 210 | if (result != null) { 211 | mImageView.getLayoutParams().width = (getResources().getDisplayMetrics().widthPixels / 100) * 24; 212 | mImageView.setImageBitmap(result); 213 | } 214 | } 215 | } 216 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_anonymous_auth.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 19 | 20 | 26 | 27 | 33 | 34 |