Wednesday, 5 October 2016

Social Media with Firebase Authentication in Android

     Now a days most of an application need to know the user's identity to use an application. Knowing a user's identity allows an app to securely save user data in the cloud and provide the same personalized experience across all of the user's devices.

Firebase Authentication provides backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app. It supports authentication using passwords, popular federated identity providers like Google, Facebook and Twitter, and more.

Firebase Authentication integrates tightly with other Firebase services, and it leverages industry standards like OAuth 2.0 and OpenID Connect, so it can be easily integrated with your custom backend.


What is Firebase?
 
Firebase is a cloud service provider. It is now under google and this service can replace your whole server side part of your application. In many tutorials we had used MySQL and PHP for our database. But if we will use Firebase we do not need any server side code or configuration. We can directly use firebase. Firebase comes with a bundle of many features.

Features of Firebase: 



Key Capabilities:
  1. FirebaseUI (beta) : The FirebaseUI Auth component implements best practices for authentication on mobile devices and websites, which can maximize sign-in and sign-up conversion for your app. It also handles edge cases like account recovery and account linking that can be security sensitive and error-prone to handle correctly.
  2. Email and Password based authentication: The Firebase Authentication SDK provides methods to create and manage users that use their email addresses and passwords to sign in. Firebase Authentication also handles sending password reset emails.
  3. Federated identity proivder integration: Authentication SDK provides methods to allow users to sign in with their Google,Facebook,Twitter, and Github accounts.
  4. Custom auth system integration: Connect your app's existing sign-in system to the Firebase Authentication SDK and gain access to Firebase Realtime Database and other Firebase services.
  5. Anonymous auth: Use Firebase features that require authentication without requiring users to sign in first by creating temporary anonymous accounts. If the user later chooses to sign up, you can upgrade the anonymous account to a regular account, so the user can continue where they left off.
Advantages of Firebase:
  • Super easy and quick to implement.
  • No server side configuration needed. No PHP Scripts and No Database Designs.
  • Realtime update without using GCM.
  • Autoscaling built-in.
  • Can start for free (only need to start paying once we hit 50 connections)
  • Robust APIs for Javascript (including several frameworks like Angular), iOS, and Android.
  • Built-in support for authentication services like Facebook, Google, and Twitter.
  • Declarative Security Rules model allows us to enforce read/write privileges and data validation throughout the tree.
Disadvantages of Firebase:
  • Need to build indexes manually.
  • May need to build “event log” manually as well (in separate sub-tree?).
  • Implementation of REST API could be difficult on embedded platforms.
  • Data validation rules do not support complex objects directly (you’d need to validate individual child nodes separately).
Add Firebase to your Android Project:
Below are the steps you need to follow to configure firebase in your application.
               Create a Firebase project in the Firebase console, if you don't already have one. If you already have an existing Google project associated with your mobile app, click Import Google Project. Otherwise, click Create New Project.
  1. Click Add Firebase to your Android app and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just download the config file.
  2. When prompted, enter your app's package name. It's important to enter the package name your app is using; this can only be set when you add an app to your Firebase project.
  3. At the end, you'll download a google-services.json file. You can download this file again at any time.
  4. If you haven't done so already, copy this into your project's module folder, typically app/.

Available Libraries
The following libraries are available for the various Firebase features.

Configure Gradle
 First, add rules to your project-level build.gradle file, to include the google-services plugin:
 // Top-level build file where you can add configuration options common to all sub-projects/modules.  
 buildscript {  
   repositories {  
     jcenter()  
   }  
   dependencies {  
     classpath 'com.android.tools.build:gradle:2.1.2'  
     //you need to add this line   
     classpath 'com.google.gms:google-services:3.0.0'  
     // NOTE: Do not place your application dependencies here; they belong  
     // in the individual module build.gradle files  
   }  
 }  
 allprojects {  
   repositories {  
     jcenter()  
   }  
 }  
 task clean(type: Delete) {  
   delete rootProject.buildDir  
 }  

Then, in your module Gradle file (usually the app/build.gradle), add the apply plugin line at the bottom of the file to enable the Gradle plugin:
 apply plugin: 'com.android.application'  
 android {  
   compileSdkVersion 24  
   buildToolsVersion "24.0.0"  
   defaultConfig {  
     applicationId "net.simplifiedcoding.firebaseauthdemo"  
     minSdkVersion 15  
     targetSdkVersion 24  
     versionCode 1  
     versionName "1.0"  
   }  
   buildTypes {  
     release {  
       minifyEnabled false  
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
     }  
   }  
 }  
 dependencies {  
   compile fileTree(dir: 'libs', include: ['*.jar'])  
   testCompile 'junit:junit:4.12'  
   compile 'com.android.support:appcompat-v7:24.0.0'  
 }  
 //add the following line  
 apply plugin: 'com.google.gms.google-services'  

Various Social Firebase Authentication Types:
Firebase authentication provides different ways to authenticate users in your application.
  1. Authenticate through Email
  2. Authenticate through Google
  3. Authenticate through Facebook
  4. Authenticate through Twitter
      1) Authenticate through Email

         Step#1 : To authenticate user with an email address using Firebase Authetication you need to first initialize the FirebaseAuth instance in your activities onCreate() method as below:
 public class SignupActivity extends FragmentActivity {  
 FirebaseAuth mFirebaseAuth;  
 @Override  
 protected void onCreate(Bundle savedInstanceState) {  
   super.onCreate(savedInstanceState);  
   setContentView(R.layout.activity_signup);  
 //initializing firebase auth object  
   mFirebaseAuth = FirebaseAuth.getInstance();  
 }  

Step#2 : After initializing an instance you need to the user for their Email address and Password to authenticate them in an application using createUserWithEmailAndPassword() method from the Firebase instance object. This method takes two String paramteres for email and password and the OnCompletionListener to check for the task completion.
 mFirebaseAuth.createUserWithEmailAndPassword(mEmail, mPassword).addOnCompleteListener  
     (this, new OnCompleteListener<AuthResult>() {  
       @Override  
       public void onComplete(@NonNull Task<AuthResult> task) {  
         if (task.isSuccessful()) {  
           Snackbar.make(pView, "Authentication Successfull!", Snackbar.LENGTH_SHORT).show();   
         } else {  
           Snackbar.make(pView, "Authentication Failed!", Snackbar.LENGTH_SHORT)  
               .show();  
         }  
       }  
     });  
That's it. FirebaseAuth API has made the authentication process so easy and faster.

        A Firebase User has fixed set of basic properties -a unique ID,a primary email address, a name and a photo URL- stored in the project's user database, that can be updated by the user.You can not add other properties to the Firebase User object directly; instead, you can store the additional properties in your Firebase Realtime Database.

The first time a user signs up to your app, the user's profile data is populated using the available information:
  • If the user signed up with an email address and password, only the primary email address property is populated
  • If the user signed up with a federated identity provider, such as Google or Facebook, the account information made available by the provider is used to populate the Firebase User's profile.
  • If the user signed up with your custom auth system, you must explicitly add the information you want to the Firebase User's profile.
Once a user account has been created, you can reload the user's information to incorporate any changes the user might have made on another device. But if the user signout the Auth instance stops keeping a reference of the user object and no longer persists its state; there is no current user available. One way to track the current state of the Firebase Auth instance is the listener.

An auth listener gets notified in the following situations:
  • The Auth object finishes initializing and a user was already signed in from a previous session, or has been redirected from an identity provider's sign-in flow.
  • A user signs in (the current user is set)
  • A user signs out (the current user becomes null)
The current user's access token is refreshed. This case can happen in the following conditions:
  • The access token expires: this is a common situation. The refresh token is used to get a new valid set of tokens.
  • The user changes his password: Firebase issues new access and refresh tokens and renders the old tokens expired. This automatically signs out the user on every device, for security reasons
  • The user re-authenticates: some actions require that the user's credentials are recently issued; such actions include deleting an account, setting a primary email address, and changing a password. Instead of signing out the user and then signing in the user again, get new credentials from the user, and pass the new credentials to the re-authenticate method of the User object.

Auth Tokens generated by Firebase Auth:
When you perform authentication with Firebase, there are three kinds of auth tokens you might encounter:

Getting Signed In User's details
    Firebase Auth allows you to access the basic details of the signed In user as below:  
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 if (user != null) {  
   // User is signed in  
 } else {  
   // No user is signed in  
 }  
To get a user's profile information, use the accessor methods of an instance of FirebaseUser. For example:
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 if (user != null) {  
   // Name, email address, and profile photo Url  
      String name = user.getDisplayName();  
      String email = user.getEmail();  
      Uri photoUrl = user.getPhotoUrl();  
      // The user's ID, unique to the Firebase project. Do NOT use this value to  
      // authenticate with your backend server, if you have one. Use  
      // FirebaseUser.getToken() instead.  
      String uid = user.getUid();  
 }  
Update User's Profile details
You can update User's basic Profile information i.e. User's name, a photo using updateProfile method.
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()  
      .setDisplayName("Q. User")  
      .setPhotoUri(Uri.parse("https://example.com/profile.jpg"))  
      .build();  
 user.updateProfile(profileUpdates)  
      .addOnCompleteListener(new OnCompleteListener<Void>() {  
            @Override  
            public void onComplete(@NonNull Task<Void> task) {  
                if (task.isSuccessful()) {  
                 Log.d(TAG, "User profile updated.");  
                }  
           }  
      });  
Update User's Email address
You can set a user's email address with the updateEmail method.
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 user.updateEmail("user@example.com")  
      .addOnCompleteListener(new OnCompleteListener<Void>() {  
           @Override  
           public void onComplete(@NonNull Task<Void> task) {  
                if (task.isSuccessful()) {  
                     Log.d(TAG, "User email address updated.");  
                }  
           }  
      });  

Send an Email Verification
You can send an address verification email to a user with the sendEmailVerification method. For example:
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 user.sendEmailVerification()  
      .addOnCompleteListener(new OnCompleteListener<Void>() {  
           @Override  
           public void onComplete(@NonNull Task<Void> task) {  
                if (task.isSuccessful()) {  
                     Log.d(TAG, "Email sent.");  
                }  
           }  
      });  

Update User's Password
You can set a user's password with the updatePassword method. For example:
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 String newPassword = "SOME-SECURE-PASSWORD";  
 user.updatePassword(newPassword)  
      .addOnCompleteListener(new OnCompleteListener<Void>() {  
           @Override  
           public void onComplete(@NonNull Task<Void> task) {  
                if (task.isSuccessful()) {  
                     Log.d(TAG, "User password updated.");  
                }  
           }  
      });  

Send Password Re-set Email
You can send a password reset email to a user with the sendPasswordResetEmail method. For example:
 FirebaseAuth auth = FirebaseAuth.getInstance();  
 String emailAddress = "user@example.com";  
 auth.sendPasswordResetEmail(emailAddress)  
      .addOnCompleteListener(new OnCompleteListener<Void>() {  
           @Override  
            public void onComplete(@NonNull Task<Void> task) {  
                if (task.isSuccessful()) {  
                     Log.d(TAG, "Email sent.");  
                }  
           }  
      });  

Delete SignedIn User
You can customize the email template that is used in Authentication section of the Firebase console, on the Email Templates page. You can delete a user account with the delete method. For example:
 FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();  
 user.delete()  
      .addOnCompleteListener(new OnCompleteListener<Void>() {  
           @Override  
           public void onComplete(@NonNull Task<Void> task) {  
                if (task.isSuccessful()) {  
                     Log.d(TAG, "User account deleted.");  
                }  
            }  
      });  

2) Authenticate through Google
       You can let your users authenticate with Firebase using their Google Accounts by integrating Google Sign-In into your app. To enable Google Sign-In follow integration steps.

Before authenticating from your Google account using Firebase, it is necessary to complete the following steps to enable Google Sign-In in Firebase:
  • Add Firebase to your Android project.
  • Add the dependencies for Firebase Authentication and Google Sign-In to your app-level build.gradle file:
      • compile 'com.google.firebase:firebase-auth:9.6.0'
      • compile 'com.google.android.gms:play-services-auth:9.6.0'
  • If you haven't yet connected your app to your Firebase project, do so from the Firebase console.
  • Enable Google Sign-In in the Firebase console:
      1. In the Firebase console, open the Auth section.
      2. On the Sign in method tab, enable the Google sign-in method and click Save.
Authenticate Google with Firebase
  1. Integrate Google Sign-In into your app by following the steps on the Integrating Google Sign-In into Your Android App page. When you configure the GoogleSignInOptions object, call requestIdToken:
 // Configure Google Sign In  
       GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)  
                .requestIdToken(getString(R.string.default_web_client_id))  
                .requestEmail()  
                .build();  
You must pass your server's client ID to the requestIdToken method. To find the OAuth 2.0 client ID:
  1. Open the Credentials page in the API Console.
  2. The Web application type client ID is your backend server's OAuth 2.0 client ID.
After you integrate Google Sign-In, your sign-in activity has code similar to the following:
 private void signIn() {  
      Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);  
      startActivityForResult(signInIntent, RC_SIGN_IN);  
       }  
      @Override  
 public void onActivityResult(int requestCode, int resultCode, Intent data) {  
           super.onActivityResult(requestCode, resultCode, data);  
            // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);  
           if (requestCode == RC_SIGN_IN) {  
       GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);  
            if (result.isSuccess()) {  
            // Google Sign In was successful, authenticate with Firebase  
       GoogleSignInAccount account = result.getSignInAccount();  
      firebaseAuthWithGoogle(account);  
      } else {  
       // Google Sign In failed, update UI appropriately  
       // ...  
           }  
      }  
  }  
2. In your sign-in activity's onCreate() method, get the shared instance of the FirebaseAuth object:
  private FirebaseAuth mAuth;  
           // ...  
  mAuth = FirebaseAuth.getInstance();  
3.Set up an AuthStateListener that responds to changes in the user's sign-in state:
  private FirebaseAuth.AuthStateListener mAuthListener;  
      // ...  
 @Override  
 protected void onCreate(Bundle savedInstanceState) {  
   // ...  
   mAuthListener = new FirebaseAuth.AuthStateListener() {  
     @Override  
     public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {  
       FirebaseUser user = firebaseAuth.getCurrentUser();  
       if (user != null) {  
         // User is signed in  
         Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());  
       } else {  
         // User is signed out  
         Log.d(TAG, "onAuthStateChanged:signed_out");  
       }  
       // ...  
     }  
   };  
   // ...  
 }  
   @Override  
   public void onStart() {  
     super.onStart();  
     mAuth.addAuthStateListener(mAuthListener);  
   }  
   @Override  
   public void onStop() {  
     super.onStop();  
     if (mAuthListener != null) {  
       mAuth.removeAuthStateListener(mAuthListener);  
     }  
   }  

4.After a user successfully signs in, get an ID token from the GoogleSignInAccount object, exchange
 it for a Firebase credential, and authenticate with Firebase using the Firebase credential:
 private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {  
     Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());  
     AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);  
     mAuth.signInWithCredential(credential)  
         .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {  
           @Override  
           public void onComplete(@NonNull Task<AuthResult> task) {  
             Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());  
             // If sign in fails, display a message to the user. If sign in succeeds  
             // the auth state listener will be notified and logic to handle the  
             // signed in user can be handled in the listener.  
             if (!task.isSuccessful()) {  
               Log.w(TAG, "signInWithCredential", task.getException());  
               Toast.makeText(GoogleSignInActivity.this, "Authentication failed.",  
                   Toast.LENGTH_SHORT).show();  
             }  
             // ...  
           }  
         });  
   }  

If the call to signInWithCredentialsucceeds, the AuthStateListenerruns theonAuthStateChanged callback. 
In the callback, you can use the getCurrentUser method to get the user's account data.
You can allow users to sign in to your app using multiple authentication providers by linking auth provider credentials to an existing user account.
3) Authenticate through Facebook
You can let your users authenticate with Firebase using their Facebook accounts by integrating Facebook Login into your app by follow below steps.

Steps of Facebook Integration:
  1. Add Firebase to your Android project.
  2. If you haven't yet connected your app to your Firebase project, do so from the Firebase console.
  3. Add the dependency for Firebase Authentication to your app-level build.gradle file:
      compile 'com.google.firebase:firebase-auth:9.6.0'
  4. On the Facebook for Developers site, get the App ID and an App Secret for your app.
  5. Enable Facebook Login:
    1. In the Firebase console, open the Auth section.
    2. On the Sign in method tab, enable the Facebook sign-in method and specify the App ID and App Secret you got from Facebook.
    3. Then, make sure your OAuth redirect URI(e.g. my-app-12345.firebaseapp.com/__/auth/handler) is listed as one of your OAuth redirect URIs in your Facebook app's settings page on the Facebook for Developers site in the Product Settings > Facebook Login config.
Authenticate Facebook with Firebase


Integrate Facebook Login into your app by following the developer's documentation. When you configure the LoginButton or LoginManager object, request the public_profile and email permissions. If you integrated Facebook Login using a LoginButton, your sign-in activity has code similar the following:
 // Initialize Facebook Login button  
 mCallbackManager = CallbackManager.Factory.create();  
 LoginButton loginButton = (LoginButton) findViewById(R.id.button_facebook_login);  
 loginButton.setReadPermissions("email", "public_profile");  
 loginButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {  
      @Override  
      public void onSuccess(LoginResult loginResult) {  
        Log.d(TAG, "facebook:onSuccess:" + loginResult);  
        handleFacebookAccessToken(loginResult.getAccessToken());  
      }  
    @Override  
      public void onCancel() {  
            Log.d(TAG, "facebook:onCancel");  
      }  
      @Override  
      public void onError(FacebookException error) {  
           Log.d(TAG, "facebook:onError", error);  
      }  
 });  

After a user successfully signs in, in the LoginButton's onSuccess callback method, get an access token for the signed-in user, exchange it for a Firebase credential, and authenticate with Firebase using the Firebase credential:
 private void handleFacebookAccessToken(AccessToken token) {  
      Log.d(TAG, "handleFacebookAccessToken:" + token);  
      AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());  
      mAuth.signInWithCredential(credential)  
           .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {  
                @Override  
                public void onComplete(@NonNull Task<AuthResult> task) {  
                     Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());  
                // If sign in fails, display a message to the user. If sign in succeeds  
                // the auth state listener will be notified and logic to handle the  
                // signed in user can be handled in the listener.  
                if (!task.isSuccessful()) {  
                     Log.w(TAG, "signInWithCredential", task.getException());  
      Toast.makeText(FacebookLoginActivity.this, "Authentication failed.",  
      Toast.LENGTH_SHORT).show();  
                }  
                }  
           });  
 }  
If the call to signInWithCredential succeeds, the AuthStateListener runs the onAuthStateChanged callback. In the callback, you can use the getCurrentUser method to get user's account data.

Note: For the Facebook authentication you have to make a registered user of facebook developer console live until and unless you won't be able to test its configuration flow. Otherwise, you will get an error like: App Not Setup: The developers of this app have not set up this app properly for Facebook Login. To resolve this error you need to make user live, as per given solution here: http://stackoverflow.com/a/26135600/1839336. After completing this configuration process you will be able to check the facebook authentication flow. Not up to here I also got the following error :
Given URL is not allowed by the Application configuration.: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains.
 It has been solved after adding our application in platform tab with all the details and generate key hashes using Generate facebook Key Hashes: keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64  and mentioned solution as here: http://stackoverflow.com/a/16347026/1839336 

4) Authenticate through Twitter
We can also let the users use their Twitter account to authenticate with Firebase.As you will have to sign in using Twitter, you will have to go through all the steps required to integrate Twitter in your app. If you haven't done so, follow the steps specified in Twitter For Developers.
Steps of Twitter Integration:
  1. Add Firebase to your Android project.
  2. If you haven't yet connected your app to your Firebase project, do so from the Firebase console.
  3. Add the dependency for Firebase Authentication to your app-level build.gradle file:
      compile 'com.google.firebase:firebase-auth:9.6.0'
  4. Register your app as a developer application on Twitter and get your app's API Key and API Secret.
  5. Enable Twitter Login:
    1. In the Firebase console, open the Auth section.
    2. On the Sign in method tab, enable the Twitter sign-in method and specify the API Key and API Secret you got from Twitter.
      Then, make sure your OAuth redirect URI(e.g. my-app-12345.firebaseapp.com/__/auth/handler) is set as your Callback URL in your app's settings page on your Twitter app's config.
Authenticate Twitter with Firebase
  1. Integrate Sign in with Twitter into your app by following the developer's documentation. At the end of the Twitter sign-in flow, you will receive an OAuth access token and an OAuth secret.
  2. Initialize FirebaseAuth in your activities onCreate method.
  3. Set up an AuthStateListener that responds to changes in the user's sign-in state:
 private FirebaseAuth.AuthStateListener mAuthListener;  
 @Override  
 protected void onCreate(Bundle savedInstanceState) {  
   mAuthListener = new FirebaseAuth.AuthStateListener() {  
     @Override  
     public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {  
       FirebaseUser user = firebaseAuth.getCurrentUser();  
       if (user != null) {  
         // User is signed in  
         Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());  
       } else {  
         // User is signed out  
         Log.d(TAG, "onAuthStateChanged:signed_out");  
       }        
     }  
   };  
 }  
 @Override  
 public void onStart() {  
   super.onStart();  
   mAuth.addAuthStateListener(mAuthListener);  
 }  
 @Override  
 public void onStop() {  
   super.onStop();  
   if (mAuthListener != null) {  
     mAuth.removeAuthStateListener(mAuthListener);  
   }  
 }  

4.After a user successfully signs in with Twitter, exchange the OAuth access token and OAuth secret for a 
Firebase credential, and authenticate with Firebase using the Firebase credential:
 private void handleTwitterSession(TwitterSession session) {  
   Log.d(TAG, "handleTwitterSession:" + session);  
   AuthCredential credential = TwitterAuthProvider.getCredential(  
       session.getAuthToken().token,  
       session.getAuthToken().secret);  
   mAuth.signInWithCredential(credential)  
       .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {  
         @Override  
         public void onComplete(@NonNull Task<AuthResult> task) {  
           Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());  
           // If sign in fails, display a message to the user. If sign in succeeds  
           // the auth state listener will be notified and logic to handle the  
           // signed in user can be handled in the listener.  
           if (!task.isSuccessful()) {  
             Log.w(TAG, "signInWithCredential", task.getException());  
             Toast.makeText(TwitterLoginActivity.this, "Authentication failed.",  
                 Toast.LENGTH_SHORT).show();  
           }  
         }  
       });  
 }  

If the call to signInWithCredential succeeds, the AuthStateListener runs the onAuthStateChanged callback.
In the callback, you can use the getCurrentUser method to get the user's account data.

Signout From Firebase
You can signout from Firebase using the following: 
 FirebaseAuth.getInstance().signOut();  

Download Sourcecode

Reference

Friday, 16 September 2016

ButterKnife 8.2.1 for Field and method binding using annotations in android

Introduction 


       Sometimes developers have to deal with redundant coding that is visually unattractive and frustrating. In this article, I will introduce an injection library for Android development that can help create more beautiful code and recent updates introduced with version 8.

Android Butter Knife  is an open source view “injection” library for Android created by Jake Wharton.

    Butter Knife is small, simple and lightweight, and it makes life as a developer easier. It allows developers to perform injection on arbitrary objects,views and OnClickListeners so they can focus on writing useful code. Butter Knife enables focus on logic instead of glue code and reduces development time by reducing redundant coding.

  • Field and method binding for Android views which uses annotation processing to generate boilerplate code for you.
  •  Eliminate findViewById calls by using @BindView on fields.
  •  Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.
  •  Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and others.
  •  Eliminate resource lookups by using resource annotations on fields.

Features

  1. VIEW BINDING
  2. RESOURCE BINDING
  3. NON-ACTIVITY BINDING
  4. VIEW LISTS
  5. LISTENER BINDING
  6. BINDING RESET
  7. OPTIONAL BINDINGS
  8. MULTI-METHOD LISTENERS

Using the Butter Knife Library


Step1: Configure Your Project for Android Butter Knife

Before getting started with Butter knife, you need to configure your Android project.
  • Update Project-level build.gradle
 buildscript {  
     repositories {  
        mavenCentral()  
     }  
     dependencies {  
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'  
      }  
  }  
  • Apply “android-apt” in module-level build.gradle
 apply plugin: 'android-apt'  
 android {  
 ...  
 }  
 dependencies {  
 compile 'com.jakewharton:butterknife:8.2.1'  
 apt 'com.jakewharton:butterknife-compiler:8.2.1'  
 }  


Finally sync project.

  • Add Butter Knife in Library Module
              Add Butterknife plugin to project-level build.gradle. 

  buildscript {  
     repositories {  
          mavenCentral()  
      }  
   dependencies {  
         classpath 'com.jakewharton:butterknife-gradle-plugin:8.2.1'  
       }  
   }  

     Apply ButterKnife plugin in library module.
 apply plugin: 'com.android.library'  
 apply plugin: 'com.jakewharton.butterknife'  

Note: If you applied ButterKnife in library project then you neeed to use R2 class instead of R class in ButterKnife annotations.


Step2: Use the Annotations

Annotate fields with @BindView and a view ID for Butter Knife to find and automatically cast the corresponding view in your layout.

 class ExampleActivity extends Activity {  
  @BindView(R.id.title) TextView title;  
  @BindView(R.id.subtitle) TextView subtitle;  
  @BindView(R.id.footer) TextView footer;  
  @Override public void onCreate(Bundle savedInstanceState) {  
   super.onCreate(savedInstanceState);  
   setContentView(R.layout.simple_activity);  
   ButterKnife.bind(this);  
   // TODO Use fields...  
  }  
 }  

Instead of slow reflection, code is generated to perform the view look-ups. Calling bind delegates to this generated code that you can see and debug.

The generated code for the above example is roughly equivalent to the following:
 public void bind(ExampleActivity activity) {  
  activity.subtitle = (android.widget.TextView) activity.findViewById(2130968578);  
  activity.footer = (android.widget.TextView) activity.findViewById(2130968579);  
  activity.title = (android.widget.TextView) activity.findViewById(2130968577);  
 }  

You can also perform binding on arbitrary objects by supplying your own view root


 View view = LayoutInflater.from(context).inflate(R.layout.thing, null);  
 TextView firstName = ButterKnife.findById(view, R.id.first_name);  
 TextView lastName = ButterKnife.findById(view, R.id.last_name);  
 ImageView photo = ButterKnife.findById(view, R.id.phot);  

RESOURCE BINDING 

Bind pre-defined resources with @BindBool, @BindColor, @BindDimen, @BindDrawable@BindInt,@BindString, which binds an R.bool ID (or your specified type) to its corresponding field.
 class ExampleActivity extends Activity {  
  @BindString(R.string.title) String title;  
  @BindDrawable(R.drawable.graphic) Drawable graphic;  
  @BindColor(R.color.red) int red; // int or ColorStateList field  
  @BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field  
  // ...  
 }  

VIEW LIST

You can group multiple views into a List or array.
 @BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })  
 List<EditText> nameViews;  
Then apply method allows you to act on all the views in a list at once.
 ButterKnife.apply(nameViews, DISABLE);  
 ButterKnife.apply(nameViews, ENABLED, false);  

Action and Setter interfaces allow specifying simple behavior.
 ButterKnife.apply(nameViews, View.ALPHA, 0.0f);  

NON-ACTIVITY BINDING

You can also perform binding on arbitrary objects by supplying your own view root.
 public class FancyFragment extends Fragment {  
  @BindView(R.id.button1) Button button1;  
  @BindView(R.id.button2) Button button2;  
  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
   View view = inflater.inflate(R.layout.fancy_fragment, container, false);  
   ButterKnife.bind(this, view);  
   // TODO Use fields...  
   return view;  
  }  
 }  
Another use is simplifying the view holder pattern inside of a list adapter.
 public class MyAdapter extends BaseAdapter {  
  @Override public View getView(int position, View view, ViewGroup parent) {  
   ViewHolder holder;  
   if (view != null) {  
    holder = (ViewHolder) view.getTag();  
   } else {  
    view = inflater.inflate(R.layout.whatever, parent, false);  
    holder = new ViewHolder(view);  
    view.setTag(holder);  
   }  
   holder.name.setText("John Doe");  
   // etc...  
   return view;  
  }  
  static class ViewHolder {  
   @BindView(R.id.title) TextView name;  
   @BindView(R.id.job_title) TextView jobTitle;  
   public ViewHolder(View view) {  
    ButterKnife.bind(this, view);  
   }  
  }  
 }  

Calls to ButterKnife.bind can be made anywhere you would otherwise put findViewById calls.
Other provided binding APIs:
  • Bind arbitrary objects using an activity as the view root. If you use a pattern like MVC you can bind the controller using its activity with ButterKnife.bind(this, activity).
  • Bind a view's children into fields using ButterKnife.bind(this). If you use <merge> tags in a layout and inflate in a custom view constructor you can call this immediately after. Alternatively, custom view types inflated from XML can use it in the onFinishInflate() callback.

LISTENER BINDING

Listeners can also be automatically configured onto methods.
 @OnClick(R.id.submit)  
 public void submit(View view) {  
  // TODO submit data to server...  
 }  
All the arguments to the listener method are optional.
 @OnClick(R.id.submit)  
 public void submit() {  
  // TODO submit data to server...  
 }  
Define a specific type and it will automatically be cast.
 @OnClick(R.id.submit)  
 public void sayHi(Button button) {  
  button.setText("Hello!");  
 }  
Specify multiple IDs in a single binding for common event handling.
 @OnClick({ R.id.door1, R.id.door2, R.id.door3 })  
 public void pickDoor(DoorView door) {  
  if (door.hasPrizeBehind()) {  
   Toast.makeText(this, "You win!", LENGTH_SHORT).show();  
  } else {  
   Toast.makeText(this, "Try again", LENGTH_SHORT).show();  
  }  
 }  
Custom views can bind to their own listeners by not specifying an ID.
 public class FancyButton extends Button {  
  @OnClick  
  public void onClick() {  
   // TODO do something!  
  }  
 }  

BINDING RESET

Fragments have a different view lifecycle than activities. When binding a fragment in onCreateView, set the views to null in onDestroyView. Butter Knife returns an Unbinder instance when you call bind to do this for you. Call its unbind method in the appropriate lifecycle callback.
 public class FancyFragment extends Fragment {  
  @BindView(R.id.button1) Button button1;  
  @BindView(R.id.button2) Button button2;  
  private Unbinder unbinder;  
  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
   View view = inflater.inflate(R.layout.fancy_fragment, container, false);  
   unbinder = ButterKnife.bind(this, view);  
   // TODO Use fields...  
   return view;  
  }  
  @Override public void onDestroyView() {  
   super.onDestroyView();  
   unbinder.unbind();  
  }  
 }  

OPTIONAL BINDINGS
By default, both @Bind and listener bindings are required. An exception will be thrown if the target view cannot be found. To suppress this behavior and create an optional binding, add a @Nullable annotation to fields or the @Optional annotation to methods.
Note: Any annotation named @Nullable can be used for fields. It is encouraged to use the @Nullable annotation from Android's "support-annotations" library.
 @Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;  
 @Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {  
  // TODO ...  
 }  

 MULTI-METHOD LISTENERS
Method annotations whose corresponding listener has multiple callbacks can be used to bind to any one of them. Each annotation has a default callback that it binds to. Specify an alternate using the callback parameter.
 @OnItemSelected(R.id.list_view)  
 void onItemSelected(int position) {  
  // TODO ...  
 }  
 @OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)  
 void onNothingSelected() {  
  // TODO ...  
 }  

BONUS
Also included are findById methods which simplify code that still has to find views on a View,Activity, or Dialog. It uses generics to infer the return type and automatically performs the cast.
 View view = LayoutInflater.from(context).inflate(R.layout.thing, null);  
 TextView firstName = ButterKnife.findById(view, R.id.first_name);  
 TextView lastName = ButterKnife.findById(view, R.id.last_name);  
 ImageView photo = ButterKnife.findById(view, R.id.photo);  

Add a static import for ButterKnife.findById and enjoy even more fun.

Reference