Showing
3 changed files
with
360 additions
and
77 deletions
... | @@ -47,5 +47,9 @@ | ... | @@ -47,5 +47,9 @@ |
47 | <receiver | 47 | <receiver |
48 | android:name=".receivers.LocationChangedReceiver" | 48 | android:name=".receivers.LocationChangedReceiver" |
49 | android:exported="false" /> | 49 | android:exported="false" /> |
50 | + | ||
51 | + <provider | ||
52 | + android:name=".utils.WarplyProvider" | ||
53 | + android:authorities="ly.warp.sdk.utils.WarplyProvider" /> | ||
50 | </application> | 54 | </application> |
51 | </manifest> | 55 | </manifest> |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -26,6 +26,11 @@ import java.io.FileNotFoundException; | ... | @@ -26,6 +26,11 @@ import java.io.FileNotFoundException; |
26 | import java.io.IOException; | 26 | import java.io.IOException; |
27 | import java.util.ArrayList; | 27 | import java.util.ArrayList; |
28 | import java.util.List; | 28 | import java.util.List; |
29 | +import java.util.concurrent.ExecutorService; | ||
30 | +import java.util.concurrent.Executors; | ||
31 | +import java.util.concurrent.Future; | ||
32 | +import java.util.concurrent.TimeUnit; | ||
33 | +import java.util.concurrent.TimeoutException; | ||
29 | 34 | ||
30 | import ly.warp.sdk.utils.constants.WarpConstants; | 35 | import ly.warp.sdk.utils.constants.WarpConstants; |
31 | 36 | ||
... | @@ -40,9 +45,13 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -40,9 +45,13 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
40 | } | 45 | } |
41 | 46 | ||
42 | private static final String DB_NAME = "warply.db"; | 47 | private static final String DB_NAME = "warply.db"; |
43 | - private static final int DB_VERSION = 12; | 48 | + private static final int DB_VERSION = 13; |
44 | private static final String KEY_CIPHER = "tn#mpOl3v3Dy1pr@W"; | 49 | private static final String KEY_CIPHER = "tn#mpOl3v3Dy1pr@W"; |
45 | 50 | ||
51 | + // Timeout constants | ||
52 | + private static final int CONNECTION_TIMEOUT_MS = 5000; // 5 seconds for database connection | ||
53 | + private static final int OPERATION_TIMEOUT_MS = 5000; // 5 seconds for database operations | ||
54 | + | ||
46 | //------------------------------ Fields -----------------------------// | 55 | //------------------------------ Fields -----------------------------// |
47 | private static String TABLE_REQUESTS = "requests"; | 56 | private static String TABLE_REQUESTS = "requests"; |
48 | private static String TABLE_PUSH_REQUESTS = "push_requests"; | 57 | private static String TABLE_PUSH_REQUESTS = "push_requests"; |
... | @@ -119,6 +128,9 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -119,6 +128,9 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
119 | private SQLiteDatabase mDb; | 128 | private SQLiteDatabase mDb; |
120 | private static WarplyDBHelper mDBHelperInstance; | 129 | private static WarplyDBHelper mDBHelperInstance; |
121 | 130 | ||
131 | + // Single-threaded executor for database operations | ||
132 | + private final ExecutorService dbExecutor = Executors.newSingleThreadExecutor(); | ||
133 | + | ||
122 | // =========================================================== | 134 | // =========================================================== |
123 | // Constructors | 135 | // Constructors |
124 | // =========================================================== | 136 | // =========================================================== |
... | @@ -145,21 +157,65 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -145,21 +157,65 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
145 | } | 157 | } |
146 | 158 | ||
147 | /** | 159 | /** |
148 | - * If database connection already initialized, return the db. Else create a | 160 | + * Gets a writable database connection on a background thread with timeout. |
149 | - * new one | 161 | + * This prevents ANR issues by ensuring database operations don't block the main thread. |
150 | */ | 162 | */ |
151 | private SQLiteDatabase getDb() { | 163 | private SQLiteDatabase getDb() { |
152 | - if (mDb == null) | 164 | + if (mDb == null || !mDb.isOpen()) { |
153 | - mDb = getWritableDatabase(KEY_CIPHER); | 165 | + try { |
166 | + // Submit task to executor and get future | ||
167 | + Future<SQLiteDatabase> future = dbExecutor.submit(() -> getWritableDatabase(KEY_CIPHER)); | ||
168 | + | ||
169 | + // Wait for result with timeout | ||
170 | + mDb = future.get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); | ||
171 | + | ||
172 | + // Set busy timeout on the database connection | ||
173 | + if (mDb != null && mDb.isOpen()) { | ||
174 | + mDb.rawExecSQL("PRAGMA busy_timeout = " + CONNECTION_TIMEOUT_MS); | ||
175 | + } | ||
176 | + } catch (TimeoutException e) { | ||
177 | + Log.e("WarplyDBHelper", "Timeout getting writable database connection", e); | ||
178 | + // Return null or handle timeout as appropriate | ||
179 | + } catch (Exception e) { | ||
180 | + Log.e("WarplyDBHelper", "Error getting writable database connection", e); | ||
181 | + // Handle other exceptions | ||
182 | + } | ||
183 | + } | ||
154 | return mDb; | 184 | return mDb; |
155 | } | 185 | } |
156 | 186 | ||
187 | + /** | ||
188 | + * Gets a readable database connection on a background thread with timeout. | ||
189 | + * This prevents ANR issues by ensuring database operations don't block the main thread. | ||
190 | + */ | ||
157 | private SQLiteDatabase getReadableDb() { | 191 | private SQLiteDatabase getReadableDb() { |
158 | - if (mDb == null) | 192 | + if (mDb == null || !mDb.isOpen()) { |
159 | - mDb = getReadableDatabase(KEY_CIPHER); | 193 | + try { |
194 | + // Submit task to executor and get future | ||
195 | + Future<SQLiteDatabase> future = dbExecutor.submit(() -> getReadableDatabase(KEY_CIPHER)); | ||
196 | + | ||
197 | + // Wait for result with timeout | ||
198 | + mDb = future.get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); | ||
199 | + | ||
200 | + // Set busy timeout on the database connection | ||
201 | + if (mDb != null && mDb.isOpen()) { | ||
202 | + mDb.rawExecSQL("PRAGMA busy_timeout = " + CONNECTION_TIMEOUT_MS); | ||
203 | + } | ||
204 | + } catch (TimeoutException e) { | ||
205 | + Log.e("WarplyDBHelper", "Timeout getting readable database connection", e); | ||
206 | + // Return null or handle timeout as appropriate | ||
207 | + } catch (Exception e) { | ||
208 | + Log.e("WarplyDBHelper", "Error getting readable database connection", e); | ||
209 | + // Handle other exceptions | ||
210 | + } | ||
211 | + } | ||
160 | return mDb; | 212 | return mDb; |
161 | } | 213 | } |
162 | 214 | ||
215 | + /** | ||
216 | + * Close database connection - should only be called when app is being destroyed | ||
217 | + * or when database won't be used for a long time | ||
218 | + */ | ||
163 | private void closeDb() { | 219 | private void closeDb() { |
164 | if (mDb != null && mDb.isOpen()) { | 220 | if (mDb != null && mDb.isOpen()) { |
165 | mDb.close(); | 221 | mDb.close(); |
... | @@ -167,8 +223,53 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -167,8 +223,53 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
167 | } | 223 | } |
168 | } | 224 | } |
169 | 225 | ||
226 | + /** | ||
227 | + * Initialize database connection on a background thread. | ||
228 | + * Call this during app startup to prevent ANR issues. | ||
229 | + */ | ||
230 | + public void initialize() { | ||
231 | + if (mDb == null || !mDb.isOpen()) { | ||
232 | + try { | ||
233 | + // Submit task to executor and get future | ||
234 | + Future<SQLiteDatabase> future = dbExecutor.submit(() -> getWritableDatabase(KEY_CIPHER)); | ||
235 | + | ||
236 | + // Wait for result with timeout | ||
237 | + mDb = future.get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); | ||
238 | + | ||
239 | + // Set busy timeout on the database connection | ||
240 | + if (mDb != null && mDb.isOpen()) { | ||
241 | + mDb.rawExecSQL("PRAGMA busy_timeout = " + CONNECTION_TIMEOUT_MS); | ||
242 | + } | ||
243 | + } catch (TimeoutException e) { | ||
244 | + Log.e("WarplyDBHelper", "Timeout initializing database connection", e); | ||
245 | + } catch (Exception e) { | ||
246 | + Log.e("WarplyDBHelper", "Error initializing database connection", e); | ||
247 | + } | ||
248 | + } | ||
249 | + } | ||
250 | + | ||
251 | + /** | ||
252 | + * Shutdown database connection and executor service. | ||
253 | + * Call this when app is being destroyed. | ||
254 | + */ | ||
255 | + public void shutdown() { | ||
256 | + closeDb(); | ||
257 | + | ||
258 | + // Shutdown executor service | ||
259 | + dbExecutor.shutdown(); | ||
260 | + try { | ||
261 | + if (!dbExecutor.awaitTermination(5, TimeUnit.SECONDS)) { | ||
262 | + dbExecutor.shutdownNow(); | ||
263 | + } | ||
264 | + } catch (InterruptedException e) { | ||
265 | + dbExecutor.shutdownNow(); | ||
266 | + Thread.currentThread().interrupt(); | ||
267 | + } | ||
268 | + } | ||
269 | + | ||
170 | @Override | 270 | @Override |
171 | public void onCreate(SQLiteDatabase db) { | 271 | public void onCreate(SQLiteDatabase db) { |
272 | + // Create tables | ||
172 | db.execSQL(CREATE_TABLE_REQUESTS); | 273 | db.execSQL(CREATE_TABLE_REQUESTS); |
173 | db.execSQL(CREATE_TABLE_TAGS); | 274 | db.execSQL(CREATE_TABLE_TAGS); |
174 | db.execSQL(CREATE_TABLE_PUSH_REQUESTS); | 275 | db.execSQL(CREATE_TABLE_PUSH_REQUESTS); |
... | @@ -176,6 +277,14 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -176,6 +277,14 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
176 | db.execSQL(CREATE_TABLE_CLIENT); | 277 | db.execSQL(CREATE_TABLE_CLIENT); |
177 | db.execSQL(CREATE_TABLE_AUTH); | 278 | db.execSQL(CREATE_TABLE_AUTH); |
178 | db.execSQL(CREATE_TABLE_TELEMATICS); | 279 | db.execSQL(CREATE_TABLE_TELEMATICS); |
280 | + | ||
281 | + // Create indexes for frequently queried columns to improve performance | ||
282 | + db.execSQL("CREATE INDEX IF NOT EXISTS idx_requests_force ON " + TABLE_REQUESTS + "(" + KEY_REQUESTS_FORCE + ")"); | ||
283 | + db.execSQL("CREATE INDEX IF NOT EXISTS idx_requests_date ON " + TABLE_REQUESTS + "(" + KEY_REQUESTS_DATE_ADDED + ")"); | ||
284 | + db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_requests_force ON " + TABLE_PUSH_REQUESTS + "(" + KEY_REQUESTS_FORCE + ")"); | ||
285 | + db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_requests_date ON " + TABLE_PUSH_REQUESTS + "(" + KEY_REQUESTS_DATE_ADDED + ")"); | ||
286 | + db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_ack_requests_force ON " + TABLE_PUSH_ACK_REQUESTS + "(" + KEY_REQUESTS_FORCE + ")"); | ||
287 | + db.execSQL("CREATE INDEX IF NOT EXISTS idx_push_ack_requests_date ON " + TABLE_PUSH_ACK_REQUESTS + "(" + KEY_REQUESTS_DATE_ADDED + ")"); | ||
179 | } | 288 | } |
180 | 289 | ||
181 | @Override | 290 | @Override |
... | @@ -228,36 +337,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -228,36 +337,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
228 | public synchronized void clearTable(String tableName) { | 337 | public synchronized void clearTable(String tableName) { |
229 | SQLiteDatabase db = getDb(); | 338 | SQLiteDatabase db = getDb(); |
230 | db.delete(tableName, null, null); | 339 | db.delete(tableName, null, null); |
231 | - | 340 | + // Don't close the database here to improve performance |
232 | - closeDb(); | ||
233 | } | 341 | } |
234 | 342 | ||
235 | public synchronized void insert(String tableName, ContentValues values) { | 343 | public synchronized void insert(String tableName, ContentValues values) { |
236 | SQLiteDatabase db = getDb(); | 344 | SQLiteDatabase db = getDb(); |
237 | db.insert(tableName, null, values); | 345 | db.insert(tableName, null, values); |
238 | - | 346 | + // Don't close the database here to improve performance |
239 | - closeDb(); | ||
240 | } | 347 | } |
241 | 348 | ||
242 | public synchronized void update(String tableName, ContentValues values) { | 349 | public synchronized void update(String tableName, ContentValues values) { |
243 | SQLiteDatabase db = getDb(); | 350 | SQLiteDatabase db = getDb(); |
244 | db.update(tableName, values, null, null); | 351 | db.update(tableName, values, null, null); |
245 | - | 352 | + // Don't close the database here to improve performance |
246 | - closeDb(); | ||
247 | } | 353 | } |
248 | 354 | ||
249 | public synchronized boolean isTableNotEmpty(String tableName) { | 355 | public synchronized boolean isTableNotEmpty(String tableName) { |
250 | - Cursor cursor = getReadableDb().rawQuery("SELECT COUNT(*) FROM " + tableName, | 356 | + boolean isNotEmpty = false; |
251 | - null); | 357 | + Cursor cursor = null; |
358 | + try { | ||
359 | + cursor = getReadableDb().rawQuery("SELECT COUNT(*) FROM " + tableName, null); | ||
252 | if (cursor != null && cursor.moveToFirst()) { | 360 | if (cursor != null && cursor.moveToFirst()) { |
253 | - boolean isNotEmpty = cursor.getInt(0) > 0; | 361 | + isNotEmpty = cursor.getInt(0) > 0; |
362 | + } | ||
363 | + } finally { | ||
364 | + if (cursor != null) { | ||
254 | cursor.close(); | 365 | cursor.close(); |
255 | - closeDb(); | ||
256 | - return isNotEmpty; | ||
257 | - } else { | ||
258 | - closeDb(); | ||
259 | - return false; | ||
260 | } | 366 | } |
367 | + // Don't close the database here to improve performance | ||
368 | + } | ||
369 | + return isNotEmpty; | ||
261 | } | 370 | } |
262 | 371 | ||
263 | //------------------------------ Auth -----------------------------// | 372 | //------------------------------ Auth -----------------------------// |
... | @@ -288,30 +397,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -288,30 +397,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
288 | @Nullable | 397 | @Nullable |
289 | public synchronized String getAuthValue(String columnName) { | 398 | public synchronized String getAuthValue(String columnName) { |
290 | String columnValue = ""; | 399 | String columnValue = ""; |
291 | - Cursor cursor = getReadableDb().query(TABLE_AUTH, new String[]{columnName}, null, null, null, null, null); | 400 | + Cursor cursor = null; |
401 | + try { | ||
402 | + cursor = getReadableDb().query(TABLE_AUTH, new String[]{columnName}, null, null, null, null, null); | ||
292 | if (cursor != null && cursor.moveToFirst()) { | 403 | if (cursor != null && cursor.moveToFirst()) { |
293 | - cursor.moveToFirst(); | ||
294 | columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 404 | columnValue = cursor.getString(cursor.getColumnIndex(columnName)); |
405 | + } | ||
406 | + } finally { | ||
407 | + if (cursor != null) { | ||
295 | cursor.close(); | 408 | cursor.close(); |
296 | } | 409 | } |
297 | - | 410 | + // Don't close the database here to improve performance |
298 | - closeDb(); | 411 | + } |
299 | - | ||
300 | return columnValue; | 412 | return columnValue; |
301 | } | 413 | } |
302 | 414 | ||
303 | @Nullable | 415 | @Nullable |
304 | public synchronized String getClientValue(String columnName) { | 416 | public synchronized String getClientValue(String columnName) { |
305 | String columnValue = ""; | 417 | String columnValue = ""; |
306 | - Cursor cursor = getReadableDb().query(TABLE_CLIENT, new String[]{columnName}, null, null, null, null, null); | 418 | + Cursor cursor = null; |
419 | + try { | ||
420 | + cursor = getReadableDb().query(TABLE_CLIENT, new String[]{columnName}, null, null, null, null, null); | ||
307 | if (cursor != null && cursor.moveToFirst()) { | 421 | if (cursor != null && cursor.moveToFirst()) { |
308 | - cursor.moveToFirst(); | ||
309 | columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 422 | columnValue = cursor.getString(cursor.getColumnIndex(columnName)); |
423 | + } | ||
424 | + } finally { | ||
425 | + if (cursor != null) { | ||
310 | cursor.close(); | 426 | cursor.close(); |
311 | } | 427 | } |
312 | - | 428 | + // Don't close the database here to improve performance |
313 | - closeDb(); | 429 | + } |
314 | - | ||
315 | return columnValue; | 430 | return columnValue; |
316 | } | 431 | } |
317 | 432 | ||
... | @@ -324,21 +439,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -324,21 +439,36 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
324 | } | 439 | } |
325 | 440 | ||
326 | //------------------------------ Api requests -----------------------------// | 441 | //------------------------------ Api requests -----------------------------// |
442 | + /** | ||
443 | + * Gets all requests from the database. | ||
444 | + * NOTE: The caller is responsible for closing the returned Cursor when done with it. | ||
445 | + */ | ||
327 | public synchronized Cursor getAllRequests() { | 446 | public synchronized Cursor getAllRequests() { |
447 | + // We don't close the database here because the cursor needs it to remain open | ||
328 | return getReadableDb().query(TABLE_REQUESTS, | 448 | return getReadableDb().query(TABLE_REQUESTS, |
329 | new String[]{KEY_REQUESTS_ID, | 449 | new String[]{KEY_REQUESTS_ID, |
330 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 450 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, |
331 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 451 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); |
332 | } | 452 | } |
333 | 453 | ||
454 | + /** | ||
455 | + * Gets all push requests from the database. | ||
456 | + * NOTE: The caller is responsible for closing the returned Cursor when done with it. | ||
457 | + */ | ||
334 | public synchronized Cursor getAllPushRequests() { | 458 | public synchronized Cursor getAllPushRequests() { |
459 | + // We don't close the database here because the cursor needs it to remain open | ||
335 | return getReadableDb().query(TABLE_PUSH_REQUESTS, | 460 | return getReadableDb().query(TABLE_PUSH_REQUESTS, |
336 | new String[]{KEY_REQUESTS_ID, | 461 | new String[]{KEY_REQUESTS_ID, |
337 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 462 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, |
338 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); | 463 | KEY_REQUESTS_DATE_ADDED + " asc", "20"); |
339 | } | 464 | } |
340 | 465 | ||
466 | + /** | ||
467 | + * Gets all push acknowledgment requests from the database. | ||
468 | + * NOTE: The caller is responsible for closing the returned Cursor when done with it. | ||
469 | + */ | ||
341 | public synchronized Cursor getAllPushAckRequests() { | 470 | public synchronized Cursor getAllPushAckRequests() { |
471 | + // We don't close the database here because the cursor needs it to remain open | ||
342 | return getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, | 472 | return getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, |
343 | new String[]{KEY_REQUESTS_ID, | 473 | new String[]{KEY_REQUESTS_ID, |
344 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, | 474 | KEY_REQUESTS_MICROAPP, KEY_REQUESTS_ENTITY}, null, null, null, null, |
... | @@ -388,18 +518,32 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -388,18 +518,32 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
388 | } | 518 | } |
389 | 519 | ||
390 | public synchronized long getRequestsInQueueCount() { | 520 | public synchronized long getRequestsInQueueCount() { |
391 | - return DatabaseUtils.queryNumEntries(getReadableDb(), TABLE_REQUESTS); | 521 | + SQLiteDatabase db = getReadableDb(); |
522 | + long count = DatabaseUtils.queryNumEntries(db, TABLE_REQUESTS); | ||
523 | + // Don't close the database here to improve performance | ||
524 | + return count; | ||
392 | } | 525 | } |
393 | 526 | ||
394 | public synchronized long getPushRequestsInQueueCount() { | 527 | public synchronized long getPushRequestsInQueueCount() { |
395 | - return DatabaseUtils.queryNumEntries(getReadableDb(), TABLE_PUSH_REQUESTS); | 528 | + SQLiteDatabase db = getReadableDb(); |
529 | + long count = DatabaseUtils.queryNumEntries(db, TABLE_PUSH_REQUESTS); | ||
530 | + // Don't close the database here to improve performance | ||
531 | + return count; | ||
396 | } | 532 | } |
397 | 533 | ||
398 | public synchronized long getPushAckRequestsInQueueCount() { | 534 | public synchronized long getPushAckRequestsInQueueCount() { |
399 | - return DatabaseUtils.queryNumEntries(getReadableDb(), TABLE_PUSH_ACK_REQUESTS); | 535 | + SQLiteDatabase db = getReadableDb(); |
536 | + long count = DatabaseUtils.queryNumEntries(db, TABLE_PUSH_ACK_REQUESTS); | ||
537 | + // Don't close the database here to improve performance | ||
538 | + return count; | ||
400 | } | 539 | } |
401 | 540 | ||
402 | public synchronized void deleteRequests(Long... ids) { | 541 | public synchronized void deleteRequests(Long... ids) { |
542 | + if (ids.length == 0) return; | ||
543 | + | ||
544 | + SQLiteDatabase db = getDb(); | ||
545 | + try { | ||
546 | + db.beginTransaction(); | ||
403 | StringBuilder strFilter = new StringBuilder(); | 547 | StringBuilder strFilter = new StringBuilder(); |
404 | for (int i = 0; i < ids.length; i++) { | 548 | for (int i = 0; i < ids.length; i++) { |
405 | if (i > 0) { | 549 | if (i > 0) { |
... | @@ -409,12 +553,20 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -409,12 +553,20 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
409 | strFilter.append("="); | 553 | strFilter.append("="); |
410 | strFilter.append(ids[i]); | 554 | strFilter.append(ids[i]); |
411 | } | 555 | } |
412 | - getDb().delete(TABLE_REQUESTS, strFilter.toString(), null); | 556 | + db.delete(TABLE_REQUESTS, strFilter.toString(), null); |
413 | - | 557 | + db.setTransactionSuccessful(); |
414 | - closeDb(); | 558 | + } finally { |
559 | + db.endTransaction(); | ||
560 | + // Don't close the database here to improve performance | ||
561 | + } | ||
415 | } | 562 | } |
416 | 563 | ||
417 | public synchronized void deletePushRequests(Long... ids) { | 564 | public synchronized void deletePushRequests(Long... ids) { |
565 | + if (ids.length == 0) return; | ||
566 | + | ||
567 | + SQLiteDatabase db = getDb(); | ||
568 | + try { | ||
569 | + db.beginTransaction(); | ||
418 | StringBuilder strFilter = new StringBuilder(); | 570 | StringBuilder strFilter = new StringBuilder(); |
419 | for (int i = 0; i < ids.length; i++) { | 571 | for (int i = 0; i < ids.length; i++) { |
420 | if (i > 0) { | 572 | if (i > 0) { |
... | @@ -424,12 +576,20 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -424,12 +576,20 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
424 | strFilter.append("="); | 576 | strFilter.append("="); |
425 | strFilter.append(ids[i]); | 577 | strFilter.append(ids[i]); |
426 | } | 578 | } |
427 | - getDb().delete(TABLE_PUSH_REQUESTS, strFilter.toString(), null); | 579 | + db.delete(TABLE_PUSH_REQUESTS, strFilter.toString(), null); |
428 | - | 580 | + db.setTransactionSuccessful(); |
429 | - closeDb(); | 581 | + } finally { |
582 | + db.endTransaction(); | ||
583 | + // Don't close the database here to improve performance | ||
584 | + } | ||
430 | } | 585 | } |
431 | 586 | ||
432 | public synchronized void deletePushAckRequests(Long... ids) { | 587 | public synchronized void deletePushAckRequests(Long... ids) { |
588 | + if (ids.length == 0) return; | ||
589 | + | ||
590 | + SQLiteDatabase db = getDb(); | ||
591 | + try { | ||
592 | + db.beginTransaction(); | ||
433 | StringBuilder strFilter = new StringBuilder(); | 593 | StringBuilder strFilter = new StringBuilder(); |
434 | for (int i = 0; i < ids.length; i++) { | 594 | for (int i = 0; i < ids.length; i++) { |
435 | if (i > 0) { | 595 | if (i > 0) { |
... | @@ -439,85 +599,103 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -439,85 +599,103 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
439 | strFilter.append("="); | 599 | strFilter.append("="); |
440 | strFilter.append(ids[i]); | 600 | strFilter.append(ids[i]); |
441 | } | 601 | } |
442 | - getDb().delete(TABLE_PUSH_ACK_REQUESTS, strFilter.toString(), null); | 602 | + db.delete(TABLE_PUSH_ACK_REQUESTS, strFilter.toString(), null); |
443 | - | 603 | + db.setTransactionSuccessful(); |
444 | - closeDb(); | 604 | + } finally { |
605 | + db.endTransaction(); | ||
606 | + // Don't close the database here to improve performance | ||
607 | + } | ||
445 | } | 608 | } |
446 | 609 | ||
447 | public synchronized boolean isForceRequestsExist() { | 610 | public synchronized boolean isForceRequestsExist() { |
448 | - Cursor cursor = getReadableDb().query(TABLE_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
449 | - null, null, null, null); | ||
450 | boolean result = false; | 611 | boolean result = false; |
612 | + Cursor cursor = null; | ||
613 | + try { | ||
614 | + cursor = getReadableDb().query(TABLE_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
615 | + null, null, null, null); | ||
451 | if (cursor != null) { | 616 | if (cursor != null) { |
452 | result = cursor.getCount() > 0; | 617 | result = cursor.getCount() > 0; |
618 | + } | ||
619 | + } finally { | ||
620 | + if (cursor != null) { | ||
453 | cursor.close(); | 621 | cursor.close(); |
454 | } | 622 | } |
455 | - | 623 | + // Don't close the database here to improve performance |
456 | - closeDb(); | 624 | + } |
457 | - | ||
458 | return result; | 625 | return result; |
459 | } | 626 | } |
460 | 627 | ||
461 | public synchronized boolean isForcePushRequestsExist() { | 628 | public synchronized boolean isForcePushRequestsExist() { |
462 | - Cursor cursor = getReadableDb().query(TABLE_PUSH_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
463 | - null, null, null, null); | ||
464 | boolean result = false; | 629 | boolean result = false; |
630 | + Cursor cursor = null; | ||
631 | + try { | ||
632 | + cursor = getReadableDb().query(TABLE_PUSH_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
633 | + null, null, null, null); | ||
465 | if (cursor != null) { | 634 | if (cursor != null) { |
466 | result = cursor.getCount() > 0; | 635 | result = cursor.getCount() > 0; |
636 | + } | ||
637 | + } finally { | ||
638 | + if (cursor != null) { | ||
467 | cursor.close(); | 639 | cursor.close(); |
468 | } | 640 | } |
469 | - | 641 | + // Don't close the database here to improve performance |
470 | - closeDb(); | 642 | + } |
471 | - | ||
472 | return result; | 643 | return result; |
473 | } | 644 | } |
474 | 645 | ||
475 | public synchronized boolean isForcePushAckRequestsExist() { | 646 | public synchronized boolean isForcePushAckRequestsExist() { |
476 | - Cursor cursor = getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
477 | - null, null, null, null); | ||
478 | boolean result = false; | 647 | boolean result = false; |
648 | + Cursor cursor = null; | ||
649 | + try { | ||
650 | + cursor = getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | ||
651 | + null, null, null, null); | ||
479 | if (cursor != null) { | 652 | if (cursor != null) { |
480 | result = cursor.getCount() > 0; | 653 | result = cursor.getCount() > 0; |
654 | + } | ||
655 | + } finally { | ||
656 | + if (cursor != null) { | ||
481 | cursor.close(); | 657 | cursor.close(); |
482 | } | 658 | } |
483 | - | 659 | + // Don't close the database here to improve performance |
484 | - closeDb(); | 660 | + } |
485 | - | ||
486 | return result; | 661 | return result; |
487 | } | 662 | } |
488 | 663 | ||
489 | //------------------------------ Tags -----------------------------// | 664 | //------------------------------ Tags -----------------------------// |
490 | public synchronized void saveTags(String[] tags) { | 665 | public synchronized void saveTags(String[] tags) { |
491 | if (tags != null && tags.length > 0) { | 666 | if (tags != null && tags.length > 0) { |
667 | + SQLiteDatabase db = getDb(); | ||
492 | try { | 668 | try { |
493 | - getDb().beginTransaction(); | 669 | + db.beginTransaction(); |
494 | ContentValues values = new ContentValues(); | 670 | ContentValues values = new ContentValues(); |
495 | for (String tag : tags) { | 671 | for (String tag : tags) { |
672 | + values.clear(); | ||
496 | values.put(KEY_TAG, tag); | 673 | values.put(KEY_TAG, tag); |
497 | values.put(KEY_TAG_LAST_ADD_DATE, System.currentTimeMillis()); | 674 | values.put(KEY_TAG_LAST_ADD_DATE, System.currentTimeMillis()); |
498 | - insert(TABLE_TAGS, values); | 675 | + db.insert(TABLE_TAGS, null, values); |
499 | } | 676 | } |
500 | - getDb().setTransactionSuccessful(); | 677 | + db.setTransactionSuccessful(); |
501 | - | ||
502 | } catch (SQLException e) { | 678 | } catch (SQLException e) { |
503 | - closeDb(); | ||
504 | if (WarpConstants.DEBUG) { | 679 | if (WarpConstants.DEBUG) { |
505 | e.printStackTrace(); | 680 | e.printStackTrace(); |
506 | } | 681 | } |
507 | } finally { | 682 | } finally { |
508 | - getDb().endTransaction(); | 683 | + db.endTransaction(); |
509 | - | 684 | + // Don't close the database here to improve performance |
510 | - closeDb(); | ||
511 | } | 685 | } |
512 | } | 686 | } |
513 | } | 687 | } |
514 | 688 | ||
515 | public synchronized void saveTelematics(JSONArray jsonArray) { | 689 | public synchronized void saveTelematics(JSONArray jsonArray) { |
516 | if (jsonArray != null && jsonArray.length() > 0) { | 690 | if (jsonArray != null && jsonArray.length() > 0) { |
691 | + SQLiteDatabase db = getDb(); | ||
692 | + try { | ||
693 | + db.beginTransaction(); | ||
517 | ContentValues values = new ContentValues(); | 694 | ContentValues values = new ContentValues(); |
518 | for (int i = 0; i < jsonArray.length(); i++) { | 695 | for (int i = 0; i < jsonArray.length(); i++) { |
519 | JSONObject jsonobject = jsonArray.optJSONObject(i); | 696 | JSONObject jsonobject = jsonArray.optJSONObject(i); |
520 | if (jsonobject != null) { | 697 | if (jsonobject != null) { |
698 | + values.clear(); | ||
521 | String timestamp = jsonobject.keys().next(); | 699 | String timestamp = jsonobject.keys().next(); |
522 | values.put(KEY_TIMESTAMP, timestamp); | 700 | values.put(KEY_TIMESTAMP, timestamp); |
523 | JSONObject jobjData = jsonobject.optJSONObject(timestamp); | 701 | JSONObject jobjData = jsonobject.optJSONObject(timestamp); |
... | @@ -525,13 +703,23 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -525,13 +703,23 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
525 | values.put(KEY_ACCELERATION, jobjData.optDouble(KEY_ACCELERATION)); | 703 | values.put(KEY_ACCELERATION, jobjData.optDouble(KEY_ACCELERATION)); |
526 | values.put(KEY_SPEED, jobjData.optDouble(KEY_SPEED)); | 704 | values.put(KEY_SPEED, jobjData.optDouble(KEY_SPEED)); |
527 | } | 705 | } |
528 | - insert(TABLE_TELEMATICS, values); | 706 | + db.insert(TABLE_TELEMATICS, null, values); |
707 | + } | ||
529 | } | 708 | } |
709 | + db.setTransactionSuccessful(); | ||
710 | + } finally { | ||
711 | + db.endTransaction(); | ||
712 | + // Don't close the database here to improve performance | ||
530 | } | 713 | } |
531 | } | 714 | } |
532 | } | 715 | } |
533 | 716 | ||
534 | public synchronized void removeTags(String[] tags) { | 717 | public synchronized void removeTags(String[] tags) { |
718 | + if (tags.length == 0) return; | ||
719 | + | ||
720 | + SQLiteDatabase db = getDb(); | ||
721 | + try { | ||
722 | + db.beginTransaction(); | ||
535 | StringBuilder strFilter = new StringBuilder(); | 723 | StringBuilder strFilter = new StringBuilder(); |
536 | for (int i = 0; i < tags.length; i++) { | 724 | for (int i = 0; i < tags.length; i++) { |
537 | if (i > 0) { | 725 | if (i > 0) { |
... | @@ -543,8 +731,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -543,8 +731,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
543 | strFilter.append(tags[i]); | 731 | strFilter.append(tags[i]); |
544 | strFilter.append("'"); | 732 | strFilter.append("'"); |
545 | } | 733 | } |
546 | - getDb().delete(TABLE_TAGS, strFilter.toString(), null); | 734 | + db.delete(TABLE_TAGS, strFilter.toString(), null); |
547 | - closeDb(); | 735 | + db.setTransactionSuccessful(); |
736 | + } finally { | ||
737 | + db.endTransaction(); | ||
738 | + // Don't close the database here to improve performance | ||
739 | + } | ||
548 | } | 740 | } |
549 | 741 | ||
550 | public synchronized void removeAllTags() { | 742 | public synchronized void removeAllTags() { |
... | @@ -553,21 +745,22 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -553,21 +745,22 @@ public class WarplyDBHelper extends SQLiteOpenHelper { |
553 | 745 | ||
554 | @Nullable | 746 | @Nullable |
555 | public synchronized String[] getTags() { | 747 | public synchronized String[] getTags() { |
556 | - | ||
557 | List<String> tags = null; | 748 | List<String> tags = null; |
558 | - Cursor cursor = getReadableDb().query(TABLE_TAGS, null, null, null, null, null, null); | 749 | + Cursor cursor = null; |
750 | + try { | ||
751 | + cursor = getReadableDb().query(TABLE_TAGS, null, null, null, null, null, null); | ||
559 | if (cursor != null) { | 752 | if (cursor != null) { |
560 | - | ||
561 | tags = new ArrayList<>(cursor.getCount()); | 753 | tags = new ArrayList<>(cursor.getCount()); |
562 | while (cursor.moveToNext()) { | 754 | while (cursor.moveToNext()) { |
563 | - tags.add(cursor.getString(cursor | 755 | + tags.add(cursor.getString(cursor.getColumnIndex(KEY_TAG))); |
564 | - .getColumnIndex(KEY_TAG))); | 756 | + } |
565 | } | 757 | } |
758 | + } finally { | ||
759 | + if (cursor != null) { | ||
566 | cursor.close(); | 760 | cursor.close(); |
567 | } | 761 | } |
568 | - | 762 | + // Don't close the database here to improve performance |
569 | - closeDb(); | 763 | + } |
570 | - | ||
571 | return tags != null ? tags.toArray(new String[tags.size()]) : null; | 764 | return tags != null ? tags.toArray(new String[tags.size()]) : null; |
572 | } | 765 | } |
573 | 766 | ... | ... |
1 | +package ly.warp.sdk.utils; | ||
2 | + | ||
3 | +import android.content.ContentProvider; | ||
4 | +import android.content.ContentValues; | ||
5 | +import android.content.Context; | ||
6 | +import android.database.Cursor; | ||
7 | +import android.net.Uri; | ||
8 | + | ||
9 | +import androidx.annotation.NonNull; | ||
10 | +import androidx.annotation.Nullable; | ||
11 | +import androidx.appcompat.app.AppCompatDelegate; | ||
12 | + | ||
13 | +import ly.warp.sdk.db.WarplyDBHelper; | ||
14 | + | ||
15 | +/** | ||
16 | + * Created by Panagiotis Triantafyllou on 05/Αυγ/2022. | ||
17 | + */ | ||
18 | +public class WarplyProvider extends ContentProvider { | ||
19 | + | ||
20 | + @Override | ||
21 | + public boolean onCreate() { | ||
22 | +// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); | ||
23 | + | ||
24 | + // Initialize the database helper | ||
25 | + Context context = getContext(); | ||
26 | + if (context != null) { | ||
27 | + WarplyDBHelper dbHelper = WarplyDBHelper.getInstance(context); | ||
28 | + dbHelper.initialize(); // This will initialize the database connection on a background thread | ||
29 | + } | ||
30 | +// ViewPump.init(ViewPump.builder() | ||
31 | +// .addInterceptor(new CalligraphyInterceptor( | ||
32 | +// new CalligraphyConfig.Builder() | ||
33 | +// .setDefaultFontPath("fonts/pf_square_sans_pro_regular.ttf") | ||
34 | +// .setFontAttrId(R.attr.fontPath) | ||
35 | +//// .setFontMapper(new FontMapper() { | ||
36 | +//// @Override | ||
37 | +//// public String map(String font) { | ||
38 | +//// return font; | ||
39 | +//// } | ||
40 | +//// }) | ||
41 | +// .build())) | ||
42 | +// .build()); | ||
43 | + | ||
44 | + return true; | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public void shutdown() { | ||
49 | + // Get the database helper instance and shut it down | ||
50 | + Context context = getContext(); | ||
51 | + if (context != null) { | ||
52 | + WarplyDBHelper dbHelper = WarplyDBHelper.getInstance(context); | ||
53 | + dbHelper.shutdown(); | ||
54 | + } | ||
55 | + | ||
56 | + super.shutdown(); | ||
57 | + } | ||
58 | + | ||
59 | + @Nullable | ||
60 | + @Override | ||
61 | + public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { | ||
62 | + return null; | ||
63 | + } | ||
64 | + | ||
65 | + @Nullable | ||
66 | + @Override | ||
67 | + public String getType(@NonNull Uri uri) { | ||
68 | + return null; | ||
69 | + } | ||
70 | + | ||
71 | + @Nullable | ||
72 | + @Override | ||
73 | + public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) { | ||
74 | + return null; | ||
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) { | ||
79 | + return 0; | ||
80 | + } | ||
81 | + | ||
82 | + @Override | ||
83 | + public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) { | ||
84 | + return 0; | ||
85 | + } | ||
86 | +} |
-
Please register or login to post a comment