org.thecongers.mtpms.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.thecongers.mtpms.MainActivity.java

Source

/*
Copyright (C) 2014 Keith Conger <keith.conger@gmail.com>
    
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package org.thecongers.mtpms;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.UUID;

public class MainActivity extends ActionBarActivity {

    private SharedPreferences sharedPrefs;
    private NotificationManager notificationManager;

    private View root;
    private LinearLayout layoutFront;
    private LinearLayout layoutRear;
    private TextView txtOutput;
    private TextView txtFrontPressure;
    private TextView txtFrontTemperature;
    private TextView txtFrontVoltage;
    private TextView txtRearPressure;
    private TextView txtRearTemperature;
    private TextView txtRearVoltage;

    private Drawable background;
    private Drawable redBackground;
    private Drawable backgroundDark;
    private Drawable redBackgroundDark;
    private Drawable txtOutBackground;
    private Drawable txtOutBackgroundDark;

    private BluetoothAdapter btAdapter = null;
    // SPP UUID service
    private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    private static final String TAG = "mTPMS";
    private final int RECEIVE_MESSAGE = 1; // Status for Handler
    private static final int SETTINGS_RESULT = 1;
    private String address;
    private int frontStatus = 0;
    private int rearStatus = 0;
    private boolean itsDark = false;
    private long darkTimer = 0;
    private long lightTimer = 0;
    static boolean hasSensor = false;
    static SensorIdDatabase sensorDB;
    private LogData logger = null;
    private Handler sensorMessages;
    private ConnectThread btConnectThread;

    @SuppressLint("HandlerLeak")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        setTitle(R.string.app_name);

        layoutFront = (LinearLayout) findViewById(R.id.layoutFront);
        layoutRear = (LinearLayout) findViewById(R.id.layoutRear);
        txtFrontPressure = (TextView) findViewById(R.id.txtFrontPressure);
        txtFrontTemperature = (TextView) findViewById(R.id.txtFrontTemperature);
        txtFrontVoltage = (TextView) findViewById(R.id.txtFrontVoltage);
        txtRearPressure = (TextView) findViewById(R.id.txtRearPressure);
        txtRearTemperature = (TextView) findViewById(R.id.txtRearTemperature);
        txtRearVoltage = (TextView) findViewById(R.id.txtRearVoltage);
        txtOutput = (TextView) findViewById(R.id.txtOutput);
        View myView = findViewById(R.id.appLayout);
        root = myView.getRootView();

        sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);

        // Keep screen on
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        // Watch for Bluetooth Changes
        IntentFilter filter1 = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
        IntentFilter filter2 = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
        IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        this.registerReceiver(btReceiver, filter1);
        this.registerReceiver(btReceiver, filter2);
        this.registerReceiver(btReceiver, filter3);

        sensorDB = new SensorIdDatabase(this);

        // Backgrounds
        background = this.getResources().getDrawable(R.drawable.rectangle_bordered);
        redBackground = this.getResources().getDrawable(R.drawable.rectangle_bordered_red);
        backgroundDark = this.getResources().getDrawable(R.drawable.rectangle_bordered_dark);
        redBackgroundDark = this.getResources().getDrawable(R.drawable.rectangle_bordered_red_dark);
        txtOutBackground = this.getResources().getDrawable(R.drawable.rectangle);
        txtOutBackgroundDark = this.getResources().getDrawable(R.drawable.rectangle_dark);

        // Update textViews with select units
        String pressureFormat = sharedPrefs.getString("prefpressuref", "0");
        String pressureUnit = "psi";
        if (pressureFormat.contains("1")) {
            // KPa
            pressureUnit = "KPa";
        } else if (pressureFormat.contains("2")) {
            // Kg-f
            pressureUnit = "Kg-f";
        } else if (pressureFormat.contains("3")) {
            // Bar
            pressureUnit = "Bar";
        }
        String temperatureUnit = "C";
        if (sharedPrefs.getString("preftempf", "0").contains("0")) {
            // F
            temperatureUnit = "F";
        }

        txtFrontPressure.setText("--- " + pressureUnit);
        txtFrontTemperature.setText("--- " + temperatureUnit);
        txtFrontVoltage.setText("--- V");
        txtRearPressure.setText("--- " + pressureUnit);
        txtRearTemperature.setText("--- " + temperatureUnit);
        txtRearVoltage.setText("--- V");

        // Set initial color scheme
        if (!sharedPrefs.getBoolean("prefNightMode", false)) {
            root.setBackgroundColor(getResources().getColor(android.R.color.white));
            layoutFront.setBackground(background);
            layoutRear.setBackground(background);
            txtFrontPressure.setTextColor(getResources().getColor(android.R.color.black));
            txtFrontTemperature.setTextColor(getResources().getColor(android.R.color.black));
            txtFrontVoltage.setTextColor(getResources().getColor(android.R.color.black));
            txtRearPressure.setTextColor(getResources().getColor(android.R.color.black));
            txtRearTemperature.setTextColor(getResources().getColor(android.R.color.black));
            txtRearVoltage.setTextColor(getResources().getColor(android.R.color.black));
            txtOutput.setBackground(txtOutBackground);
            txtOutput.setTextColor(getResources().getColor(android.R.color.black));
        } else {
            root.setBackgroundColor(getResources().getColor(android.R.color.black));
            layoutFront.setBackground(backgroundDark);
            layoutRear.setBackground(backgroundDark);
            txtFrontPressure.setTextColor(getResources().getColor(android.R.color.white));
            txtFrontTemperature.setTextColor(getResources().getColor(android.R.color.white));
            txtFrontVoltage.setTextColor(getResources().getColor(android.R.color.white));
            txtRearPressure.setTextColor(getResources().getColor(android.R.color.white));
            txtRearTemperature.setTextColor(getResources().getColor(android.R.color.white));
            txtRearVoltage.setTextColor(getResources().getColor(android.R.color.white));
            txtOutput.setBackground(txtOutBackgroundDark);
            txtOutput.setTextColor(getResources().getColor(android.R.color.white));
        }

        // Check if there are sensor to wheel mappings
        if (sharedPrefs.getString("prefFrontID", "").equals("")
                && sharedPrefs.getString("prefRearID", "").equals("")) {
            new AlertDialog.Builder(this).setTitle(R.string.alert_setup_title)
                    .setMessage(R.string.alert_setup_message).setNeutralButton(R.string.alert_setup_button, null)
                    .show();
        }

        sensorMessages = new Handler() {
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case RECEIVE_MESSAGE:
                    // Message received
                    Log.d(TAG, "Serial Message Received, Length: " + msg.arg1);
                    // Check to see if message is the correct size
                    if (msg.arg1 == 13) {
                        byte[] readBuf = (byte[]) msg.obj;

                        // Validate against checksum
                        int calculatedCheckSum = readBuf[4] + readBuf[5] + readBuf[6] + readBuf[7] + readBuf[8]
                                + readBuf[9] + readBuf[10];
                        if (calculatedCheckSum == readBuf[11]) {
                            // Convert to hex
                            String[] hexData = new String[13];
                            StringBuilder sbhex = new StringBuilder();
                            for (int i = 0; i < msg.arg1; i++) {
                                hexData[i] = String.format("%02X", readBuf[i]);
                                sbhex.append(hexData[i]);
                            }

                            // Get sensor position
                            String position = hexData[3];
                            // Get sensor ID
                            StringBuilder sensorID = new StringBuilder();
                            sensorID.append(hexData[4]);
                            sensorID.append(hexData[5]);
                            sensorID.append(hexData[6]);
                            sensorID.append(hexData[7]);

                            // Check if sensor ID is new
                            boolean checkID = sensorDB.sensorIdExists(sensorID.toString());
                            if (!checkID) {
                                // Add sensor ID to db
                                sensorDB.addID(sensorID.toString());
                                Toast.makeText(MainActivity.this, getResources().getString(R.string.toast_newSensor)
                                        + " " + sensorID.toString(), Toast.LENGTH_LONG).show();
                            }
                            // Only parse message if there is one or more sensor mappings
                            String prefFrontID = sharedPrefs.getString("prefFrontID", "");
                            String prefRearID = sharedPrefs.getString("prefRearID", "");
                            if (!prefFrontID.equals("") || !prefRearID.equals("")) {
                                try {
                                    // Get temperature
                                    int tempC = Integer.parseInt(hexData[8], 16) - 50;
                                    double temp = tempC;
                                    String temperatureUnit = "C";
                                    // Get tire pressure
                                    int psi = Integer.parseInt(hexData[9], 16);
                                    double pressure = psi;
                                    String pressureUnit = "psi";
                                    // Get battery voltage
                                    double voltage = Integer.parseInt(hexData[10], 16) / 50;
                                    // Get pressure thresholds
                                    int fLowPressure = Integer
                                            .parseInt(sharedPrefs.getString("prefFrontLowPressure", "30"));
                                    int fHighPressure = Integer
                                            .parseInt(sharedPrefs.getString("prefFrontHighPressure", "46"));
                                    int rLowPressure = Integer
                                            .parseInt(sharedPrefs.getString("prefRearLowPressure", "30"));
                                    int rHighPressure = Integer
                                            .parseInt(sharedPrefs.getString("prefRearHighPressure", "46"));
                                    if (sharedPrefs.getString("preftempf", "0").contains("0")) {
                                        // F
                                        temp = (9.0 / 5.0) * tempC + 32.0;
                                        temperatureUnit = "F";
                                    }
                                    int formattedTemperature = (int) (temp + 0.5d);
                                    String pressureFormat = sharedPrefs.getString("prefpressuref", "0");
                                    if (pressureFormat.contains("1")) {
                                        // KPa
                                        pressure = psi * 6.894757293168361;
                                        pressureUnit = "KPa";
                                    } else if (pressureFormat.contains("2")) {
                                        // Kg-f
                                        pressure = psi * 0.070306957965539;
                                        pressureUnit = "Kg-f";
                                    } else if (pressureFormat.contains("3")) {
                                        // Bar
                                        pressure = psi * 0.0689475729;
                                        pressureUnit = "Bar";
                                    }
                                    int formattedPressure = (int) (pressure + 0.5d);
                                    // Get checksum
                                    String checksum = hexData[11];
                                    Log.d(TAG,
                                            "Sensor ID: " + sensorID.toString() + ", Sensor Position: " + position
                                                    + ", Temperature(" + temperatureUnit + "): "
                                                    + String.valueOf(temp) + ", Pressure(" + pressureUnit + "): "
                                                    + String.valueOf(pressure) + ", Voltage: "
                                                    + String.valueOf(voltage) + ", Checksum: " + checksum
                                                    + ", Data: " + sbhex.toString() + ", Bytes:" + msg.arg1);

                                    if (sensorID.toString().equals(prefFrontID)) {
                                        Log.d(TAG, "Front ID matched");
                                        // Check for data logging enabled
                                        if (sharedPrefs.getBoolean("prefDataLogging", false)) {
                                            // Log data
                                            if (logger == null) {
                                                logger = new LogData();
                                            }
                                            logger.write("front", String.valueOf(psi), String.valueOf(tempC),
                                                    String.valueOf(voltage));
                                        }

                                        // Set front tire status
                                        if (psi <= fLowPressure) {
                                            frontStatus = 1;
                                        } else if (psi >= fHighPressure) {
                                            frontStatus = 2;
                                        } else {
                                            frontStatus = 0;
                                        }

                                        txtFrontPressure
                                                .setText(String.valueOf(formattedPressure) + " " + pressureUnit);
                                        txtFrontTemperature.setText(
                                                String.valueOf(formattedTemperature) + " " + temperatureUnit);
                                        txtFrontVoltage.setText(String.format("%.2f", voltage) + " V");
                                    } else if (sensorID.toString().equals(prefRearID)) {
                                        Log.d(TAG, "Rear ID matched");
                                        // Check for data logging enabled
                                        if (sharedPrefs.getBoolean("prefDataLogging", false)) {
                                            // Log data
                                            if (logger == null) {
                                                logger = new LogData();
                                            }
                                            logger.write("rear", String.valueOf(psi), String.valueOf(tempC),
                                                    String.valueOf(voltage));
                                        }

                                        // Set rear tire status
                                        if (psi <= rLowPressure) {
                                            rearStatus = 1;
                                        } else if (psi >= rHighPressure) {
                                            rearStatus = 2;
                                        } else {
                                            rearStatus = 0;
                                        }
                                        txtRearPressure
                                                .setText(String.valueOf(formattedPressure) + " " + pressureUnit);
                                        txtRearTemperature.setText(
                                                String.valueOf(formattedTemperature) + " " + temperatureUnit);
                                        txtRearVoltage.setText(String.format("%.2f", voltage) + " V");
                                    }
                                    // Update txtOutput box and send notification
                                    if ((frontStatus == 0) && (rearStatus == 0)) {
                                        txtOutput.setText("");
                                        if (notificationManager != null) {
                                            notificationManager.cancel(0);
                                        }
                                    } else if ((frontStatus == 1) && (rearStatus == 0)) {
                                        txtOutput
                                                .setText(getResources().getString(R.string.alert_lowFrontPressure));
                                        Notify(getResources().getString(R.string.alert_lowFrontPressure));
                                    } else if ((frontStatus == 2) && (rearStatus == 0)) {
                                        txtOutput.setText(
                                                getResources().getString(R.string.alert_highFrontPressure));
                                        Notify(getResources().getString(R.string.alert_highFrontPressure));
                                    } else if ((rearStatus == 1) && (frontStatus == 0)) {
                                        txtOutput.setText(getResources().getString(R.string.alert_lowRearPressure));
                                        Notify(getResources().getString(R.string.alert_lowRearPressure));
                                    } else if ((rearStatus == 2) && (frontStatus == 0)) {
                                        txtOutput
                                                .setText(getResources().getString(R.string.alert_highRearPressure));
                                        Notify(getResources().getString(R.string.alert_highRearPressure));
                                    } else if ((frontStatus == 1) && (rearStatus == 1)) {
                                        txtOutput.setText(
                                                getResources().getString(R.string.alert_lowFrontLowRearPressure));
                                        Notify(getResources().getString(R.string.alert_lowFrontLowRearPressure));
                                    } else if ((frontStatus == 2) && (rearStatus == 2)) {
                                        txtOutput.setText(
                                                getResources().getString(R.string.alert_highFrontHighRearPressure));
                                        Notify(getResources().getString(R.string.alert_highFrontHighRearPressure));
                                    } else if ((frontStatus == 1) && (rearStatus == 2)) {
                                        txtOutput.setText(
                                                getResources().getString(R.string.alert_lowFrontHighRearPressure));
                                        Notify(getResources().getString(R.string.alert_lowFrontHighRearPressure));
                                    } else if ((frontStatus == 2) && (rearStatus == 1)) {
                                        txtOutput.setText(
                                                getResources().getString(R.string.alert_highFrontLowRearPressure));
                                        Notify(getResources().getString(R.string.alert_highFrontLowRearPressure));
                                    }
                                    // Update color scheme
                                    if ((!itsDark) && (!sharedPrefs.getBoolean("prefNightMode", false))) {
                                        if (frontStatus == 0) {
                                            layoutFront.setBackground(background);
                                        } else {
                                            layoutFront.setBackground(redBackground);
                                        }
                                        if (rearStatus == 0) {
                                            layoutRear.setBackground(background);
                                        } else {
                                            layoutRear.setBackground(redBackground);
                                        }
                                        root.setBackgroundColor(getResources().getColor(android.R.color.white));
                                        txtOutput.setBackground(txtOutBackground);
                                        txtOutput.setTextColor(getResources().getColor(android.R.color.black));
                                        txtFrontPressure
                                                .setTextColor(getResources().getColor(android.R.color.black));
                                        txtFrontTemperature
                                                .setTextColor(getResources().getColor(android.R.color.black));
                                        txtFrontVoltage
                                                .setTextColor(getResources().getColor(android.R.color.black));
                                        txtRearPressure
                                                .setTextColor(getResources().getColor(android.R.color.black));
                                        txtRearTemperature
                                                .setTextColor(getResources().getColor(android.R.color.black));
                                        txtRearVoltage.setTextColor(getResources().getColor(android.R.color.black));
                                    } else {
                                        if (frontStatus == 0) {
                                            layoutFront.setBackground(backgroundDark);
                                        } else {
                                            layoutFront.setBackground(redBackgroundDark);
                                        }
                                        if (rearStatus == 0) {
                                            layoutRear.setBackground(backgroundDark);
                                        } else {
                                            layoutRear.setBackground(redBackgroundDark);
                                        }
                                        root.setBackgroundColor(getResources().getColor(android.R.color.black));
                                        txtOutput.setBackground(txtOutBackgroundDark);
                                        txtOutput.setTextColor(getResources().getColor(android.R.color.white));
                                        txtFrontPressure
                                                .setTextColor(getResources().getColor(android.R.color.white));
                                        txtFrontTemperature
                                                .setTextColor(getResources().getColor(android.R.color.white));
                                        txtFrontVoltage
                                                .setTextColor(getResources().getColor(android.R.color.white));
                                        txtRearPressure
                                                .setTextColor(getResources().getColor(android.R.color.white));
                                        txtRearTemperature
                                                .setTextColor(getResources().getColor(android.R.color.white));
                                        txtRearVoltage.setTextColor(getResources().getColor(android.R.color.white));
                                    }
                                } catch (NumberFormatException e) {
                                    Log.d(TAG, "Malformed message, unexpected value");
                                }
                            }
                        }
                    } else {
                        Log.d(TAG, "Malformed message, message length: " + msg.arg1);
                    }
                    break;
                }
            }
        };
        // Light Sensor Stuff
        SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

        if (lightSensor == null) {
            Log.d(TAG, "Light sensor not found");
        } else {
            float max = lightSensor.getMaximumRange();
            sensorManager.registerListener(lightSensorEventListener, lightSensor,
                    SensorManager.SENSOR_DELAY_NORMAL);
            hasSensor = true;
            Log.d(TAG, "Light Sensor Max Value: " + max);
        }
        // Try to connect to iTPMSystem
        btConnect();
    }

    @Override
    protected void onStop() {
        try {
            unregisterReceiver(btReceiver);
        } catch (IllegalArgumentException e) {
            Log.d(TAG, "Receiver not registered");
        }
        super.onStop();
    }

    // Called when screen rotates or size changes
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        setContentView(R.layout.activity_main);

        // Redraw Screen
        layoutFront = (LinearLayout) findViewById(R.id.layoutFront);
        layoutRear = (LinearLayout) findViewById(R.id.layoutRear);
        // Restore Text
        CharSequence currentTxtFrontPressure = txtFrontPressure.getText();
        txtFrontPressure = (TextView) findViewById(R.id.txtFrontPressure);
        txtFrontPressure.setText(currentTxtFrontPressure);

        CharSequence currentTxtFrontTemperature = txtFrontTemperature.getText();
        txtFrontTemperature = (TextView) findViewById(R.id.txtFrontTemperature);
        txtFrontTemperature.setText(currentTxtFrontTemperature);

        CharSequence currentTxtFrontVoltage = txtFrontVoltage.getText();
        txtFrontVoltage = (TextView) findViewById(R.id.txtFrontVoltage);
        txtFrontVoltage.setText(currentTxtFrontVoltage);

        CharSequence currentTxtRearPressure = txtRearPressure.getText();
        txtRearPressure = (TextView) findViewById(R.id.txtRearPressure);
        txtRearPressure.setText(currentTxtRearPressure);

        CharSequence currentTxtRearTemperature = txtRearTemperature.getText();
        txtRearTemperature = (TextView) findViewById(R.id.txtRearTemperature);
        txtRearTemperature.setText(currentTxtRearTemperature);

        CharSequence currentTxtRearVoltage = txtRearVoltage.getText();
        txtRearVoltage = (TextView) findViewById(R.id.txtRearVoltage);
        txtRearVoltage.setText(currentTxtRearVoltage);

        CharSequence currentTxt = txtOutput.getText();
        txtOutput = (TextView) findViewById(R.id.txtOutput);
        txtOutput.setText(currentTxt);

        // Restore Colors
        if ((!itsDark) && (!sharedPrefs.getBoolean("prefNightMode", false))) {
            if (frontStatus > 0) {
                layoutFront.setBackground(redBackground);
            } else {
                layoutFront.setBackground(background);
            }
            if (rearStatus > 0) {
                layoutRear.setBackground(redBackground);
            } else {
                layoutRear.setBackground(background);
            }
            root.setBackgroundColor(getResources().getColor(android.R.color.white));
            txtOutput.setBackground(txtOutBackground);
            txtFrontPressure.setTextColor(getResources().getColor(android.R.color.black));
            txtFrontTemperature.setTextColor(getResources().getColor(android.R.color.black));
            txtFrontVoltage.setTextColor(getResources().getColor(android.R.color.black));
            txtRearPressure.setTextColor(getResources().getColor(android.R.color.black));
            txtRearTemperature.setTextColor(getResources().getColor(android.R.color.black));
            txtRearVoltage.setTextColor(getResources().getColor(android.R.color.black));
            txtOutput.setTextColor(getResources().getColor(android.R.color.black));

        } else {
            if (frontStatus > 0) {
                layoutFront.setBackground(redBackgroundDark);
            } else {
                layoutFront.setBackground(backgroundDark);
            }
            if (rearStatus > 0) {
                layoutRear.setBackground(redBackgroundDark);
            } else {
                layoutRear.setBackground(backgroundDark);
            }
            root.setBackgroundColor(getResources().getColor(android.R.color.black));
            txtOutput.setBackground(txtOutBackgroundDark);
            txtFrontPressure.setTextColor(getResources().getColor(android.R.color.white));
            txtFrontTemperature.setTextColor(getResources().getColor(android.R.color.white));
            txtFrontVoltage.setTextColor(getResources().getColor(android.R.color.white));
            txtRearPressure.setTextColor(getResources().getColor(android.R.color.white));
            txtRearTemperature.setTextColor(getResources().getColor(android.R.color.white));
            txtRearVoltage.setTextColor(getResources().getColor(android.R.color.white));
            txtOutput.setTextColor(getResources().getColor(android.R.color.white));
        }
    }

    //Draw options menu
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    // When options menu item is selected
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_settings:
            // Settings Menu was selected
            Intent i = new Intent(getApplicationContext(), UserSettingActivity.class);
            startActivityForResult(i, SETTINGS_RESULT);
            return true;
        case R.id.action_sensorReset:
            // Sensor Reset Menu Item was selected
            sensorDB.purgeID();
            SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
            settings.edit().remove("prefFrontID").apply();
            settings.edit().remove("prefRearID").apply();
            return true;
        case R.id.action_about:
            // About was selected
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle(getResources().getString(R.string.alert_about_title));
            builder.setMessage(readRawTextFile(this, R.raw.about));
            builder.setPositiveButton(getResources().getString(R.string.alert_about_button), null);
            builder.show();
            return true;
        case R.id.action_exit:
            // Exit menu item was selected
            if (logger != null) {
                logger.shutdown();
            }
            finish();
            System.exit(0);
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    //Runs when settings are updated
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == SETTINGS_RESULT) {
            updateUserSettings();
        }
    }

    // Update UI when settings are updated
    private void updateUserSettings() {
        // Shutdown Logger
        if (!sharedPrefs.getBoolean("prefDataLogging", false) && (logger != null)) {
            logger.shutdown();
        }
    }

    // Connect to iTPMSystem
    private boolean btConnect() {
        btAdapter = BluetoothAdapter.getDefaultAdapter();
        checkBTState();
        if (btAdapter != null) {
            Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();
            // If there are paired devices
            if (pairedDevices.size() > 0) {
                // Loop through paired devices
                for (BluetoothDevice device : pairedDevices) {
                    if (device.getName().contains("iTPMS")) {
                        address = device.getAddress();
                        Log.d(TAG, "Paired iTPMSystem found: " + device.getName() + " " + device.getAddress());
                    }
                }
                if (address == null) {
                    Toast.makeText(MainActivity.this, getResources().getString(R.string.toast_noPaired),
                            Toast.LENGTH_LONG).show();
                    return false;
                }
            }
            if (address != null) {
                // Set up a pointer to the remote node using it's address.
                BluetoothDevice device = btAdapter.getRemoteDevice(address);
                btConnectThread = new ConnectThread(device);
                btConnectThread.start();
            } else {
                Toast.makeText(MainActivity.this, getResources().getString(R.string.toast_noPaired),
                        Toast.LENGTH_LONG).show();
                return false;
            }
            return true;
        }
        Log.d(TAG, "Bluetooth not supported");
        return false;
    }

    private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
        if (Build.VERSION.SDK_INT >= 10) {
            try {
                final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord",
                        new Class[] { UUID.class });
                return (BluetoothSocket) m.invoke(device, MY_UUID);
            } catch (Exception e) {
                Log.e(TAG, "Could not create insecure RFComm Connection", e);
            }
        }
        return device.createRfcommSocketToServiceRecord(MY_UUID);
    }

    // Listens for Bluetooth broadcasts
    private final BroadcastReceiver btReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

            if ((BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) && (device.getName().contains("iTPMS"))) {
                // Do something if connected
                Log.d(TAG, "iTPMSystem Connected");
                btConnect();
            } else if ((BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action))
                    && (device.getName().contains("iTPMS"))) {
                // Do something if disconnected
                Log.d(TAG, "iTPMSystem Disconnected");
            }
        }
    };

    // Check current Bluetooth state
    private void checkBTState() {
        // Check for Bluetooth support and then check to make sure it is turned on
        if (btAdapter == null) {
            Log.d(TAG, "Bluetooth not supported");
        } else {
            if (btAdapter.isEnabled()) {
                Log.d(TAG, "Bluetooth is on");
            } else {
                //Prompt user to turn on Bluetooth
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 1);
            }
        }
    }

    // Bluetooth Connect Thread
    private class ConnectThread extends Thread {
        private final BluetoothSocket btSocket;
        private final BluetoothDevice btDevice;

        public ConnectThread(BluetoothDevice device) {
            // Use a temporary object that is later assigned to mmSocket,
            // because btSocket is final
            BluetoothSocket tmp = null;
            btDevice = device;

            // Get a BluetoothSocket to connect with the given BluetoothDevice
            try {
                tmp = createBluetoothSocket(device);
            } catch (IOException e) {
                Log.d(TAG, "Bluetooth socket create failed: " + e.getMessage() + ".");
            }
            btSocket = tmp;
        }

        public void run() {
            // Cancel discovery because it will slow down the connection
            btAdapter.cancelDiscovery();
            Log.d(TAG, "Connecting to the iTPMSystem...");
            try {
                // Connect the device through the socket. This will block until it succeeds or
                // throws an exception
                btSocket.connect();
                Log.d(TAG, "Connected to: " + btDevice.getName() + " " + btDevice.getAddress());
                MainActivity.this.runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, getResources().getString(R.string.toast_connectedTo) + " "
                                + btDevice.getName() + " " + btDevice.getAddress(), Toast.LENGTH_LONG).show();

                    }
                });
            } catch (IOException connectException) {
                // Unable to connect
                Log.d(TAG, "Unable to connect to the iTPMSystem...");
                try {
                    btSocket.close();
                } catch (IOException closeException) {
                    Log.d(TAG, "Unable to close socket during connection failure");
                }
                return;
            }

            // Do work to manage the connection (in a separate thread)
            ConnectedThread btConnectedThread = new ConnectedThread(btSocket);
            btConnectedThread.start();
        }

        // Cancel an in-progress connection, and close the socket
        public void cancel() {
            try {
                btSocket.close();
            } catch (IOException e) {
                Log.d(TAG, "Unable to close Bluetooth socket");
            }
        }
    }

    // Connected bluetooth thread
    private class ConnectedThread extends Thread {
        private final InputStream btInStream;

        public ConnectedThread(BluetoothSocket socket) {
            InputStream tmpInput = null;

            // Get the input stream, using temp objects because member streams are final
            try {
                tmpInput = socket.getInputStream();
            } catch (IOException e) {
                Log.d(TAG, "IO Exception getting input stream");
            }
            btInStream = tmpInput;
        }

        public void run() {
            byte[] buffer = new byte[256]; // Buffer store for the stream
            int bytes; // Bytes returned from read()

            // Keep listening to the InputStream until an exception occurs
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = btInStream.read(buffer); // Get number of bytes and message in "buffer"
                    sensorMessages.obtainMessage(RECEIVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
                } catch (IOException e) {
                    Log.d(TAG, "IO Exception while reading stream");
                    btConnectThread.cancel();
                    break;
                }
            }
        }
    }

    // Read raw text file
    private static String readRawTextFile(Context ctx, int resId) {
        InputStream inputStream = ctx.getResources().openRawResource(resId);

        InputStreamReader inputreader = new InputStreamReader(inputStream);
        BufferedReader buffreader = new BufferedReader(inputreader);
        String line;
        StringBuilder text = new StringBuilder();

        try {
            while ((line = buffreader.readLine()) != null) {
                text.append(line);
                text.append('\n');
            }
        } catch (IOException e) {
            return null;
        }
        return text.toString();
    }

    //Send Notification
    private void Notify(String notificationMessage) {
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        Intent intent = new Intent(this, MainActivity.class);
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

        String alertURI = sharedPrefs.getString("prefsound", "content://settings/system/notification_sound");
        Uri soundURI = Uri.parse(alertURI);
        // Build notification
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setContentTitle(getResources().getString(R.string.app_shortName))
                .setContentText(notificationMessage).setSmallIcon(R.drawable.notification_icon).setAutoCancel(false)
                .setOnlyAlertOnce(true).setPriority(Notification.PRIORITY_MAX).setContentIntent(pendingIntent);
        // Check for LED enabled
        if (sharedPrefs.getBoolean("prefNotificationLED", true)) {
            builder.setLights(android.graphics.Color.RED, 1500, 1500);
        }
        // Check for sound enabled
        if (sharedPrefs.getBoolean("prefNotificationSound", true)) {
            builder.setSound(soundURI);
        }
        Notification notification = builder.build();
        // Check for vibration enabled
        if (sharedPrefs.getBoolean("prefNotificationVibrate", false)) {
            notification.defaults |= Notification.DEFAULT_VIBRATE;
        }
        // Make alert repeat until read
        notification.flags |= Notification.FLAG_INSISTENT;

        // Send notification
        notificationManager.notify(0, notification);
    }

    // Listens for light sensor events
    private final SensorEventListener lightSensorEventListener = new SensorEventListener() {

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // Do something

        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            if (sharedPrefs.getBoolean("prefAutoNightMode", false)
                    && (!sharedPrefs.getBoolean("prefNightMode", false))) {
                int delay = (Integer.parseInt(sharedPrefs.getString("prefAutoNightModeDelay", "30")) * 1000);
                if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
                    float currentReading = event.values[0];
                    double darkThreshold = 20.0; // Light level to determine darkness
                    if (currentReading < darkThreshold) {
                        lightTimer = 0;
                        if (darkTimer == 0) {
                            darkTimer = System.currentTimeMillis();
                        } else {
                            long currentTime = System.currentTimeMillis();
                            long duration = (currentTime - darkTimer);
                            if ((duration >= delay) && (!itsDark)) {
                                itsDark = true;
                                Log.d(TAG, "Its dark");
                                // Redraw Screen
                                layoutFront = (LinearLayout) findViewById(R.id.layoutFront);
                                layoutRear = (LinearLayout) findViewById(R.id.layoutRear);

                                root.setBackgroundColor(getResources().getColor(android.R.color.black));

                                if (frontStatus > 0) {
                                    layoutFront.setBackground(redBackgroundDark);
                                } else {
                                    layoutFront.setBackground(backgroundDark);
                                }
                                if (rearStatus > 0) {
                                    layoutRear.setBackground(redBackgroundDark);
                                } else {
                                    layoutRear.setBackground(backgroundDark);
                                }
                                txtOutput.setBackground(txtOutBackgroundDark);
                                txtFrontPressure.setTextColor(getResources().getColor(android.R.color.white));
                                txtFrontTemperature.setTextColor(getResources().getColor(android.R.color.white));
                                txtFrontVoltage.setTextColor(getResources().getColor(android.R.color.white));
                                txtRearPressure.setTextColor(getResources().getColor(android.R.color.white));
                                txtRearTemperature.setTextColor(getResources().getColor(android.R.color.white));
                                txtRearVoltage.setTextColor(getResources().getColor(android.R.color.white));
                                txtOutput.setTextColor(getResources().getColor(android.R.color.white));
                            }
                        }
                    } else {
                        darkTimer = 0;
                        if (lightTimer == 0) {
                            lightTimer = System.currentTimeMillis();
                        } else {
                            long currentTime = System.currentTimeMillis();
                            long duration = (currentTime - lightTimer);
                            if ((duration >= delay) && (itsDark)) {
                                itsDark = false;
                                Log.d(TAG, "Its light");
                                // Redraw Screen
                                layoutFront = (LinearLayout) findViewById(R.id.layoutFront);
                                layoutRear = (LinearLayout) findViewById(R.id.layoutRear);

                                root.setBackgroundColor(getResources().getColor(android.R.color.white));
                                if (frontStatus > 0) {
                                    layoutFront.setBackground(redBackground);
                                } else {
                                    layoutFront.setBackground(background);
                                }
                                if (rearStatus > 0) {
                                    layoutRear.setBackground(redBackground);
                                } else {
                                    layoutRear.setBackground(background);
                                }
                                txtOutput.setBackground(txtOutBackground);
                                txtFrontPressure.setTextColor(getResources().getColor(android.R.color.black));
                                txtFrontTemperature.setTextColor(getResources().getColor(android.R.color.black));
                                txtFrontVoltage.setTextColor(getResources().getColor(android.R.color.black));
                                txtRearPressure.setTextColor(getResources().getColor(android.R.color.black));
                                txtRearTemperature.setTextColor(getResources().getColor(android.R.color.black));
                                txtRearVoltage.setTextColor(getResources().getColor(android.R.color.black));
                                txtOutput.setTextColor(getResources().getColor(android.R.color.black));
                            }
                        }
                    }
                }
            }
        }
    };
}