Context-detection API for Android developed as a university project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DataHelper.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * Copyright (c) 2009-2010 Chris Smith
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package uk.co.md87.android.contextanalyser;
  23. import android.content.Context;
  24. import android.database.Cursor;
  25. import android.database.sqlite.SQLiteDatabase;
  26. import android.database.sqlite.SQLiteOpenHelper;
  27. import android.database.sqlite.SQLiteStatement;
  28. import android.location.Location;
  29. import android.util.Log;
  30. import java.util.Collection;
  31. import java.util.HashMap;
  32. import java.util.LinkedList;
  33. import java.util.List;
  34. import java.util.Map;
  35. import uk.co.md87.android.contextanalyser.model.Journey;
  36. import uk.co.md87.android.contextanalyser.model.JourneyStep;
  37. import uk.co.md87.android.contextanalyser.model.Place;
  38. /**
  39. * Facilitates accessing the SQLite database used for storing places and
  40. * journeys.
  41. *
  42. * @author chris
  43. */
  44. public class DataHelper {
  45. public static final String LOCATIONS_TABLE = "locations";
  46. public static final String JOURNEYS_TABLE = "journeys";
  47. public static final String JOURNEYSTEPS_TABLE = "journeysteps";
  48. private static final String DATABASE_NAME = "contextapi.db";
  49. private static final int DATABASE_VERSION = 6;
  50. private static final String INSERT_LOCATION = "insert into "
  51. + LOCATIONS_TABLE + "(name, lat, lon) values (?, ?, ?)";
  52. private static final String INSERT_JOURNEY = "insert into "
  53. + JOURNEYS_TABLE + "(start, end, steps, number) values (?, ?, ?, 1)";
  54. private static final String INSERT_JOURNEYSTEP = "insert into "
  55. + JOURNEYSTEPS_TABLE + "(activity, repetitions, journey, next) values (?, ?, ?, ?)";
  56. private static final String UPDATE_LOCATION = "update "
  57. + LOCATIONS_TABLE + " set name = ? where _id = ?";
  58. private static final String UPDATE_JOURNEY = "update "
  59. + JOURNEYS_TABLE + " set number = number + 1 WHERE _id = ?";
  60. private static final String UNNAMED_QUERY = "name LIKE '%.%,%.%'";
  61. private static final String LOCATION_QUERY = "lat > %1$s - 0.005 and "
  62. + "lat < %1$s + 0.005 and lon > %2$s - 0.01 and lon < %2$s + 0.01";
  63. private static final String JOURNEY_STEPS_QUERY = "journey = %1$s";
  64. private static final String JOURNEY_START_QUERY = "start = %1$s";
  65. private static final String JOURNEY_BOTH_QUERY = JOURNEY_START_QUERY + " AND end = %1$s";
  66. private final SQLiteStatement insertLocationStatement, insertJourneyStatement,
  67. insertJourneyStepStatement, updateLocationStatement,
  68. updateJourneyStatement;
  69. private SQLiteDatabase db;
  70. public DataHelper(final Context context) {
  71. final OpenHelper helper = new OpenHelper(context);
  72. this.db = helper.getWritableDatabase();
  73. this.insertLocationStatement = db.compileStatement(INSERT_LOCATION);
  74. this.updateLocationStatement = db.compileStatement(UPDATE_LOCATION);
  75. this.insertJourneyStatement = db.compileStatement(INSERT_JOURNEY);
  76. this.insertJourneyStepStatement = db.compileStatement(INSERT_JOURNEYSTEP);
  77. this.updateJourneyStatement = db.compileStatement(UPDATE_JOURNEY);
  78. }
  79. public SQLiteDatabase getDatabase() {
  80. return db;
  81. }
  82. public long addLocation(final String name, final double lat, final double lon) {
  83. Log.i(getClass().getSimpleName(), "Adding new place at " + lat + ", " + lon);
  84. insertLocationStatement.bindString(1, name);
  85. insertLocationStatement.bindDouble(2, lat);
  86. insertLocationStatement.bindDouble(3, lon);
  87. return insertLocationStatement.executeInsert();
  88. }
  89. public void updateLocation(final long id, final String name) {
  90. Log.i(getClass().getSimpleName(), "Setting name of place " + id + " to " + name);
  91. updateLocationStatement.bindString(1, name);
  92. updateLocationStatement.bindLong(2, id);
  93. updateLocationStatement.execute();
  94. }
  95. public Map<String, Long> getUnnamedLocations() {
  96. final Map<String, Long> results = new HashMap<String, Long>();
  97. final Cursor cursor = db.query(LOCATIONS_TABLE,
  98. new String[] { Place._ID, Place.NAME },
  99. UNNAMED_QUERY, null, null, null, null);
  100. if (cursor.moveToFirst()) {
  101. do {
  102. results.put(cursor.getString(1), cursor.getLong(0));
  103. } while (cursor.moveToNext());
  104. }
  105. closeCursor(cursor);
  106. return results;
  107. }
  108. public Collection<Journey> findJourneys(final Place start) {
  109. return findJourneys(start, null);
  110. }
  111. public Collection<Journey> findJourneys(final Place start,
  112. final Place end) {
  113. final Collection<Journey> results = new LinkedList<Journey>();
  114. final String query;
  115. if (end == null) {
  116. query = String.format(JOURNEY_START_QUERY, start.getId());
  117. } else {
  118. query = String.format(JOURNEY_BOTH_QUERY, start.getId(), end.getId());
  119. }
  120. final Cursor cursor = db.query(JOURNEYS_TABLE,
  121. new String[] { "_id", "start", "end", "steps", "number" },
  122. query, null, null, null, null);
  123. if (cursor.moveToFirst()) {
  124. do {
  125. results.add(new Journey(cursor.getLong(0), cursor.getLong(1),
  126. cursor.getLong(2), cursor.getInt(3), cursor.getInt(4)));
  127. } while (cursor.moveToNext());
  128. }
  129. closeCursor(cursor);
  130. return results;
  131. }
  132. public void addJourney(final Place start, final Place end, final List<String> activities) {
  133. final List<JourneyStep> steps = getSteps(activities);
  134. final Collection<Journey> journeys = findJourneys(start, end);
  135. for (Journey journey : journeys) {
  136. if (journey.getSteps() == steps.size()) {
  137. final List<JourneyStep> theirSteps = getSteps(journey);
  138. if (theirSteps.equals(steps)) {
  139. updateJourneyStatement.bindLong(1, journey.getId());
  140. updateJourneyStatement.execute();
  141. return;
  142. }
  143. }
  144. }
  145. insertJourneyStatement.bindLong(1, start.getId());
  146. insertJourneyStatement.bindLong(2, end.getId());
  147. insertJourneyStatement.bindLong(3, steps.size());
  148. final long id = insertJourneyStatement.executeInsert();
  149. long next = 0;
  150. for (int i = steps.size() - 1; i >= 0; i--) {
  151. final JourneyStep step = steps.get(i);
  152. insertJourneyStepStatement.bindString(1, step.getActivity());
  153. insertJourneyStepStatement.bindLong(2, step.getRepetitions());
  154. insertJourneyStepStatement.bindLong(3, id);
  155. insertJourneyStepStatement.bindLong(4, next);
  156. next = insertJourneyStepStatement.executeInsert();
  157. }
  158. }
  159. protected static List<JourneyStep> getSteps(final List<String> activities) {
  160. final List<JourneyStep> steps = new LinkedList<JourneyStep>();
  161. String last = null;
  162. int count = 0;
  163. for (String activity : activities) {
  164. if (activity.equals(last)) {
  165. count++;
  166. } else {
  167. if (last != null) {
  168. steps.add(new JourneyStep(last, count));
  169. }
  170. count = 1;
  171. last = activity;
  172. }
  173. }
  174. steps.add(new JourneyStep(last, count));
  175. return steps;
  176. }
  177. public List<JourneyStep> getSteps(final Journey journey) {
  178. final Map<Long, JourneyStep> results
  179. = new HashMap<Long, JourneyStep>(journey.getSteps());
  180. final String query = String.format(JOURNEY_STEPS_QUERY, journey.getId());
  181. final Cursor cursor = db.query(JOURNEYSTEPS_TABLE,
  182. new String[] { "_id", "activity", "repetitions", "next" },
  183. query, null, null, null, null);
  184. if (cursor.moveToFirst()) {
  185. do {
  186. results.put(cursor.getLong(3),
  187. new JourneyStep(cursor.getLong(0), cursor.getString(1),
  188. cursor.getInt(2), journey.getId(), cursor.getLong(3)));
  189. } while (cursor.moveToNext());
  190. }
  191. closeCursor(cursor);
  192. final List<JourneyStep> ordered = new LinkedList<JourneyStep>();
  193. long previous = 0;
  194. while (results.containsKey(previous)) {
  195. final JourneyStep step = results.get(previous);
  196. ordered.add(step);
  197. previous = step.getId();
  198. }
  199. return ordered;
  200. }
  201. public Place findLocation(final double lat, final double lon) {
  202. final Cursor cursor = db.query(LOCATIONS_TABLE,
  203. new String[] { Place._ID, Place.NAME, Place.LATITUDE, Place.LONGITUDE },
  204. String.format(LOCATION_QUERY, lat, lon), null, null, null, null);
  205. if (cursor.moveToFirst()) {
  206. do {
  207. final float[] res = new float[1];
  208. Location.distanceBetween(lat, lon, cursor.getDouble(2), cursor.getDouble(3), res);
  209. if (res[0] <= 500) {
  210. final Place place = new Place(cursor.getLong(0), cursor.getString(1),
  211. cursor.getDouble(2), cursor.getDouble(3));
  212. closeCursor(cursor);
  213. return place;
  214. }
  215. } while (cursor.moveToNext());
  216. }
  217. closeCursor(cursor);
  218. return null;
  219. }
  220. private static void closeCursor(final Cursor cursor) {
  221. if (cursor != null && !cursor.isClosed()) {
  222. cursor.close();
  223. }
  224. }
  225. private static class OpenHelper extends SQLiteOpenHelper {
  226. public OpenHelper(final Context context) {
  227. super(context, DATABASE_NAME, null, DATABASE_VERSION);
  228. }
  229. /** {@inheritDoc} */
  230. @Override
  231. public void onCreate(final SQLiteDatabase db) {
  232. db.execSQL("CREATE TABLE " + LOCATIONS_TABLE
  233. + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, lon REAL, lat REAL)");
  234. db.execSQL("CREATE TABLE " + JOURNEYS_TABLE
  235. + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, start INTEGER,"
  236. + " end INTEGER, steps INTEGER)");
  237. db.execSQL("CREATE TABLE " + JOURNEYSTEPS_TABLE
  238. + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, activity TEXT,"
  239. + " repetitions INTEGER, journey INTEGER, next INTEGER)");
  240. }
  241. /** {@inheritDoc} */
  242. @Override
  243. public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
  244. final int newVersion) {
  245. Log.i(getClass().getSimpleName(), "Upgrading DB " + oldVersion + "->" + newVersion);
  246. if (oldVersion <= 2) {
  247. db.execSQL("DROP TABLE " + LOCATIONS_TABLE);
  248. onCreate(db);
  249. } else if (oldVersion <= 6) {
  250. db.execSQL("DROP TABLE " + LOCATIONS_TABLE);
  251. db.execSQL("DROP TABLE " + JOURNEYS_TABLE);
  252. db.execSQL("DROP TABLE " + JOURNEYSTEPS_TABLE);
  253. onCreate(db);
  254. }
  255. }
  256. }
  257. }