com.example.cody.tapwater.activities.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.example.cody.tapwater.activities.MainActivity.java

Source

/****************************************************************************************
 /*
 /* FILE NAME: MainActivity.java
 /*
 /* DESCRIPTION: The main menu for the application where drinks are added and the library can be accessed.
 /*
 /* REFERENCE: Starts when application begins
 /*
 /* WRITTEN BY: Cody Rogers
 /* DATE: 10/24/14
 /*
 /****************************************************************************************/

package com.example.cody.tapwater.activities;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.cody.tapwater.asyncs.AuthenticateUserAsync;
import com.example.cody.tapwater.services.NotificationService;
import com.example.cody.tapwater.callbacks.CallBackListenerMain;
import com.example.cody.tapwater.asyncs.CreateDrinkAsync;
import com.example.cody.tapwater.asyncs.CreateUserAsync;
import com.example.cody.tapwater.database.DataSource;
import com.example.cody.tapwater.objects.Drink;
import com.example.cody.tapwater.objects.Helper;
import com.example.cody.tapwater.asyncs.LoadDrinksAsync;
import com.example.cody.tapwater.R;
import com.example.cody.tapwater.objects.ServerDrink;
import com.example.cody.tapwater.objects.ServerUser;
import com.example.cody.tapwater.database.TapOpenHelper;
import com.example.cody.tapwater.objects.User;
import com.google.gson.Gson;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class MainActivity extends Activity {

    private Context context = this;
    public static final String TAG = "MainActivity";
    private DataSource datasource;
    private SwipeRefreshLayout swipeLayout;
    private User user;
    private TextView cups;
    private Helper helper;
    private AlertDialog alert;
    private Gson gson = new Gson();

    /**
     * Callback class that responds to actions done to the server
     */
    public class CallBack implements CallBackListenerMain {

        /**
         * Called upon completion of CreateUserAsync. Toasts to user that a user was successfully created.
         *
         * @param response:        integer response that indicates success or failure.
         * @param responseMessage: Server's response.
         */
        @Override
        public void callbackCreateUser(Integer response, String responseMessage) {
            Log.i(TAG, "callback called " + response);
            if (response == 1) {
                alert.dismiss();
                String message = "User created";
                Toast.makeText(getBaseContext(), message, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getBaseContext(), responseMessage, Toast.LENGTH_SHORT).show();
            }
        }

        /**
         * Called upon completion of CreateDrinkAsync. Updates total number of cups in DB and Toasts to user that the drink was successfully created.
         *
         * @param response:        integer response that indicates success or failure.
         * @param d:               drink object returned to determine category of created drink.
         * @param responseMessage: Server's response.
         */
        @Override
        public void callbackCreateDrink(Integer response, Drink d, String responseMessage) {
            Log.i(TAG, "callback called " + response);
            if (response == 1) {
                String message = d.getCategory() + " created";
                cups.setText(String.valueOf(datasource.getTotalCups()) + " cups");
                Toast.makeText(getBaseContext(), message, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getBaseContext(), responseMessage, Toast.LENGTH_SHORT).show();
            }
        }

        /**
         * Called upon completion of AuthenticateUserAsync. Calls LoadDrinksAsync on success and Toasts to user that log in was successful.
         *
         * @param response:        integer response that indicates success or failure.
         * @param responseMessage: Server's response.
         */
        @Override
        public void callbackAuthenticateUser(Integer response, String responseMessage) {
            Log.i(TAG, "callback called " + response);
            if (response == 1) {
                alert.dismiss();
                String message = "User logged in";
                LoadDrinksAsync async = new LoadDrinksAsync(context, new CallBack());
                async.execute();
                Toast.makeText(getBaseContext(), message, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getBaseContext(), responseMessage, Toast.LENGTH_SHORT).show();
            }
        }

        /**
         * Called upon completion of LoadDrinkAsync. Toasts to user that drinks were loaded successfully. Updates total cups in DB accordingly.
         *
         * @param response:        integer response that indicates success or failure.
         * @param responseMessage: Server's response.
         */
        @Override
        public void callbackLoadDrinks(Integer response, String responseMessage) {
            Log.i(TAG, "callback called " + response);
            if (response == 1) {
                String message = "Drinks loaded";
                if (swipeLayout.isRefreshing()) {
                    swipeLayout.setRefreshing(false);
                }
                cups.setText(String.valueOf(datasource.getTotalCups()) + " cups");
                Toast.makeText(getBaseContext(), message, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getBaseContext(), responseMessage, Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * Instantiates the activity, creates its views, and sets listeners for all of the UI components.
     *
     * @param savedInstanceState: Last saved state of the system.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // Create activity based on last saved system state. Then instantiate layout.
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Instantiate datasource and helper objects
        datasource = new DataSource(context);
        helper = new Helper(context);

        // Instantiate swipe layout for refresh actions and establish behavior.
        swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe);
        swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                LoadDrinksAsync async = new LoadDrinksAsync(context, new CallBack());
                async.execute();
            }
        });
        swipeLayout.setColorScheme(android.R.color.holo_blue_bright, android.R.color.holo_green_light,
                android.R.color.holo_orange_light, android.R.color.holo_red_light);

        // Instantiate buttons to create drink, glass, and bottle of water.
        View drink = findViewById(R.id.drinkButton);
        View glass = findViewById(R.id.glassButton);
        View bottle = findViewById(R.id.bottleButton);

        // Instantiate total cups field and set it to the current total cups in the DB.
        cups = (TextView) findViewById(R.id.cupsText);
        cups.setText(String.valueOf(datasource.getTotalCups()) + " cups");

        // Instantiate timer indicating time since last drink was created.
        final TextView timer = (TextView) findViewById(R.id.timeSinceLastDrink);

        // Listener for drink button. Posts a "drink" category Drink to server.
        drink.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drinkPost("drink");
            }
        });

        // Listener for glass button. Posts a "glass" category Drink to server.
        glass.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drinkPost("glass");
            }
        });

        // Listener for bottle button. Posts a "bottle" category Drink to server.
        bottle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drinkPost("bottle");
            }
        });

        // Thread runs every second to update the text of the timer.
        Thread t = new Thread() {

            @Override
            public void run() {
                try {
                    while (!isInterrupted()) {
                        Thread.sleep(1000);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                timer.setText(timerTextCalc());
                            }
                        });
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t.start();

        // Call login method, which displays login prompt if user is not logged in.
        login();
    }

    /**
     * Inflates the options menu from the layout in the res/menu folder.
     *
     * @param menu: Menu layout contained in the res/menu folder.
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    /**
     * Determines what action to take when a menu item is selected.
     *
     * @param item: Menu item as defined in menu's xml file.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        // Starts activity to view drinks in the DB.
        if (id == R.id.library) {
            Intent library = new Intent(getBaseContext(), Library.class);
            startActivity(library);
            return true;

            // Displays log out alert asking if user really wants to log out.
        } else if (id == R.id.profile) {
            Intent profile = new Intent(getBaseContext(), Profile.class);
            startActivity(profile);
            return true;
        } else if (id == R.id.logout) {
            logOutAlert();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * Calculates the time since a drink was created based on the current date and the last recorded drink date in the database.
     *
     * @return formatted string detailed time since last drink.
     */
    public String timerTextCalc() {

        // Get calendars for current time and for last time recorded in Drinks table.
        Calendar now = Calendar.getInstance();
        Calendar latest = datasource.getLatestDate();

        // Get time difference in milliseconds. Instantiate hour, minute, and second strings.
        long difference = now.getTimeInMillis() - latest.getTimeInMillis();
        String hoursString, minutesString, secondsString;

        // Calculation for number of hours.
        int hours = (int) difference / (1000 * 60 * 60);
        hoursString = (hours < 10) ? 0 + "" + hours : "" + hours;

        // Calculation for number of minutes.
        int minutes = (int) difference / (60 * 1000) % 60;
        minutesString = (minutes < 10) ? 0 + "" + minutes : "" + minutes;

        // Calculation for number of seconds.
        int seconds = (int) difference / 1000 % 60;
        secondsString = (seconds < 10) ? 0 + "" + seconds : "" + seconds;

        // return formatted string.
        return hoursString + ":" + minutesString + ":" + secondsString;
    }

    /**
     * If there is no logged in user, displays the log in prompt.
     */
    public void login() {

        // Check if a user exists in the database. If not, user is prompted to log in
        Cursor c = null;
        try {
            c = datasource.query(true, TapOpenHelper.USER_TABLE_NAME, null, null, null, null, null, null, null);
        } catch (Exception e) {

            // If this call fails, this is first use. Create the database
            TapOpenHelper th = new TapOpenHelper(MainActivity.this);
            SQLiteDatabase db = th.getReadableDatabase();
            th.onCreate(db);
        }

        // No users exist in database
        if (c != null && c.getCount() == 0) {
            AlertDialog.Builder b = new AlertDialog.Builder(this);
            b.setTitle("Login");

            // Get login dialog layout
            LayoutInflater inflater = this.getLayoutInflater();
            View v = inflater.inflate(R.layout.login, null);

            // Instantiate EditTexts for username and password.
            final EditText username = (EditText) v.findViewById(R.id.username);
            final EditText password = (EditText) v.findViewById(R.id.password);

            b.setView(v);
            b.setPositiveButton("Login", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                }
            });
            b.setNegativeButton("Register", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                }
            });
            alert = b.create();

            alert.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialog) {
                    Button login = alert.getButton(DialogInterface.BUTTON_POSITIVE);
                    Button register = alert.getButton(DialogInterface.BUTTON_NEGATIVE);
                    login.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {

                            // Make sure EditTexts are not empty
                            if (username.getText().toString().equals("")) {
                                Toast.makeText(getBaseContext(), "Please enter email address", Toast.LENGTH_SHORT)
                                        .show();
                            } else if (password.getText().toString().equals("")) {
                                Toast.makeText(getBaseContext(), "Please enter license number", Toast.LENGTH_SHORT)
                                        .show();
                            } else {
                                // Create User object and set fields needed for async
                                Gson gson = new Gson();
                                User u = new User();
                                u.setUsername(username.getText().toString());
                                u.setPassword(password.getText().toString());

                                // Create json string of activation object
                                String json = gson.toJson(u, User.class);

                                // Begin async to authenticate the user's credentials
                                AuthenticateUserAsync async = new AuthenticateUserAsync(context, new CallBack());

                                // If internet connection exists, DO IT, else, tell user they need to connect
                                if (helper.haveNetworkConnection()) {
                                    async.execute(json);
                                } else {
                                    Toast.makeText(getBaseContext(), "No Network Connection", Toast.LENGTH_LONG)
                                            .show();
                                }
                            }
                        }
                    });

                    // If user clicks register, bring up the registration prompt.
                    register.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            alert.dismiss();
                            register();
                        }
                    });
                }

            });

            // Show the prompt, if the user cancels, close the application
            alert.show();
            alert.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    finish();
                }
            });

        } else {
            // If user is already logged in, get their information and set the textviews on the main activity
            user = datasource.getUser();
        }
    }

    /**
     * Creates the dialog for a user to register with the application.
     */
    public void register() {

        // Instantiate dialog.
        AlertDialog.Builder b = new AlertDialog.Builder(this);
        b.setTitle("Register");

        // Get register dialog layout
        LayoutInflater inflater = this.getLayoutInflater();
        View v = inflater.inflate(R.layout.register, null);

        // Instantiate EditTexts for username, password, and password confirmation.
        final EditText u = (EditText) v.findViewById(R.id.username);
        final EditText p = (EditText) v.findViewById(R.id.password);
        final EditText cp = (EditText) v.findViewById(R.id.confirm_password);

        b.setView(v);
        b.setPositiveButton("Register", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        alert = b.create();

        alert.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                Button register = alert.getButton(DialogInterface.BUTTON_POSITIVE);
                register.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // Make sure EditTexts are not empty
                        if (u.getText().toString().equals("")) {
                            Toast.makeText(getBaseContext(), "Please enter email address", Toast.LENGTH_SHORT)
                                    .show();
                        } else if (p.getText().toString().equals("") || cp.getText().toString().equals("")) {
                            Toast.makeText(getBaseContext(), "Please enter license number", Toast.LENGTH_SHORT)
                                    .show();
                        } else {
                            // Create User object and set fields needed for async
                            Gson gson = new Gson();
                            User us = new User();
                            us.setUsername(u.getText().toString());
                            us.setPassword(p.getText().toString());
                            us.setPasswordConfirmation(cp.getText().toString());

                            // Create object fit to satisfy json transfer to server.
                            ServerUser s = new ServerUser(us);

                            // Create json string of ServerUser object
                            String json = gson.toJson(s, ServerUser.class);

                            // Begin async to authenticate the user's credentials
                            CreateUserAsync async = new CreateUserAsync(context, new CallBack());

                            // If internet connection exists, DO IT, else, tell user they need to connect
                            if (helper.haveNetworkConnection()) {
                                async.execute(json);
                            } else {
                                Toast.makeText(getBaseContext(), "No Network Connection", Toast.LENGTH_LONG).show();
                            }
                        }
                    }
                });
            }

        });

        // Show the prompt, if the user cancels, close the application
        alert.show();
        alert.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                login();
            }
        });
    }

    /**
     * Shows an alert asking the user if they wish to log out. If no, cancels. If yes, logs the user out.
     */
    public void logOutAlert() {
        AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
        b.setTitle(Html
                .fromHtml("Are you sure you want to log out?\n" + "<b>" + "Unsynced data will be lost." + "</b>"));
        b.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

                // Reset total cups text and log out, then call login prompt.
                cups.setText("0.0 cups");
                TapOpenHelper th = new TapOpenHelper(MainActivity.this);
                SQLiteDatabase db = th.getWritableDatabase();
                th.logOut(db);
                login();
            }
        });
        b.setNegativeButton("No", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        b.show();
    }

    /**
     * Posts drink object to the server.
     *
     * @param cat: String detailing the category of the drink to be sent to the server
     */
    public void drinkPost(String cat) {
        Drink d = new Drink(cat);
        ServerDrink s = new ServerDrink(datasource.getUser().getDeviceToken(), d);
        String json = gson.toJson(s, ServerDrink.class);
        CreateDrinkAsync async = new CreateDrinkAsync(context, new CallBack());
        async.execute(json);
    }

    @Override
    public void onResume() {
        super.onResume();
        System.out.println("Alarm manager setup");
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        String prompts = prefs.getString("prompts", "5");
        String beginStr = prefs.getString("begin_time", "");
        String endStr = prefs.getString("end_time", "");
        Calendar beginCal = Calendar.getInstance();
        Calendar endCal = Calendar.getInstance();
        try {
            beginCal.setTime(sdf.parse(beginStr));
            endCal.setTime(sdf.parse(endStr));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        long interval = notificationIntervalCalculation(Integer.valueOf(prompts), beginCal, endCal);
        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
        Intent i = new Intent(context, NotificationService.class);
        PendingIntent pi = PendingIntent.getService(context, 0, i, 0);
        am.cancel(pi);

        // by my own convention, minutes <= 0 means notifications are disabled
        if (interval > 0) {
            am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + interval,
                    interval, pi);
        }
    }

    public long notificationIntervalCalculation(int prompts, Calendar begin, Calendar end) {
        long timeSpan = end.getTimeInMillis() - begin.getTimeInMillis();
        System.out.println(timeSpan / prompts);
        return timeSpan / prompts;
    }
}