Panagiotis Triantafyllou

db fixes

...@@ -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 +}