package nl.sense_os.service.scheduler; import java.util.concurrent.CopyOnWriteArrayList; import android.content.Context; import android.util.Log; /** * This class is responsible for scheduling the sampling tasks of the phone, as also the sensor data * transmission. It applies batch scheduling and opportunistic execution algorithms in order to * reduce the number of CPU wakeups and thus the energy consumption. * * @author Kimon Tsitsikas <kimon@sense-os.nl> */ public class Scheduler { protected static class Task { public Runnable runnable; public long interval; public long flexibility; public long nextExecution; } private static final String TAG = "Scheduler"; private static Scheduler sInstance; /** * Factory method to get the singleton instance. * * @param context * @return instance */ public static Scheduler getInstance(Context context) { if (sInstance == null) { sInstance = new Scheduler(context); } return sInstance; } private final Context mContext; private CopyOnWriteArrayList<Task> mTasks = new CopyOnWriteArrayList<Task>(); /** * Constructor. * * @param context */ protected Scheduler(Context context) { mContext = context; } /** * Registers a new task to be scheduled with a given interval. * * @param command * The runnable of the new task * @param sensorInterval * Execution interval of the new task * @param sensorFlexibility * Delay tolerance of task execution */ public synchronized void register(Runnable command, long sensorInterval, long sensorFlexibility) { Log.v(TAG, "Register new sample task at " + sensorInterval + "ms interval"); ScheduleAlarmTool scheduleTool = ScheduleAlarmTool.getInstance(mContext); // prepare task object Task newTask = new Task(); newTask.runnable = command; newTask.interval = sensorInterval; newTask.flexibility = sensorFlexibility; // add the task to the list of tasks int index = -1; for (Task task : mTasks) { if (task.runnable.equals(newTask.runnable)) { index = mTasks.indexOf(task); } } if (index != -1) { // remove existing task (probably interval changed) mTasks.remove(index); } // add new task to the end of the list mTasks.add(newTask); scheduleTool.setTasks(mTasks); scheduleTool.resetNextExecution(); scheduleTool.cancelDeterministicAlarm(); scheduleTool.cancelOpportunisticAlarm(); scheduleTool.schedule(); } /** * Unregisters a task. * * @param command */ public synchronized void unregister(Runnable command) { Log.v(TAG, "Unregister sample task"); for (Task task : mTasks) { if (task.runnable.equals(command)) { mTasks.remove(task); } } // stop scheduling alarms ScheduleAlarmTool scheduleTool = ScheduleAlarmTool.getInstance(mContext); scheduleTool.cancelDeterministicAlarm(); scheduleTool.cancelOpportunisticAlarm(); // update reschedule alarms scheduleTool.setTasks(mTasks); if (!mTasks.isEmpty()) { // reschedule! there are still other tasks scheduleTool.resetNextExecution(); scheduleTool.cancelDeterministicAlarm(); scheduleTool.cancelOpportunisticAlarm(); scheduleTool.schedule(); } else { // nothing to do } } }