In this lab you'll learn how Firebase User Management works using Google Sign-In as an example. With the skills you learn, you'll be able to quickly move on to using other providers such as Facebook and Twitter.

Using Android Studio, create a new Android App.

Click File->New Project, and in the first dialog give your application a name and company domain. This will generate a package name. Make a note of this package name. You will need it later.

Click Next, and you'll be asked to select the form factors that your app will run on. Just keep the defaults and click Next.

On the next screen, you'll be asked to Add an Activity to Mobile. Pick ‘Empty Activity' as shown, and click Next.

The next screen asks you to Customize the Activity. Just keep the defaults and click ‘Finish'. You'll now have an empty app. The next step is to add the Firebase dependencies to this.

When using Android Studio for Android applications, dependency and library configuration is managed using gradle. You'll find that there are two build.gradle files that you have to manage, and it can often be confusing as to what goes where. In Android Studio, if you select the ‘Android' tab in the project explorer, you'll see a ‘Gradle Scripts' folder. Open this and you'll see both build.gradle files:

The selected one -- with ‘(Module: app)' listed after it, is typically referred to as the ‘app level' build.gradle, and the other is the ‘root' or ‘project' level one.

Open the app-level build.gradle file. At the bottom of it, you'll see a section called dependencies. Edit this to add the Firebase dependencies. When you're done it should look like this:

dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   testCompile 'junit:junit:4.12'
   compile 'com.android.support:appcompat-v7:23.3.0'
   compile 'com.google.firebase:firebase-auth:9.0.0'
   compile 'com.google.android.gms:play-services-auth:9.0.0'
}
apply plugin: 'com.google.gms.google-services'

Android Studio will ask you to sync your files because they have been updated. This will give you an error if you do so. Don't worry about this, as there are more changes needed.

The next step is to open the ‘project-level' build.gradle file. You'll need to add a dependency to the google services. When you're done, it should look like this:

buildscript {
   repositories {
       jcenter()
   }
   dependencies {
       classpath 'com.android.tools.build:gradle:2.1.0'
       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
}

If you sync now, there won't be any errors in synching, but you'll see in the messages window that there's a problem with a missing google-services.json file:

You'll get this in the next step -- when you configure your project in the Firebase Console.

When using Firebase in your apps, you need an associated project in the Firebase Console. This allows you to manage many things about your project, from analytics to data and more. When using Auth, the console is required to turn on the services that you want to use -- and in this lab you'll be using Google Sign-In, so you'll see how to activate that.

Create a New Project

In Firebase Console, select ‘Create New Project' and you'll see this dialog:

Give the project a name, and then click the ‘Create Project' button. You'll be taken to the Firebase Overview screen:

Generate Google Services File

At the top of this screen, you'll see options to add Firebase to Android / iOS and Web apps. Choose the ‘Add Firebase to your Android App'. You'll see the ‘Enter app details' screen:

You'll need to enter the package name for your app and the debug signing certificate's SHA-1. The package name is what you configured earlier on.

Getting the SHA-1

More details on the SHA-1 are available here. For the purposes of this lab you'll be signing your app as a debug app, which is much easier -- but doesn't allow you to deploy it to the play store. For that you'll need to sign in release mode. To get your SHA-1 debug key, you have to find your debug keystore.

It's in these folders:

On Mac: /Users/<username>/.android/

On Windows: C:\Documents and Settings\<username>\.android\

On Linux: ~/.android/

Once you've found it, open a terminal or command prompt, and from within the same directory as debug.keystore, issue the following command:

keytool -list -v -keystore debug.keystore -storepass android

You'll see an output something like this:

Note the SHA1 value.

.

Installing your Google-Services.json file

Click ‘Add App', and on the next screen, you'll see that a file called ‘google-services.json' gets downloaded. Put this in your app folder as shown. In Android Studio 2, select the ‘Project Files' tab as shown here:

You'll see there's an app section, with an app folder in it. Drop the google-services.json onto that.

Click through the rest of the setup wizard, and you'll be returned to the overview screen. You'll see that your app has now been added to it:

Add Google Auth to your Project

On the left of the screen you'll see an ‘Auth' section. Select it. At the top of the screen there are a number of options. Ensure that ‘Sign In Method' is selected, and you'll see the list of providers:

Select the ‘Google' one, and click the button to enable it. Then press ‘Save'. You're now ready to begin coding the app.

Return to Android Studio. Now if you do a gradle sync, everything will work fine, showing that you've added all the necessary dependencies, and configured the back end on Firebase console.

Now let's start coding a simple sign-in app that uses all of this.

Edit your Layout File

The first step is to edit your layout file to have a Google Sign-In button. In your res/layout folder you'll find activity_main.xml

Edit this file to add a Sign In button and some basic layout like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context="com.google.devrel.lmoroney.androidauthcodelab.MainActivity">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">
       <TextView
           android:id="@+id/status_textview"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="Hello World!" />
       <com.google.android.gms.common.SignInButton
           android:id="@+id/sign_in_button"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content" />
   </LinearLayout>
</RelativeLayout>

All you've done here is to replace the default ‘Hello World' text view with a Linear Layout containing that text view, and a SignInButton. You've also given the text view an id so it can be accessed in code.

Edit your Main Activity Declaration

The empty Main Activity that was created for you was declared as simply extending AppCompatActivity. To handle Auth, you'll need to use a GoogleApiClient, which requires you to declare that your class implements GoogleApiClient.OnConnectionFailedListener. In addition, as the buttons will use an OnClickListener, you need to implement the View.OnClickListener interface too.

So update your class declaration like this:

public class MainActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, View.OnClickListener {

Android Studio will give you a red underline here. Don't worry about that for now -- it's just warning you that you haven't implemented some required overrides yet.

Add Class Variables

Next up you'll need to add some class-level variables that will be shared across the various functions you're writing. Below the class declaration and above the onCreate, add the following:

SignInButton signInButton;
TextView statusTextView;
GoogleApiClient mGoogleApiClient;
private static final String TAG = "SignInActivity";
private static final int RC_SIGN_IN = 9001;

Set up the Google Api Client

In your onCreate function, you'll next need to add the declarations of a GoogleSignInOptions and a GoogleApiClient. The options object is used to define the type of GoogleSignIn experience you want to access. You'll notice that it requests just the Email address of the user. This simplifies the sign in flow so that no further elevated permissions are required -- you're only accessing their email address. This is then used to construct the Google API Client, which is told to access the Google Sign In API.

Add these lines to the onCreate function:

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
       .requestEmail()
       .build();

mGoogleApiClient = new GoogleApiClient.Builder(this)
       .enableAutoManage(this , this)
       .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
       .build();

Create Code for User Interface Components

You'll finish up your onCreate function by setting up the objects representing the user interface components -- the status text view and the sign in button:

statusTextView = (TextView) findViewById(R.id.status_textview);
signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(this);

You'll notice that the Sign In Button sets its on click listener to this, so you'll need to implement the onClick override. Here's the code:

@Override
public void onClick(View v){
   switch(v.getId()){
       case R.id.sign_in_button:
           signIn();
           break;
   }
}

When the user clicks anything in the activity this function will be called -- at present it just checks if the click was raised by the sign in button, and if it does, it calls the signIn() function. This will be red right now, because you haven't implemented it yet. Let's implement that next.

Create Sign In Function

Here's the code:

private void signIn(){
   Intent signInIntent = 
Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
   startActivityForResult(signInIntent, RC_SIGN_IN);
}

This creates a new Intent called signInIntent, using the Google Sign In API. It then starts an activity for the result of that intent. When you run this code later, the effect of this will be that the account picker will be displayed.

Handle Activity Result

When the user picks an account, an Activity Result will be generated. So the next step is to handle this Activity Result:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);

   if (requestCode == RC_SIGN_IN) {
       GoogleSignInResult result = 
Auth.GoogleSignInApi.getSignInResultFromIntent(data);
       handleSignInResult(result);
   }
}

The Activity was generated with the code RC_SIGN_IN (we declared this earlier), so when we check the activity result, we want to check if it's the result for the activity with this code. It's possible to have multiple activities calling back, so the code is used to differentiate between them. When the request code matches, we know that the data returned from the activity will have a Sign In Result, so we can create a GoogleSignInResult object from it. We then handle that in handleSignInResult. You'll implement that next:

private void handleSignInResult(GoogleSignInResult result) {
   if (result.isSuccess()) {
       GoogleSignInAccount acct = result.getSignInAccount();
       statusTextView.setText("Hello, " + acct.getDisplayName());
   } else {
   }
}

This gets the account details from the result, and pulls the user name from that, setting it to the contents of the text view.

Implement On Connection Failed Listener

There's one last thing you need to do, and that's implementing the OnConnectionFailedListener override, which is a requirement of using the GoogleApiClient.

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
   // An unresolvable error has occurred and Google APIs (including Sign-In) will not
   // be available.
   Log.d(TAG, "onConnectionFailed:" + connectionResult);
}

Now when you run your app, you'll see the following:

Clicking the Sign In button will call up the Account Picker:

Once you've chosen the picker, you will get signed in, and the user interface will update to welcome you based on the name associated with the account that you sign in with:

You've taken your first steps into the world of federated authentication and identity. Well done! Some next steps to consider: