/* * 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.service; import android.app.Notification; import android.app.Service; import android.content.Intent; import android.graphics.Color; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.widget.Toast; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; import com.luan.thermospy.android.core.NotificationHandler; import com.luan.thermospy.android.core.pojo.Temperature; import com.luan.thermospy.android.core.rest.GetTemperatureReq; import com.luan.thermospy.android.fragments.AlarmCondition; import java.util.Observable; import java.util.Observer; /** * The TemperatureMonitorService is responsible for monitoring the current temperature * and notifing the user about the temperature changes/sounding the alarm etc. */ public class TemperatureMonitorService extends Service { private LocalService mService = new LocalService(); private ServiceBinder mBinder = new ServiceBinder(mService); public interface ServiceArguments { static final String REFRESH_RATE = "refreshrate"; static final String IP_ADDRESS = "ipaddress"; static final String PORT = "port"; static final String ALARM_CONDITION = "alarmcondition"; static final String ALARM_ENABLED = "alarmenabled"; static final String ALARM = "alarm"; } private Looper mServiceLooper; private ServiceHandler mServiceHandler; private NotificationHandler mNotificationHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler implements Observer { public boolean m_error; private Temperature m_temperature = null; public ServiceHandler(Looper looper) { super(looper); mNotificationHandler = new NotificationHandler(); mService.addObserver(this); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long refreshInterval = msg.getData().getInt(ServiceArguments.REFRESH_RATE)*1000; String ip = msg.getData().getString(ServiceArguments.IP_ADDRESS); int port = msg.getData().getInt(ServiceArguments.PORT); RequestQueue requestQueue = Volley.newRequestQueue(TemperatureMonitorService.this); boolean mAlarmFired =false; final GetTemperatureReq temperatureReq = new GetTemperatureReq(requestQueue, new GetTemperatureReq.OnGetTemperatureListener() { @Override public void onTemperatureUpdate(Temperature temperature) { synchronized (ServiceHandler.this) { m_temperature = temperature; ServiceHandler.this.notify(); } } @Override public void onTemperatureError() { synchronized (ServiceHandler.this) { m_temperature = null; m_error = true; ServiceHandler.this.notify(); } } }); mService.setRunning(true); while (!mServiceLooper.getThread().isInterrupted()) { synchronized (ServiceHandler.this) { try { temperatureReq.request(ip,port ); wait(refreshInterval*10); } catch (Exception e) { break; } } if (m_error || m_temperature == null) { mService.onServerError(); break; } mService.temperatureChanged(m_temperature); boolean alarmEnabled = mService.isAlarmEnabled(); if (!mAlarmFired && alarmEnabled) { int alarm = mService.getAlarm(); AlarmCondition alarmCondition = mService.getAlarmCondition(); boolean triggerAlarm = alarmCondition.evaluate(m_temperature.getTemperature(), alarm); if (triggerAlarm) { mNotificationHandler.playSound(TemperatureMonitorService.this, m_temperature.toString()); mAlarmFired = true; mService.alarmTriggered(); } else { mNotificationHandler.update(TemperatureMonitorService.this, m_temperature.toString(), getColor(alarmCondition, m_temperature.getTemperature(), alarm)); } } else { if (mAlarmFired && !alarmEnabled) { mAlarmFired = false; } mNotificationHandler.update(TemperatureMonitorService.this, m_temperature.toString(), Notification.COLOR_DEFAULT); } synchronized (ServiceHandler.this) { try { refreshInterval = mService.getRefreshInterval() * 1000; wait(refreshInterval); } catch (InterruptedException e) { break; } } } temperatureReq.cancel(); mNotificationHandler.cancel(TemperatureMonitorService.this); stopSelf(msg.arg1); mService.setRunning(false); } private int getColor(AlarmCondition condition, int temperature, int alarm) { double remaining; if (condition == AlarmCondition.GREATER_THAN_OR_EQUAL) remaining = (double)temperature/alarm; else remaining = (double)alarm/temperature; if (remaining > 0.8) return Color.RED; else if (remaining > 0.6) return 0xffa500; else if (remaining > 0.3) return 0x32cd32; else return Color.BLUE; } @Override public void update(Observable observable, Object data) { synchronized (ServiceHandler.this) { ServiceHandler.this.notify(); } } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", android.os.Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "Temperature monitor starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.setData(intent.getExtras()); mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_REDELIVER_INTENT; } @Override public IBinder onBind(Intent intent) { int condition = intent.getExtras().getInt(ServiceArguments.ALARM_CONDITION); boolean alarmEnabled = intent.getExtras().getBoolean(ServiceArguments.ALARM_ENABLED); int alarm = intent.getExtras().getInt(ServiceArguments.ALARM); int refreshInterval = intent.getExtras().getInt(ServiceArguments.REFRESH_RATE); // We don't provide binding, so return null mService.setRefreshInterval(refreshInterval); mService.setAlarmEnabled(alarmEnabled); mService.setAlarmCondition(AlarmCondition.fromInt(condition)); mService.setAlarm(alarm); return mBinder; } @Override public void onDestroy() { mServiceLooper.quit(); mServiceLooper.getThread().interrupt(); } }