Android Basics Nanodegree By Google

udacity-android-basics-nanodegree-certificate-of-completion
Certificate Of Completion

Course Work Projects

Project 1: Single Screen App

project-1-contact-us-app-screenshot

In Part 1 of the Nanodegree, I learned about the XML markup language. I also learned how Views and ViewGroups are used to create user interfaces in Android.

At the end of Part 1, I was tasked with building a simple, single-screen application that displayed the contact information for a local business.

Since I am the founder of Fall3nWarrior.com, I decided to use my company’s contact information. I created a simple layout with some TextViews and ImageViews and selected colors to match my brand. 

Project 2: Score Keeper App

project-2-baseball-score-tracker-app-screenshot

In Part 2 of the Nanodegree, I learned how to harness the power of Java to add interactivity to my applications via user input and the basic principles of object-oriented programming.

For the first project of Part 2, I was tasked with building a scorekeeper application that provides the user with an easy way to keep track of the score of two different teams playing a game of my choice. 

Since I played baseball when I was younger, I created an application that tracks the score of two baseball teams, the current count, and the number of outs in an inning. I also added a color scheme that matched the color of most baseball fields and an image of home plate.

Project 3: Quiz App

project-3-world-war-2-quizlet-app-screenshot

At the end of Part 2 of the Nanodegree, I was later tasked with creating a Quiz application to test my understanding of Java and the use of different Views to receive input from the user.

Since I love studying History, I chose World War II as the topic and began creating a layout for the Quiz. By using, an EditText field, CheckBoxes, RadioButtons, RadioGroups, and a ScrollView, I was able to create a simple, vertical, nested, LinearLayout for the Quiz.

At the end of the ScrollView, I added a button that called a function to parse and check the answers entered by the user.  It also displayed the Quiz results in a toast message.

Project 4: Music App Structure

project-4-music-player-main-menu-screenshot
Main Menu

project-4-music-player-search-screenshot
Search

project-4-music-player-my-library-screenshot
My Library

project-4-music-player-now-playing-screenshot
Now Playing

project-4-music-player-store-screenshot
Store

project-4-music-player-checkout-screenshot
Checkout

project-4-music-player-main-menu-screenshot
Main Menu

project-4-music-player-my-library-screenshot
My Library

project-4-music-player-store-screenshot
Store

project-4-music-player-search-screenshot
Search

project-4-music-player-now-playing-screenshot
Now Playing

project-4-music-player-checkout-screenshot
Checkout

In Part 3 of the Nanodegree, I learned how to add different screens to an application, in the form of Activities, using Java. I also learned Explicit Intents and OnClickListeners in order to switch between the different Activities and to add additional behavior to Buttons.

For the first project of Part 3, I was tasked with building the basic structure of a Music Player application. I had to create several different Activities and layouts for each screen in the application. I utilized ButtonViews and Explicit Intents to allow the user to navigate between the different parts of my application. I created a Search, My Library, Now Playing, Store, and a Checkout for a total of five different activities. As an additional step, I displayed the purpose of each Activity in a TextView  within each Activity.

Project 5: Report Card Custom Java Class

In the middle of Part 3 of the Nanodegree, my second project focused upon Custom Java Classes and how they make up a critical part of every object-oriented program. I was tasked with writing a Custom Java Class that could be used to store scores on a student’s report card. The custom class was required to have, at least one constructor to instantiate all variables in the class, getter and setter methods to access and modify the private variables in the class and a toString() method which returns the contents of the class in a human-readable string. The resulting Java Class Source Code can be found below.

// Report Card class
package com.example.android.reportcard;

public class ReportCard {

    //  @mName stores the name of the student.
    //  @mClassYear stores the student's class graduation year.
    //  @mHistory stores the students grade for history.
    //  @mMath stores the students grade for math.
    //  @mEnglish stores the students grade for english.
    //  @mScience stores the students grade for science.
    private String mName;
    private int mClassYear;
    private int mHistory;
    private int mMath;
    private int mEnglish;
    private int mScience;

    private void reportCard(String name, int classYear, int history, int math, int english, int science) {
        mName = name;
        mClassYear = classYear;
        mHistory = history;
        mMath = math;
        mEnglish = english;
        mScience = science;
    }

    @Override
    // Create report card summary.
    public String toString() {
        String mReportCardSummary;
        mReportCardSummary = 'Report Card Summary:';
        mReportCardSummary += '\nStudent Name: ' + mName;
        mReportCardSummary += '\nClass Year: ' + mClassYear;
        mReportCardSummary += '\nHistory Grade: ' + mHistory;
        mReportCardSummary += '\nMath Grade: ' + mMath;
        mReportCardSummary += '\nEnglish Grade: ' + mEnglish;
        mReportCardSummary += '\nScience Grade: ' + mScience;
        mReportCardSummary += '\nSee you next year!';
        return mReportCardSummary;
    }

    // Get name of student
    public String getName() {
        return mName;
    }

    // Set name of student
    public void setName(String name) {
        mName = name;
    }

    // Get class year
    public int getClassYear() {
        return mClassYear;
    }

    // Set class year
    public void setClassYear(int classYear) {
        mClassYear = classYear;
    }

    // Get history grade
    public int getHistoryGrade() {
        return mHistory;
    }

    // Set history grade
    public void setHistoryGrade(int history) {
        mHistory = history;
    }

    // Get math grade
    public int getMathGrade() {
        return mMath;
    }

    // Set math grade
    public void setMathGrade(int math) {
        mMath = math;
    }

    // Get english grade
    public int getEnglishGrade() {
        return mEnglish;
    }

    // Set english grade
    public void setEnglishGrade(int english) {
        mEnglish = english;
    }

    // Get science grade
    public int getScienceGrade() {
        return mScience;
    }

    // Set science grade
    public void setScienceGrade(int science) {
        mScience = science;
    }
}

Project 6: Tour Guide App

project-6-main-menu-screenshot
Main Menu

project-6-restaurants-screenshot
Restaurants

project-6-parks-screenshot
Parks

project-6-museums-screenshot
Museums

project-6-entertainment-screenshot
Entertainment

project-6-main-menu-screenshot
Main Menu

project-6-parks-screenshot
Parks

project-6-entertainment-screenshot
Entertainment

project-6-restaurants-screenshot
Restaurants

project-6-museums-screenshot
Museums

At the end of Part 3 of the Nanodegree and for the last project in this section, I was tasked with creating a multi-screen tour guide application for a user visiting my city. The application was required to list top attractions, restaurants, public places and events. Since I live in New York, I had many places to recommend.  

First, I created a Main Menu featuring four categories of places to visit, which included Restaurants, Parks, Museums and Entertainment. Each category displayed a list of relevant places and information. By tapping on a location, the location opened in the Google Maps application on the user’s device. After adding all of the locations and relevant information for each site to visit, I created a simple layout and color scheme to show the information in an easy-to-read, user interface design.

Project 7: Book Listing App

project-7-book-listing-app-screenshot

In Part 4 of the Nanodegree, networking in Android was the focus. I learned about HTTP Networking and how to make requests using Java. I also learned how to parse JSON responses from API’s on separate threads, other than the main thread of my application, using AsyncTasks.

For the first project of Part 4, I was tasked with making a book listing application whose purpose was to allow a user to get a list of published books on a given topic. I also had to use the Google Books API to gather search results and display them to the user.

As a result, I created a simple ScrollView with a SearchView for the user to fill in with their search query. When the user pressed search on their keyboard, the application made an HTTP request to the Google Books API and parsed the JSON response using an AsyncTask. Lastly, it populated a ListView with the results of the user’s query. If the search did not return any results, the application displayed a simple message entitled, “No Books Found.”

Project 8: News App

project-8-news-app-screenshot
Main Menu

project-8-news-app-results-screenshot
Search Results

For the second project of Part 4, I was tasked with making a news application, whose purpose was to allow a user to get a list of the most recent news articles from a news API of my choosing. The goal of the project was to use an unfamiliar API and create an application to access and display information from the unfamiliar API. I decided to use The Guardian’s API for this project.

To begin, I created a simple layout instructing the user to swipe down on their screen to get the latest news. When the user swiped down, the SwipeRefresh Layout called a function to make an HTTP request to The Guardian’s API and parsed the JSON response, using an AsyncTask. Lastly, it populated the ListView Layout with the most recent news articles in a simple and easy-to-read layout. If the API request did not return any results, the application displayed a simple message “No News Found. Has The World Ended?” Lastly, if the user tapped on an article, the chosen article would open in the user’s default browser via an Implicit Intent.

The SwipeRefreshLayout was added to this application as a bonus since it was not a requirement of the project. I took the initiative to learn how to implement it within my project to add an additional, user-friendly function to the application.

Project 9: Habit Tracker App Structure

In Part 5 of the Nanodegree, we learned about the importance of data persistence when building Android applications. Specifically, we learned how to work with SQL databases and ContentProviders and how they can help keep our application data bug-free and allow us to share our data storage with other applications and developers. We essentially learned how to create, initialize and implement a SQLite database in our application. We also learned how to create a DBHelper class to safely read and write data to our database.

The first project for Part 5 was to show that we properly created, initialized and implemented a SQLite database. I was tasked with creating the structure of a habit-tracking application. The project consisted of only a few Java classes because programming was the focus.  A user interface was not required in this project.  Therefore, in the three classes below, I created and initialized a SQLite table and implemented methods to read, write and modify the data in the database.

package com.example.android.habittracker;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.example.android.habittracker.data.HabitContract.HabitEntry;
import com.example.android.habittracker.data.HabitDbHelper;

public class MainActivity extends AppCompatActivity {

    // Reference to the current active HabitDbHelper Instance.
    private HabitDbHelper mDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Create and Grab a referene to the new HabitDbHelper instance.
        mDbHelper = new HabitDbHelper(this);

        // Insert a Habit into the habits Table.
        insertHabit();

        // Read the list of habits stored in the habits Table.
        // Show the result of the query in a simple TextView in the middle of the screen.
        readDatabaseInfo();
    }

    // Insert a Habit into the habits Table.
    private void insertHabit() {

        // Obtain access to the database.
        SQLiteDatabase db = mDbHelper.getWritableDatabase();

        // Create a set of values to add to the database.
        ContentValues values = new ContentValues();

        // The Status of the Habit the user wants to track.
        // 0 = INCOMPLETE (Default 0) and 1 = COMPLETE.
        int status = 0;

        // Add a Name value for the name of the Habit the user wants to track.
        values.put(HabitEntry.COLUMN_HABIT_NAME, 'Walk The Dog');

        // Add a Status value for the status  of the Habit the user wants to track.
        values.put(HabitEntry.COLUMN_HABIT_STATUS, status);

        // Insert the values into the habits Table.
        // Save the result to a variable.
        long newRowId = db.insert(HabitEntry.TABLE_NAME, null, values);

        // If the insertion failed...
        if (newRowId == -1) {

            // Show an error message
            Toast.makeText(getApplicationContext(), 'Error with saving Habit',
                    Toast.LENGTH_SHORT).show();

        } else {

            // Otherwise show a message that the insertion was successful
            // with a reference to the row id.
            Toast.makeText(getApplicationContext(), 'Habit saved with id: '
                    + newRowId, Toast.LENGTH_SHORT).show();
        }
    }

    // Read the list of habits stored in the habits Table.
    private void readDatabaseInfo() {

        // Queries the database and returns a Cursor object.
        Cursor cursor = queryDatabase();

        // Get the indexes of each Column included in the query.
        int idColumnIndex = cursor.getColumnIndex(HabitEntry._ID);
        int nameColumnIndex = cursor.getColumnIndex(HabitEntry.COLUMN_HABIT_NAME);
        int statusColumnIndex = cursor.getColumnIndex(HabitEntry.COLUMN_HABIT_STATUS);
        int dateCreatedColumnIndex = cursor.getColumnIndex(HabitEntry.COLUMN_HABIT_DATE_CREATED);

        // Create a log message to display the format of the Columns in the database.
        Log.d('MainActivity', 'ID - Name - Status - Date created \n');

        // Parse the query using the cursor object.
        try {
            while (cursor.moveToNext()) {

                // Save the values of each Column in all Rows of the Table in the Database.
                int currentID = cursor.getInt(idColumnIndex);
                String currentName = cursor.getString(nameColumnIndex);
                int currentStatus = cursor.getInt(statusColumnIndex);
                String currentDateCreated = cursor.getString(dateCreatedColumnIndex);

                // Show and Append the results of the query in a simple log message.
                Log.d("MainActivity", '\n' + currentID + ' - '
                        + currentName + ' - '
                        + currentStatus + ' - '
                        + currentDateCreated);
            }
        } finally {

            // Close the cursor to prevent memory leaks.
            cursor.close();
        }
    }

    // Queries the database and returns a Cursor object.
    private Cursor queryDatabase() {

        // Obtain access to the database.
        SQLiteDatabase db = mDbHelper.getReadableDatabase();

        // Create a string array of the Columns to be included in the query.
        String[] projection = {
                HabitEntry._ID,
                HabitEntry.COLUMN_HABIT_NAME,
                HabitEntry.COLUMN_HABIT_STATUS,
                HabitEntry.COLUMN_HABIT_DATE_CREATED,
        };

        // Make the query to the database for the specified Columns and return a Cursor.
        return db.query(
                HabitEntry.TABLE_NAME,
                projection,
                null,
                null,
                null, null,
                null);
    }
}
package com.example.android.habittracker.data;

import android.provider.BaseColumns;

public class HabitContract {

    private HabitContract() {
    }

    public static abstract class HabitEntry implements BaseColumns {

        // Name of the Database Table that stores a list of Habits.
        public static final String TABLE_NAME = 'habits';

        // Names of the Columns in the habits Database.
        // Name of the Column that stores the Row ID.
        public static final String _ID = BaseColumns._ID;

        // Name of the Column that stores the Name of the Habit the user wants to track.
        public static final String COLUMN_HABIT_NAME = 'name';

        // Name of the Column that store the Status of the Habit the user wants to track.
        // 0 = INCOMPLETE and 1 = COMPLETE.
        public static final String COLUMN_HABIT_STATUS = 'status';

        // Name of the Column that stores the Date the Habit was added to the Database.
        public static final String COLUMN_HABIT_DATE_CREATED = 'date_created';
    }
}
package com.example.android.habittracker.data;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class HabitDbHelper extends SQLiteOpenHelper {

    // The Current Database Version.
    private static final int DATABASE_VERSION = 1;

    // The Current Database Name.
    private static final String DATABASE_NAME = "trackers.db";

    // Constructor for a new HabitDbHelper.
    public HabitDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    // Creates a new Database named list with a table of habits.
    @Override
    public void onCreate(SQLiteDatabase db) {

        // Create an SQLite command to create a new habits Table and setup the Columns.
        String CREATE_HABITS_TABLE = "CREATE TABLE " + HabitContract.HabitEntry.TABLE_NAME +
                " ("
                + HabitContract.HabitEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + HabitContract.HabitEntry.COLUMN_HABIT_NAME + " TEXT NOT NULL,"
                + HabitContract.HabitEntry.COLUMN_HABIT_STATUS + " INTEGER NOT NULL DEFAULT 0,"
                + HabitContract.HabitEntry.COLUMN_HABIT_DATE_CREATED
                + " TEXT NOT NULL DEFAULT CURRENT_DATE);";

        // Execute the SQLite command to create the habits Table and setup the Columns.
        db.execSQL(CREATE_HABITS_TABLE);
    }

    // onUpgrade delete the current habits Table and Create a new Table only if...
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        // the Database version has been changed.
        if (oldVersion != newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + HabitContract.HabitEntry.TABLE_NAME);
            onCreate(db);
        }
    }
}

Project 10: Inventory App

project-10-inventory-app-main-menu-screenshot
Main Menu

project-10-inventory-app-product-example-screenshot
Product Example

project-10-inventory-app-add-product-screenshot
Add A Product

project-10-inventory-app-edit-product-screenshot
Edit A Product

project-10-inventory-app-delete-prompt-screenshot
Delete A Product

project-10-inventory-app-main-menu-screenshot
Main Menu

project-10-inventory-app-add-product-screenshot
Add A Product

project-10-inventory-app-delete-prompt-screenshot
Delete A Product

project-10-inventory-app-product-example-screenshot
Product Example

project-10-inventory-app-edit-product-screenshot
Edit A Product

For the final project of the Nanodegree, I was tasked with creating a multi-screen inventory tracking application for a user or business, so they could keep track of their product inventory.

Using my newly acquired knowledge of SQLite and ContentProviders, I created a simple layout that allowed the user to add a product to their inventory. By pressing the plus button in the MainActivity, the user added a new product along with an image and any additional relevant information. Upon saving the product, all entered data was validated and stored in the database. A product could be edited by tapping on it and updating the information. Also, a product could be deleted by pressing the delete button in the Options Menu, at any time. If the user made a change to the product information and left the activity without saving, they were prompted to save or discard the information. The same process occurred whenever data was deleted by the user.

In terms of inventory counts, pressing the “Sale” button on the MainActivity reduced the chosen product’s remaining quantity by one. And the “Order More” button on the Add or Edit Product activities created an email via Implicit Intent using the supplier’s email information so that the user could replenish their inventory with more products.