/*
* Copyright 2015 Ludwig Andersson
*
* This file is part of Thermospy-android.
*
* Thermospy-android 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 3 of the License, or
* (at your option) any later version.
*
* Thermospy-android 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 Thermospy-android. If not, see <http://www.gnu.org/licenses/>.
*/
package com.luan.thermospy.android.activities;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
import com.luan.thermospy.android.R;
import com.luan.thermospy.android.core.AlarmSettings;
import com.luan.thermospy.android.core.Coordinator;
import com.luan.thermospy.android.core.LocalServiceObserver;
import com.luan.thermospy.android.core.LocalServiceSubject;
import com.luan.thermospy.android.core.ServerSettings;
import com.luan.thermospy.android.core.pojo.Boundary;
import com.luan.thermospy.android.core.pojo.ServiceStatus;
import com.luan.thermospy.android.core.pojo.Temperature;
import com.luan.thermospy.android.fragments.AlarmCondition;
import com.luan.thermospy.android.fragments.MonitorFragment;
import com.luan.thermospy.android.fragments.NavigationDrawerFragment;
import com.luan.thermospy.android.fragments.RealtimeChartFragment;
import com.luan.thermospy.android.fragments.setup.SetupBoundary;
import com.luan.thermospy.android.fragments.setup.SetupConfirm;
import com.luan.thermospy.android.fragments.setup.SetupService;
import com.luan.thermospy.android.fragments.temperaturelog.LogSessionDialogFragment;
import com.luan.thermospy.android.service.LocalService;
import com.luan.thermospy.android.service.ServiceBinder;
import com.luan.thermospy.android.service.TemperatureMonitorService;
import java.util.ArrayList;
/**
* Main activity
*/
public class MainActivity extends ActionBarActivity
implements SetupService.OnSetupServerListener,
NavigationDrawerFragment.NavigationDrawerCallbacks,
SetupBoundary.OnSetupBoundaryListener,
SetupConfirm.OnThermoSpySetupConfirmedListener,
MonitorFragment.OnMonitorFragmentListener,
LocalServiceSubject,
LocalServiceObserver,
RealtimeChartFragment.OnRealtimeChartFragmentListener{
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Keeps track of the last selected "page"/fragment
*/
private int mLastSelected = -1;
RequestQueue requestQueue;
/**
* Used to store the last screen title. For use in {@link #restoreActionBar()}.
*/
private CharSequence mTitle;
private ArrayList<LocalServiceObserver> mTemperatureObservers = new ArrayList<>();
private String LOG_TAG = MainActivity.class.getSimpleName();
/**
* The local service is responsible for notification handling. The main activity communicates
* alarm settings, refresh rate etc.
*
*/
LocalService mService;
/**
* Flag telling whether or not the local service is bound or not.
*/
boolean mBound = false;
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
ServiceBinder binder = (ServiceBinder) service;
mService = binder.getService();
// Update the service with the latest values
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
try {
int refreshRate = Integer.parseInt(settings.getString(getString(R.string.pref_key_refresh_interval), "5"));
mService.setRefreshInterval(refreshRate);
} catch (Exception e) {
mService.setRefreshInterval(5);
}
try {
mService.setAlarm(Integer.parseInt(Coordinator.getInstance().getAlarmSettings().getAlarm()));
} catch (Exception e) {
mService.setAlarmEnabled(false);
mService.setAlarm(0);
}
mService.setAlarmEnabled(Coordinator.getInstance().getAlarmSettings().isAlarmSwitchEnabled());
mService.setAlarmCondition(Coordinator.getInstance().getAlarmSettings().getAlarmCondition());
mBound = true;
mService.registerObserver(MainActivity.this);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
mService.unregisterObserver(MainActivity.this);
}
};
;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestQueue = Volley.newRequestQueue(this);
Coordinator coordinator = Coordinator.getInstance();
coordinator.initDb(getApplicationContext());
coordinator.setRequestQueue(requestQueue);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
mNavigationDrawerFragment.selectItem(0);
}
@Override
protected void onStart()
{
super.onStart();
bindLocalService();
}
private void bindLocalService()
{
if (!mBound) {
Intent intent = new Intent(this, TemperatureMonitorService.class);
Bundle bundle = new Bundle();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
int interval = Integer.parseInt(settings.getString(getString(R.string.pref_key_refresh_interval), "5"));
bundle.putInt(TemperatureMonitorService.ServiceArguments.ALARM, Integer.parseInt(Coordinator.getInstance().getAlarmSettings().getAlarm()));
bundle.putInt(TemperatureMonitorService.ServiceArguments.ALARM_CONDITION, Coordinator.getInstance().getAlarmSettings().getAlarmCondition().getId());
bundle.putInt(TemperatureMonitorService.ServiceArguments.REFRESH_RATE, interval);
bundle.putBoolean(TemperatureMonitorService.ServiceArguments.ALARM_ENABLED, Coordinator.getInstance().getAlarmSettings().isAlarmSwitchEnabled());
intent.putExtras(bundle);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
@Override
protected void onStop()
{
super.onStop();
Coordinator.getInstance().save();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
@Override
protected void onResume()
{
super.onResume();
if (mLastSelected == 3)
{
mNavigationDrawerFragment.selectItem(0);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Coordinator.getInstance().save();
}
@Override
public void onBackPressed()
{
if (mLastSelected > 0 && Coordinator.getInstance().getServerSettings().isConnected()) {
mNavigationDrawerFragment.selectItem(0);
}
else
{
super.onBackPressed();
}
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
final ServerSettings serverSettings = Coordinator.getInstance().getServerSettings();
final AlarmSettings alarmSettings = Coordinator.getInstance().getAlarmSettings();
final Temperature lastTemperature = Coordinator.getInstance().getTemperature();
final String temperature = lastTemperature == null ? "--" : lastTemperature.toString();
final String ip = serverSettings.getIpAddress();
final int port = serverSettings.getPort();
final boolean isAlarmSwitchChecked = alarmSettings.isAlarmSwitchEnabled();
final AlarmCondition condition = alarmSettings.getAlarmCondition();
final String alarm = alarmSettings.getAlarm();
if (position == 0) {
if (ip.isEmpty() == false && port != -1)
{
android.support.v4.app.FragmentTransaction transaction;
MonitorFragment fragment;
if (isAlarmSwitchChecked)
{
fragment = MonitorFragment.newInstance(ip, port, alarm, temperature);
}
else
{
fragment = MonitorFragment.newInstance(ip, port, getString(R.string.not_enabled), temperature);
}
transaction = getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment);
transaction.commit();
}
else
{
Toast t = Toast.makeText(this, getString(R.string.not_available_no_connection), Toast.LENGTH_SHORT);
t.show();
mNavigationDrawerFragment.selectItem(1);
return;
}
}
else if (position == 1)
{
android.support.v4.app.FragmentTransaction transaction;
transaction = getSupportFragmentManager().beginTransaction()
.replace(R.id.container, SetupService.newInstance(ip, port));
transaction.commit();
}
else if (position == 2)
{
if (serverSettings.isConnected()) {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
String dateformat = settings.getString(getString(R.string.pref_key_dateformat), "yyyy-MM-dd");
String timeformat = settings.getString(getString(R.string.pref_key_timeformat), "HH");
String dateTimeFormat = dateformat + " " + timeformat + ":mm:ss";
if (timeformat.equals("hh")) {
// Show am/pm marker
dateTimeFormat += " a";
}
Intent intent = new Intent(this, LogSessionActivity.class);
intent.putExtra(LogSessionActivity.DATEFORMAT, dateTimeFormat);
startActivity(intent);
return;
}
else
{
Toast t = Toast.makeText(this, getString(R.string.not_available_no_connection), Toast.LENGTH_SHORT);
t.show();
mNavigationDrawerFragment.selectItem(1);
return;
}
}
onSectionAttached(position);
mLastSelected = position;
}
public void onSectionAttached(int number) {
switch (number) {
case 0:
mTitle = getString(R.string.title_section1);
break;
case 1:
mTitle = getString(com.luan.thermospy.android.R.string.title_section2);
break;
case 2:
mTitle = getString(com.luan.thermospy.android.R.string.title_section3);
break;
default:
mTitle = "";
break;
}
}
public void restoreActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
@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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onSetupServerConnectionEstablished(String ipAddress, int port, boolean running) {
FragmentManager fragmentManager = getSupportFragmentManager();
ServerSettings serverSettings = Coordinator.getInstance().getServerSettings();
serverSettings.setRunning(running);
serverSettings.setIpAddress(ipAddress);
serverSettings.setPort(port);
serverSettings.setConnected(true);
if (mBound)
{
mService.setIpAddress(ipAddress);
mService.setPort(port);
}
fragmentManager.beginTransaction()
.replace(R.id.container, SetupBoundary.newInstance(serverSettings.getIpAddress(), serverSettings.getPort()))
.commit();
}
@Override
public void onResetBounds() {
ServerSettings serverSettings = Coordinator.getInstance().getServerSettings();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, SetupBoundary.newInstance(serverSettings.getIpAddress(), serverSettings.getPort()))
.commit();
}
@Override
public void onSetupServerFailed() {
onServiceStatus(new ServiceStatus());
Toast toast = Toast.makeText(getApplicationContext(), R.string.setup_server_failed, Toast.LENGTH_SHORT);
toast.show();
mNavigationDrawerFragment.selectItem(1);
Coordinator.getInstance().getServerSettings().setConnected(false);
}
@Override
public void onSetupServerAborted() {
onServiceStatus(new ServiceStatus());
Toast toast = Toast.makeText(getApplicationContext(), R.string.setup_aborted, Toast.LENGTH_SHORT);
toast.show();
mNavigationDrawerFragment.selectItem(1);
Coordinator.getInstance().getServerSettings().setConnected(false);
}
@Override
public void onBoundsSpecified(Boundary bounds) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, SetupConfirm.newInstance())
.commit();
}
@Override
public void setupConfirmed(String s) {
onServiceStatus(new ServiceStatus());
// Start
mNavigationDrawerFragment.selectItem(0);
}
@Override
public void onServerNotRunning() {
onServiceStatus(new ServiceStatus());
mNavigationDrawerFragment.selectItem(1);
mLastSelected = -1;
if (isMyServiceRunning(TemperatureMonitorService.class)) {
if (mBound) {
unbindService(mConnection);
mBound = false;
}
mService.unregisterObserver(this);
Intent intent = new Intent(this, TemperatureMonitorService.class);
stopService(intent);
}
Coordinator.getInstance().getServerSettings().setConnected(false);
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
return (mBound && mService.isRunning());
}
public void startBackgroundService() {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
int interval = Integer.parseInt(settings.getString(getString(R.string.pref_key_refresh_interval), "5"));
if (!isMyServiceRunning(TemperatureMonitorService.class))
{
// Send intent to start the local service
Intent intent = new Intent(this, TemperatureMonitorService.class);
Bundle bundle = new Bundle();
bundle.putString(TemperatureMonitorService.ServiceArguments.IP_ADDRESS, Coordinator.getInstance().getServerSettings().getIpAddress());
bundle.putInt(TemperatureMonitorService.ServiceArguments.PORT, Coordinator.getInstance().getServerSettings().getPort());
bundle.putInt(TemperatureMonitorService.ServiceArguments.REFRESH_RATE, interval);
intent.putExtras(bundle);
if (mService != null) mService.registerObserver(MainActivity.this);
startService(intent);
}
}
@Override
public void onServiceStatus(ServiceStatus status) {
if (!Coordinator.getInstance().getServerSettings().isConnected()) {
Coordinator.getInstance().getServerSettings().setConnected(true);
}
else
{
Coordinator.getInstance().getServerSettings().setConnected(false);
}
Coordinator.getInstance().getServerSettings().setRunning(status.isRunning());
if (status.isRunning()) {
if (!mBound) {
bindLocalService();
}
// Service is up and running, check if we are bound if not start the service
startBackgroundService();
} else {
if (isMyServiceRunning(TemperatureMonitorService.class)) {
// Service is stopped. Unbound and stop the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
mService.unregisterObserver(this);
Intent intent = new Intent(this, TemperatureMonitorService.class);
stopService(intent);
}
}
}
public void onShowCreateLogSessionDialog(DialogInterface.OnDismissListener dismissListener) {
FragmentManager fm = getSupportFragmentManager();
LogSessionDialogFragment editNameDialog = LogSessionDialogFragment.newInstance(Coordinator.getInstance().getServerSettings());
editNameDialog.setDismissListener(dismissListener);
editNameDialog.show(fm, "fragment_edit_name");
}
@Override
public void onAlarmEnableSwitchChanged(boolean checked) {
onAlarmSwitchChanged(checked);
}
@Override
public void onAlarmChanged(int alarm) {
onAlarmTextChanged(Integer.toString(alarm));
}
public void onAlarmConditionChanged(AlarmCondition alarmCondition) {
Coordinator.getInstance().getAlarmSettings().setAlarmCondition(alarmCondition);
if (mBound)
{
mService.setAlarmCondition(alarmCondition);
}
else
{
startBackgroundService();
}
}
public void onAlarmTextChanged(String alarmText) {
Coordinator.getInstance().getAlarmSettings().setAlarm(alarmText);
if (mBound)
{
mService.setAlarm(Integer.parseInt(alarmText));
}
else
{
startBackgroundService();
}
}
public void onAlarmSwitchChanged(Boolean isChecked) {
CharSequence text;
if (isChecked)
text = getString(R.string.enable_alarm);
else
text = getString(R.string.disable_alarm);
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(getApplicationContext(), text, duration);
toast.show();
Coordinator.getInstance().getAlarmSettings().setAlarmSwitchEnabled(isChecked);
if (mBound)
{
mService.setAlarmEnabled(isChecked);
}
else
{
startBackgroundService();
}
}
@Override
public void registerObserver(LocalServiceObserver listener) {
mTemperatureObservers.add(listener);
if (Coordinator.getInstance().getTemperature() != null) {
listener.onTemperatureRecv(Coordinator.getInstance().getTemperature());
}
}
@Override
public void unregisterObserver(LocalServiceObserver listener) {
mTemperatureObservers.remove(listener);
}
@Override
public void temperatureChanged(Temperature entry) {
Coordinator.getInstance().setTemperature(entry);
for (LocalServiceObserver observer : mTemperatureObservers)
{
observer.onTemperatureRecv(entry);
}
}
@Override
public void alarmTriggered() {
Log.d(LOG_TAG, "Alarm triggered!");
}
@Override
public void onTemperatureRecv(final Temperature temperature) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//stuff that updates ui
temperatureChanged(temperature);
}
});
}
@Override
public void onServerError() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Coordinator.getInstance().setTemperature(null);
for (LocalServiceObserver observer : mTemperatureObservers)
{
observer.onServerError();
}
onServerNotRunning();
}
});
}
@Override
public void onAlarmTriggered() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Coordinator.getInstance().getAlarmSettings().setAlarmSwitchEnabled(false);
for (LocalServiceObserver observer : mTemperatureObservers)
{
observer.onAlarmTriggered();
}
}
});
}
}