package nl.sense_os.service.storage; import java.io.IOException; import java.net.URISyntaxException; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import nl.sense_os.service.commonsense.SenseApi; import nl.sense_os.service.constants.SensePrefs; import nl.sense_os.service.constants.SensePrefs.Auth; import nl.sense_os.service.constants.SenseUrls; import nl.sense_os.service.constants.SensorData.DataPoint; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.util.Log; /** * Class that manages the (read-only) store for sensor data points in the remote CommonSense * storage. Helper class for {@link LocalStorage}. * * @author Steven Mulder <steven@sense-os.nl> */ class RemoteStorage { private static final String TAG = "RemoteStorage"; private Context context; public RemoteStorage(Context context) { this.context = context; } public Cursor query(Uri uri, String[] projection, String where, String[] selectionArgs, int limit, String sortOrder) throws JSONException, URISyntaxException, IOException { // Log.v(TAG, "Query data points in CommonSense"); // try to parse the selection criteria List<String> sensorNames = ParserUtils.getSelectedSensors(new HashSet<String>(), where, selectionArgs); long[] timeRangeSelect = ParserUtils.getSelectedTimeRange(where, selectionArgs); String deviceUuid = ParserUtils.getSelectedDeviceUuid(where, selectionArgs); if (sensorNames.size() != 1) { throw new IllegalArgumentException("Incorrect number of sensors in query: " + sensorNames.size()); } // check if the requested sensor is in the list String id = SenseApi.getSensorId(context, sensorNames.get(0), null, null, deviceUuid); if (null == id) { throw new IllegalArgumentException("Cannot find sensor ID"); } // convert sort order to commonsense format if (null != sortOrder && sortOrder.length() > 0) { if (sortOrder.toLowerCase(Locale.ENGLISH).contains("desc")) { sortOrder = "desc"; } else { sortOrder = "asc"; } } else { sortOrder = "desc"; } // get the data for the sensor String url = SenseUrls.SENSOR_DATA.replace("%1", id) + "?start_date=" + timeRangeSelect[0] / 1000d + "&end_date=" + timeRangeSelect[1] / 1000d; url += "&per_page=" + limit; url += sortOrder != null ? "&sort=" + sortOrder : ""; String cookie = context.getSharedPreferences(SensePrefs.AUTH_PREFS, Context.MODE_PRIVATE) .getString(Auth.LOGIN_COOKIE, null); Map<String, String> response = SenseApi.request(context, url, null, cookie); // parse response JSONArray data; if (response.get(SenseApi.RESPONSE_CODE).equals("200")) { String content = response.get(SenseApi.RESPONSE_CONTENT); JSONObject json = new JSONObject(content); data = json.getJSONArray("data"); } else { Log.w(TAG, "Error retrieving sensor data: " + response.get(SenseApi.RESPONSE_CODE)); return null; } // fill the result Cursor with sensor data MatrixCursor result = new MatrixCursor(projection, data.length()); for (int i = 0; i < data.length(); i++) { Object[] row = new Object[projection.length]; JSONObject jsonDataPoint = data.getJSONObject(i); for (int j = 0; j < projection.length; j++) { if (projection[j].equals(DataPoint.VALUE)) { row[j] = jsonDataPoint.getString("value"); } else if (projection[j].equals(DataPoint.TIMESTAMP)) { double rawDate = jsonDataPoint.getDouble("date"); row[j] = Math.round(rawDate * 1000d); } else if (projection[j].equals(DataPoint.SENSOR_NAME)) { row[j] = sensorNames.get(0); } } result.addRow(row); } return result; } }