Lesson Monday

Most applications need to know the identity of a user. This allows them to offer a personalized experience, and to associate content with a specific users. For example, social media apps only display content from users you have followed, and can attribute anything you post to your own account. And a note-taking app displays only your notes when you log in, allowing you to keep some content private.

In our case, MyRestaurants should associate each user's "Saved Restaurants" list with a specific user account. This will allow every user to have their own private, personalized list. Conveniently, Firebase offers built-in tools for managing user authentication.

In this lesson, we will prepare to integrate user authentication into our application by configuring the necessary components and settings. In subsequent lessons we'll write the actual methods to handle registering new users and logging them in and out.

Required Reading

To get started, read the Firebase Authentication Overview and Authenticate with Firebase using Password-Based Accounts on Android articles.

Adding Dependencies

First off, to use Firebase's built-in authentication tools we'll need to add the firebase-auth dependency. Add the following to your build.gradle file:

build.gradle (Module: app)
dependencies {
    ...
    compile 'com.google.firebase:firebase-auth:9.2.1'
}

Note: 9.0+ versions of firebase-auth are built using Google Play Services 9.0+. If you receive a gradle error after adding this package, it's likely that your Google Play Services SDK needs to be updated. Select _Tools > Android > SDK Manager, in Android Studio, then navigate to the SDK Tools tab in the resulting pop-up. Select and install Google Play Services , and hit Apply. Sync and build your project after it is complete._

Configuring Firebase

We also need to enable the user authentication feature in Firebase. We can do this by visiting the overview of our Firebase application already functioning as our database, selecting "Auth" from the sidebar...

firebase-panel-auth

...clicking the "set up sign in method" button...

firebase-setup-signin-method

...selecting the _edit _icon for the "Email/Password" provider...

edit-email-password

... and checking the "Enable" switch:

enable-email-password

Account Registration Page

Before users can sign in and out they'll need to be able to create an account. Let's create a new activity in our ui sub-package called CreateAccountActivity. We'll also check the box labeled Generate Layout File to create a corresponding xml file in our layouts directory:

create-new-blank-activity-android-studio

generate-layout-file-when-creating-new-activity

Before writing any logic, let's construct a basic layout for this area of our application. We'll begin by adding the following to the activity_create_account.xml file generated when we created our new activity:

activity_create_account.xml
<?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"
    tools:context="com.epicodus.myrestaurants.ui.CreateAccountActivity"
    android:background="@color/colorPrimary">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="30dp"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/linearLayout">

        <EditText
            android:id="@+id/nameEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:hint="Name"
            android:nextFocusDown="@+id/passwordEditText"
            android:padding="10dp"
            android:layout_marginBottom="10dp"
            android:textColor="@android:color/black"
            android:textColorHint="@color/colorDivider"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/emailEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:hint="Email"
            android:inputType="textEmailAddress"
            android:nextFocusDown="@+id/passwordEditText"
            android:padding="10dp"
            android:layout_marginBottom="10dp"
            android:textColor="@android:color/black"
            android:textColorHint="@color/colorDivider"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/passwordEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:hint="Password"
            android:inputType="textPassword"
            android:nextFocusDown="@+id/passwordEditText"
            android:padding="10dp"
            android:layout_marginBottom="10dp"
            android:textColor="@android:color/black"
            android:textColorHint="@color/colorDivider"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/confirmPasswordEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:hint="Confirm Password"
            android:inputType="textPassword"
            android:nextFocusDown="@+id/passwordEditText"
            android:padding="10dp"
            android:layout_marginBottom="10dp"
            android:textColor="@android:color/black"
            android:textColorHint="@color/colorDivider"
            android:textSize="20sp" />


        <Button
            android:id="@+id/createUserButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="Sign up"
            android:background="@color/colorAccent"
            android:layout_marginTop="15dp"
            android:textColor="@color/colorTextIcons" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:textColor="@color/colorTextIcons"
            android:textStyle="bold"
            android:textSize="15sp"
            android:text="Already have an account? Log in here!"
            android:id="@+id/loginTextView"
            android:layout_gravity="center_horizontal" />

    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Create Account"
        android:textColor="@color/colorPrimaryLight"
        android:textSize="30dp"
        android:textStyle="bold"
        android:layout_above="@+id/linearLayout"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

This creates a registration form where users may enter their name, email address, password, and password confirmation. We've also included a "Create Account" button that will eventually trigger the account registration process.

Account Login Page

Now that they can register for accounts, users will also need a place to log in. Let's create another empty activity in our ui sub-package called LoginActivity. Again, make sure to check Generate Layout File.

We'll populate the corresponding activity_login.xml layout with email and password EditTexts, a button, a TextView that will take users to our CreateAccountActivity if they are not yet registered, and some basic styling:

activity_login.xml
<?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"
    tools:context="com.epicodus.myrestaurants.ui.LoginActivity"
    android:background="@color/colorPrimary">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="30dp"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/linearLayout">

        <EditText
            android:id="@+id/emailEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:hint="Email"
            android:inputType="textEmailAddress"
            android:nextFocusDown="@+id/passwordEditText"
            android:padding="10dp"
            android:layout_marginBottom="10dp"
            android:textColor="@android:color/black"
            android:textColorHint="@color/colorDivider"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/passwordEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:hint="Password"
            android:inputType="textPassword"
            android:nextFocusDown="@+id/passwordEditText"
            android:padding="10dp"
            android:textColor="@android:color/black"
            android:textColorHint="@color/colorDivider"
            android:textSize="20sp" />


        <Button
            android:id="@+id/passwordLoginButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="Log in"
            android:background="@color/colorAccent"
            android:layout_marginTop="15dp"
            android:textColor="@color/colorTextIcons" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:textColor="@color/colorTextIcons"
            android:textStyle="bold"
            android:textSize="15sp"
            android:text="Don't have an account? Sign up here!"
            android:id="@+id/registerTextView"
            android:layout_gravity="center_horizontal" />

    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login"
        android:textColor="@color/colorPrimaryLight"
        android:textSize="30dp"
        android:textStyle="bold"
        android:layout_above="@+id/linearLayout"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

Intent Filters and the Category Launcher

In our AndroidManifest, the block of XML corresponding to our MainActivity currently contains the following code:

...
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
...

This is called an intent filter. An intent filter is an expression in the manifest that specifies the type of intents a particular component may receive. This particular line of code adds the category_launcher filter to our MainActivity. This means we're instructing our app to display MainActivity when it first launches.

However, now that we're implementing authentication we'll want users to log in before anything else. Let's move this line from the MainActivity block of AndroidManifest into the LoginActivity block. This will ensure the LoginActivity is the first thing users see when launching our app.

Our updated AndroidManfest.xml file should look like this:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.epicodus.myrestaurants">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".ui.MainActivity"
            android:theme="@style/NoActionBarTheme">
        </activity>
        <activity android:name=".ui.RestaurantListActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.MainActivity" />
        </activity>
        <activity android:name=".ui.RestaurantDetailActivity" />
        <activity android:name=".ui.SavedRestaurantListActivity" />
        <activity android:name=".ui.CreateAccountActivity" />
        <activity android:name=".ui.LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

And, if we restart our application we should see our LoginActivity first:

login-page-myrestaurants

For more information about intent filters, check out the Android Developers Guide.


Example GitHub Repo for MyRestaurants

Terminology


  • Intent filter: An expression in the manifest that specifies the type of intents a particular component may receive.

Examples


Additional Resources