/************************************************************************************************** * Copyright (C) 2010 Sense Observation Systems, Rotterdam, the Netherlands. All rights reserved. * *************************************************************************************************/ package nl.sense_os.service; import nl.sense_os.service.commonsense.DefaultSensorRegistrationService; import nl.sense_os.service.commonsense.senddata.BufferTransmitHandler; import nl.sense_os.service.commonsense.senddata.DataTransmitHandler; import nl.sense_os.service.commonsense.senddata.FileTransmitHandler; import nl.sense_os.service.constants.SenseDataTypes; import nl.sense_os.service.constants.SensePrefs; import nl.sense_os.service.constants.SensePrefs.Auth; import nl.sense_os.service.constants.SensePrefs.Main; import nl.sense_os.service.storage.LocalStorage; import org.json.JSONObject; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; import android.os.Bundle; import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.util.Log; /** * This class is responsible for handling the sensor data that has been collected by the different * sensors. It has two main tasks: * <ul> * <li>Collect incoming sensor data and add it to the buffer.</li> * <li>Periodically transmit all sensor data in the buffer to CommonSense.</li> * </ul> * Sensors that have sampled a new data point should send it to the MsgHandler by sending an Intent * with {@link R.string#action_sense_new_data} that contains the details of the datapoint.<br/> * <br/> * For example: * * <pre> * Intent sensorData = new Intent(getString(R.string.action_sense_new_data)); * sensorData.putExtra(DataPoint.SENSOR_NAME, "sensor name"); * sensorData.putExtra(DataPoint.VALUE, "foo"); * sensorData.putExtra(DataPoint.DATA_TYPE, SenseDataTypes.FLOAT); * sensorData.putExtra(DataPoint.TIMESTAMP, System.currentTimeMillis()); * startService(sensorData); * </pre> * * @author Steven Mulder <steven@sense-os.nl> */ public class MsgHandler extends Service { private static final String TAG = "Sense MsgHandler"; /** * Key for Intent extra that defines the buffer type to send data from. The value should be * either {@link #BUFFER_TYPE_FLASH} or {@link #BUFFER_TYPE_MEMORY}. */ public static final String EXTRA_BUFFER_TYPE = "buffer-type"; public static final int BUFFER_TYPE_FLASH = 1; public static final int BUFFER_TYPE_MEMORY = 0; private static FileTransmitHandler fileHandler; private static DataTransmitHandler dataTransmitHandler; private static BufferTransmitHandler bufferHandler; /** Messenger for communicating with the service. */ Messenger mSenseService = null; /** * Sends data points for one sensor to CommonSense. * * @param name * Sensor name, used to determine the sensor ID at CommonSense * @param description * Sensor description (previously 'device_type'), used to determine the sensor ID at * CommonSense * @param dataType * Sensor data type, used to determine the sensor ID at CommonSense * @param deviceUuid * (Optional) UUID of the sensor's device. Set null to use this phone as the default * device. * @param sensorData * JSON Object with the sensor data. */ public static void sendSensorData(Context context, String name, String description, String dataType, String deviceUuid, JSONObject sensorData) { try { // get cookie for transmission SharedPreferences authPrefs = context.getSharedPreferences(SensePrefs.AUTH_PREFS, MODE_PRIVATE); String cookie = authPrefs.getString(Auth.LOGIN_COOKIE, null); if (cookie.length() > 0) { // prepare message to let handler run task Bundle args = new Bundle(); args.putString("name", name); args.putString("description", description); args.putString("dataType", dataType); args.putString("deviceUuid", deviceUuid); args.putString("cookie", cookie); Message msg = Message.obtain(); msg.setData(args); msg.obj = sensorData; // check for sending a file if (dataType.equals(SenseDataTypes.FILE)) { fileHandler.sendMessage(msg); } else { dataTransmitHandler.sendMessage(msg); } } else { Log.w(TAG, "Cannot send data point! no cookie"); } } catch (Exception e) { Log.e(TAG, "Error in sending sensor data:", e); } } private void handleSendIntent(Intent intent) { Log.d(TAG, "handleSendIntent"); if (isOnline()) { Log.d(TAG, "is online"); // verify the sensor IDs //startService(new Intent(this, DefaultSensorRegistrationService.class)); // get the cookie SharedPreferences authPrefs = getSharedPreferences(SensePrefs.AUTH_PREFS, MODE_PRIVATE); String cookie = authPrefs.getString(Auth.LOGIN_COOKIE, null); // send the message to the handler Message msg = Message.obtain(); Bundle args = new Bundle(); args.putString("cookie", cookie); msg.setData(args); bufferHandler.sendMessage(msg); } } /** * @return <code>true</code> if the phone has network connectivity. */ private boolean isOnline() { SharedPreferences mainPrefs; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { mainPrefs = getSharedPreferences(SensePrefs.MAIN_PREFS, MODE_MULTI_PROCESS); } else { mainPrefs = getSharedPreferences(SensePrefs.MAIN_PREFS, MODE_PRIVATE); } boolean isCommonSenseEnabled = mainPrefs.getBoolean(Main.Advanced.USE_COMMONSENSE, true); SharedPreferences authPrefs; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { authPrefs = getSharedPreferences(SensePrefs.AUTH_PREFS, MODE_MULTI_PROCESS); } else { authPrefs = getSharedPreferences(SensePrefs.AUTH_PREFS, MODE_PRIVATE); } boolean isLoggedIn = authPrefs.getString(Auth.LOGIN_COOKIE, null) != null; final ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); final NetworkInfo info = cm.getActiveNetworkInfo(); return (null != info) && info.isConnected() && isCommonSenseEnabled && isLoggedIn; } @Override public IBinder onBind(Intent intent) { // you cannot bind to this service return null; } @Override public void onCreate() { Log.d(TAG, " on create "); super.onCreate(); { HandlerThread handlerThread = new HandlerThread("TransmitRecentDataThread"); handlerThread.start(); bufferHandler = new BufferTransmitHandler(this, LocalStorage.getInstance(this), handlerThread.getLooper()); } { HandlerThread handlerThread = new HandlerThread("TransmitFileThread"); handlerThread.start(); fileHandler = new FileTransmitHandler(this, LocalStorage.getInstance(this), handlerThread.getLooper()); } { HandlerThread handlerThread = new HandlerThread("TransmitDataPointThread"); handlerThread.start(); dataTransmitHandler = new DataTransmitHandler(this, LocalStorage.getInstance(this), handlerThread.getLooper()); } } @Override public void onDestroy() { // stop buffered data transmission threads bufferHandler.getLooper().quit(); fileHandler.getLooper().quit(); dataTransmitHandler.getLooper().quit(); super.onDestroy(); } /** * Handles an incoming Intent that started the service by checking if it wants to store a new * message or if it wants to send data to CommonSense. */ @Override public int onStartCommand(Intent intent, int flags, int startId) { //if (getString(R.string.action_sense_send_data).equals(intent.getAction())) { handleSendIntent(intent); // } else { // Log.e(TAG, "Unexpected intent action: " + intent.getAction()); // } // this service is not sticky, it will get an intent to restart it if necessary return START_NOT_STICKY; } }