Showing
4 changed files
with
361 additions
and
146 deletions
| ... | @@ -5,7 +5,7 @@ android.buildFeatures.buildConfig = true | ... | @@ -5,7 +5,7 @@ android.buildFeatures.buildConfig = true | 
| 5 | 5 | ||
| 6 | ext { | 6 | ext { | 
| 7 | PUBLISH_GROUP_ID = 'ly.warp' | 7 | PUBLISH_GROUP_ID = 'ly.warp' | 
| 8 | - PUBLISH_VERSION = '4.5.5.4p10' | 8 | + PUBLISH_VERSION = '4.5.5.4p11' | 
| 9 | PUBLISH_ARTIFACT_ID = 'warply-android-sdk' | 9 | PUBLISH_ARTIFACT_ID = 'warply-android-sdk' | 
| 10 | } | 10 | } | 
| 11 | 11 | ||
| ... | @@ -107,9 +107,9 @@ dependencies { | ... | @@ -107,9 +107,9 @@ dependencies { | 
| 107 | implementation 'com.huawei.hms:maps-basic:6.9.0.300' | 107 | implementation 'com.huawei.hms:maps-basic:6.9.0.300' | 
| 108 | 108 | ||
| 109 | //------------------------------ SQLCipher -----------------------------// | 109 | //------------------------------ SQLCipher -----------------------------// | 
| 110 | - api "net.zetetic:android-database-sqlcipher:4.5.2" | 110 | + api "net.zetetic:android-database-sqlcipher:4.5.4" | 
| 111 | - api "androidx.sqlite:sqlite:2.2.0" | 111 | + api "androidx.sqlite:sqlite:2.5.1" | 
| 112 | - api 'com.getkeepsafe.relinker:relinker:1.4.4' | 112 | + api 'com.getkeepsafe.relinker:relinker:1.4.5' | 
| 113 | 113 | ||
| 114 | //------------------------------ Calligraphy -----------------------------// | 114 | //------------------------------ Calligraphy -----------------------------// | 
| 115 | // api 'io.github.inflationx:calligraphy3:3.1.1' | 115 | // api 'io.github.inflationx:calligraphy3:3.1.1' | ... | ... | 
| ... | @@ -258,8 +258,8 @@ | ... | @@ -258,8 +258,8 @@ | 
| 258 | <!-- </intent-filter>--> | 258 | <!-- </intent-filter>--> | 
| 259 | <!-- </receiver>--> | 259 | <!-- </receiver>--> | 
| 260 | 260 | ||
| 261 | - <!-- <provider--> | 261 | + <provider | 
| 262 | - <!-- android:name=".utils.WarplyProvider"--> | 262 | + android:name=".utils.WarplyProvider" | 
| 263 | - <!-- android:authorities="ly.warp.sdk.utils.WarplyProvider" />--> | 263 | + android:authorities="ly.warp.sdk.utils.WarplyProvider" /> | 
| 264 | </application> | 264 | </application> | 
| 265 | </manifest> | 265 | </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,8 +45,12 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -40,8 +45,12 @@ 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"; | 
| 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 | ||
| 45 | 54 | ||
| 46 | //------------------------------ Fields -----------------------------// | 55 | //------------------------------ Fields -----------------------------// | 
| 47 | private static String TABLE_REQUESTS = "requests"; | 56 | private static String TABLE_REQUESTS = "requests"; | 
| ... | @@ -118,6 +127,9 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -118,6 +127,9 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | 
| 118 | 127 | ||
| 119 | private SQLiteDatabase mDb; | 128 | private SQLiteDatabase mDb; | 
| 120 | private static WarplyDBHelper mDBHelperInstance; | 129 | private static WarplyDBHelper mDBHelperInstance; | 
| 130 | + | ||
| 131 | + // Single-threaded executor for database operations | ||
| 132 | + private final ExecutorService dbExecutor = Executors.newSingleThreadExecutor(); | ||
| 121 | 133 | ||
| 122 | // =========================================================== | 134 | // =========================================================== | 
| 123 | // Constructors | 135 | // Constructors | 
| ... | @@ -145,30 +157,119 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -145,30 +157,119 @@ 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(); | 
| 166 | mDb = null; | 222 | mDb = null; | 
| 167 | } | 223 | } | 
| 168 | } | 224 | } | 
| 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 | + } | ||
| 169 | 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; | 
| 252 | - if (cursor != null && cursor.moveToFirst()) { | 358 | + try { | 
| 253 | - boolean isNotEmpty = cursor.getInt(0) > 0; | 359 | + cursor = getReadableDb().rawQuery("SELECT COUNT(*) FROM " + tableName, null); | 
| 254 | - cursor.close(); | 360 | + if (cursor != null && cursor.moveToFirst()) { | 
| 255 | - closeDb(); | 361 | + isNotEmpty = cursor.getInt(0) > 0; | 
| 256 | - return isNotEmpty; | 362 | + } | 
| 257 | - } else { | 363 | + } finally { | 
| 258 | - closeDb(); | 364 | + if (cursor != null) { | 
| 259 | - return false; | 365 | + cursor.close(); | 
| 366 | + } | ||
| 367 | + // Don't close the database here to improve performance | ||
| 260 | } | 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; | 
| 292 | - if (cursor != null && cursor.moveToFirst()) { | 401 | + try { | 
| 293 | - cursor.moveToFirst(); | 402 | + cursor = getReadableDb().query(TABLE_AUTH, new String[]{columnName}, null, null, null, null, null); | 
| 294 | - columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 403 | + if (cursor != null && cursor.moveToFirst()) { | 
| 295 | - cursor.close(); | 404 | + columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 
| 405 | + } | ||
| 406 | + } finally { | ||
| 407 | + if (cursor != null) { | ||
| 408 | + cursor.close(); | ||
| 409 | + } | ||
| 410 | + // Don't close the database here to improve performance | ||
| 296 | } | 411 | } | 
| 297 | - | ||
| 298 | - closeDb(); | ||
| 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; | 
| 307 | - if (cursor != null && cursor.moveToFirst()) { | 419 | + try { | 
| 308 | - cursor.moveToFirst(); | 420 | + cursor = getReadableDb().query(TABLE_CLIENT, new String[]{columnName}, null, null, null, null, null); | 
| 309 | - columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 421 | + if (cursor != null && cursor.moveToFirst()) { | 
| 310 | - cursor.close(); | 422 | + columnValue = cursor.getString(cursor.getColumnIndex(columnName)); | 
| 423 | + } | ||
| 424 | + } finally { | ||
| 425 | + if (cursor != null) { | ||
| 426 | + cursor.close(); | ||
| 427 | + } | ||
| 428 | + // Don't close the database here to improve performance | ||
| 311 | } | 429 | } | 
| 312 | - | ||
| 313 | - closeDb(); | ||
| 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,163 +518,225 @@ public class WarplyDBHelper extends SQLiteOpenHelper { | ... | @@ -388,163 +518,225 @@ 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) { | 
| 403 | - StringBuilder strFilter = new StringBuilder(); | 542 | + if (ids.length == 0) return; | 
| 404 | - for (int i = 0; i < ids.length; i++) { | 543 | + | 
| 405 | - if (i > 0) { | 544 | + SQLiteDatabase db = getDb(); | 
| 406 | - strFilter.append(" OR "); | 545 | + try { | 
| 546 | + db.beginTransaction(); | ||
| 547 | + StringBuilder strFilter = new StringBuilder(); | ||
| 548 | + for (int i = 0; i < ids.length; i++) { | ||
| 549 | + if (i > 0) { | ||
| 550 | + strFilter.append(" OR "); | ||
| 551 | + } | ||
| 552 | + strFilter.append(KEY_REQUESTS_ID); | ||
| 553 | + strFilter.append("="); | ||
| 554 | + strFilter.append(ids[i]); | ||
| 407 | } | 555 | } | 
| 408 | - strFilter.append(KEY_REQUESTS_ID); | 556 | + db.delete(TABLE_REQUESTS, strFilter.toString(), null); | 
| 409 | - strFilter.append("="); | 557 | + db.setTransactionSuccessful(); | 
| 410 | - strFilter.append(ids[i]); | 558 | + } finally { | 
| 559 | + db.endTransaction(); | ||
| 560 | + // Don't close the database here to improve performance | ||
| 411 | } | 561 | } | 
| 412 | - getDb().delete(TABLE_REQUESTS, strFilter.toString(), null); | ||
| 413 | - | ||
| 414 | - closeDb(); | ||
| 415 | } | 562 | } | 
| 416 | 563 | ||
| 417 | public synchronized void deletePushRequests(Long... ids) { | 564 | public synchronized void deletePushRequests(Long... ids) { | 
| 418 | - StringBuilder strFilter = new StringBuilder(); | 565 | + if (ids.length == 0) return; | 
| 419 | - for (int i = 0; i < ids.length; i++) { | 566 | + | 
| 420 | - if (i > 0) { | 567 | + SQLiteDatabase db = getDb(); | 
| 421 | - strFilter.append(" OR "); | 568 | + try { | 
| 569 | + db.beginTransaction(); | ||
| 570 | + StringBuilder strFilter = new StringBuilder(); | ||
| 571 | + for (int i = 0; i < ids.length; i++) { | ||
| 572 | + if (i > 0) { | ||
| 573 | + strFilter.append(" OR "); | ||
| 574 | + } | ||
| 575 | + strFilter.append(KEY_REQUESTS_ID); | ||
| 576 | + strFilter.append("="); | ||
| 577 | + strFilter.append(ids[i]); | ||
| 422 | } | 578 | } | 
| 423 | - strFilter.append(KEY_REQUESTS_ID); | 579 | + db.delete(TABLE_PUSH_REQUESTS, strFilter.toString(), null); | 
| 424 | - strFilter.append("="); | 580 | + db.setTransactionSuccessful(); | 
| 425 | - strFilter.append(ids[i]); | 581 | + } finally { | 
| 582 | + db.endTransaction(); | ||
| 583 | + // Don't close the database here to improve performance | ||
| 426 | } | 584 | } | 
| 427 | - getDb().delete(TABLE_PUSH_REQUESTS, strFilter.toString(), null); | ||
| 428 | - | ||
| 429 | - closeDb(); | ||
| 430 | } | 585 | } | 
| 431 | 586 | ||
| 432 | public synchronized void deletePushAckRequests(Long... ids) { | 587 | public synchronized void deletePushAckRequests(Long... ids) { | 
| 433 | - StringBuilder strFilter = new StringBuilder(); | 588 | + if (ids.length == 0) return; | 
| 434 | - for (int i = 0; i < ids.length; i++) { | 589 | + | 
| 435 | - if (i > 0) { | 590 | + SQLiteDatabase db = getDb(); | 
| 436 | - strFilter.append(" OR "); | 591 | + try { | 
| 592 | + db.beginTransaction(); | ||
| 593 | + StringBuilder strFilter = new StringBuilder(); | ||
| 594 | + for (int i = 0; i < ids.length; i++) { | ||
| 595 | + if (i > 0) { | ||
| 596 | + strFilter.append(" OR "); | ||
| 597 | + } | ||
| 598 | + strFilter.append(KEY_REQUESTS_ID); | ||
| 599 | + strFilter.append("="); | ||
| 600 | + strFilter.append(ids[i]); | ||
| 437 | } | 601 | } | 
| 438 | - strFilter.append(KEY_REQUESTS_ID); | 602 | + db.delete(TABLE_PUSH_ACK_REQUESTS, strFilter.toString(), null); | 
| 439 | - strFilter.append("="); | 603 | + db.setTransactionSuccessful(); | 
| 440 | - strFilter.append(ids[i]); | 604 | + } finally { | 
| 605 | + db.endTransaction(); | ||
| 606 | + // Don't close the database here to improve performance | ||
| 441 | } | 607 | } | 
| 442 | - getDb().delete(TABLE_PUSH_ACK_REQUESTS, strFilter.toString(), null); | ||
| 443 | - | ||
| 444 | - closeDb(); | ||
| 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; | 
| 451 | - if (cursor != null) { | 612 | + Cursor cursor = null; | 
| 452 | - result = cursor.getCount() > 0; | 613 | + try { | 
| 453 | - cursor.close(); | 614 | + cursor = getReadableDb().query(TABLE_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | 
| 615 | + null, null, null, null); | ||
| 616 | + if (cursor != null) { | ||
| 617 | + result = cursor.getCount() > 0; | ||
| 618 | + } | ||
| 619 | + } finally { | ||
| 620 | + if (cursor != null) { | ||
| 621 | + cursor.close(); | ||
| 622 | + } | ||
| 623 | + // Don't close the database here to improve performance | ||
| 454 | } | 624 | } | 
| 455 | - | ||
| 456 | - closeDb(); | ||
| 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; | 
| 465 | - if (cursor != null) { | 630 | + Cursor cursor = null; | 
| 466 | - result = cursor.getCount() > 0; | 631 | + try { | 
| 467 | - cursor.close(); | 632 | + cursor = getReadableDb().query(TABLE_PUSH_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | 
| 633 | + null, null, null, null); | ||
| 634 | + if (cursor != null) { | ||
| 635 | + result = cursor.getCount() > 0; | ||
| 636 | + } | ||
| 637 | + } finally { | ||
| 638 | + if (cursor != null) { | ||
| 639 | + cursor.close(); | ||
| 640 | + } | ||
| 641 | + // Don't close the database here to improve performance | ||
| 468 | } | 642 | } | 
| 469 | - | ||
| 470 | - closeDb(); | ||
| 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; | 
| 479 | - if (cursor != null) { | 648 | + Cursor cursor = null; | 
| 480 | - result = cursor.getCount() > 0; | 649 | + try { | 
| 481 | - cursor.close(); | 650 | + cursor = getReadableDb().query(TABLE_PUSH_ACK_REQUESTS, null, KEY_REQUESTS_FORCE + "=1", | 
| 651 | + null, null, null, null); | ||
| 652 | + if (cursor != null) { | ||
| 653 | + result = cursor.getCount() > 0; | ||
| 654 | + } | ||
| 655 | + } finally { | ||
| 656 | + if (cursor != null) { | ||
| 657 | + cursor.close(); | ||
| 658 | + } | ||
| 659 | + // Don't close the database here to improve performance | ||
| 482 | } | 660 | } | 
| 483 | - | ||
| 484 | - closeDb(); | ||
| 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) { | 
| 517 | - ContentValues values = new ContentValues(); | 691 | + SQLiteDatabase db = getDb(); | 
| 518 | - for (int i = 0; i < jsonArray.length(); i++) { | 692 | + try { | 
| 519 | - JSONObject jsonobject = jsonArray.optJSONObject(i); | 693 | + db.beginTransaction(); | 
| 520 | - if (jsonobject != null) { | 694 | + ContentValues values = new ContentValues(); | 
| 521 | - String timestamp = jsonobject.keys().next(); | 695 | + for (int i = 0; i < jsonArray.length(); i++) { | 
| 522 | - values.put(KEY_TIMESTAMP, timestamp); | 696 | + JSONObject jsonobject = jsonArray.optJSONObject(i); | 
| 523 | - JSONObject jobjData = jsonobject.optJSONObject(timestamp); | 697 | + if (jsonobject != null) { | 
| 524 | - if (jobjData != null) { | 698 | + values.clear(); | 
| 525 | - values.put(KEY_ACCELERATION, jobjData.optDouble(KEY_ACCELERATION)); | 699 | + String timestamp = jsonobject.keys().next(); | 
| 526 | - values.put(KEY_SPEED, jobjData.optDouble(KEY_SPEED)); | 700 | + values.put(KEY_TIMESTAMP, timestamp); | 
| 701 | + JSONObject jobjData = jsonobject.optJSONObject(timestamp); | ||
| 702 | + if (jobjData != null) { | ||
| 703 | + values.put(KEY_ACCELERATION, jobjData.optDouble(KEY_ACCELERATION)); | ||
| 704 | + values.put(KEY_SPEED, jobjData.optDouble(KEY_SPEED)); | ||
| 705 | + } | ||
| 706 | + db.insert(TABLE_TELEMATICS, null, values); | ||
| 527 | } | 707 | } | 
| 528 | - insert(TABLE_TELEMATICS, values); | ||
| 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) { | 
| 535 | - StringBuilder strFilter = new StringBuilder(); | 718 | + if (tags.length == 0) return; | 
| 536 | - for (int i = 0; i < tags.length; i++) { | 719 | + | 
| 537 | - if (i > 0) { | 720 | + SQLiteDatabase db = getDb(); | 
| 538 | - strFilter.append(" OR "); | 721 | + try { | 
| 722 | + db.beginTransaction(); | ||
| 723 | + StringBuilder strFilter = new StringBuilder(); | ||
| 724 | + for (int i = 0; i < tags.length; i++) { | ||
| 725 | + if (i > 0) { | ||
| 726 | + strFilter.append(" OR "); | ||
| 727 | + } | ||
| 728 | + strFilter.append(KEY_TAG); | ||
| 729 | + strFilter.append("="); | ||
| 730 | + strFilter.append("'"); | ||
| 731 | + strFilter.append(tags[i]); | ||
| 732 | + strFilter.append("'"); | ||
| 539 | } | 733 | } | 
| 540 | - strFilter.append(KEY_TAG); | 734 | + db.delete(TABLE_TAGS, strFilter.toString(), null); | 
| 541 | - strFilter.append("="); | 735 | + db.setTransactionSuccessful(); | 
| 542 | - strFilter.append("'"); | 736 | + } finally { | 
| 543 | - strFilter.append(tags[i]); | 737 | + db.endTransaction(); | 
| 544 | - strFilter.append("'"); | 738 | + // Don't close the database here to improve performance | 
| 545 | } | 739 | } | 
| 546 | - getDb().delete(TABLE_TAGS, strFilter.toString(), null); | ||
| 547 | - closeDb(); | ||
| 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; | 
| 559 | - if (cursor != null) { | 750 | + try { | 
| 560 | - | 751 | + cursor = getReadableDb().query(TABLE_TAGS, null, null, null, null, null, null); | 
| 561 | - tags = new ArrayList<>(cursor.getCount()); | 752 | + if (cursor != null) { | 
| 562 | - while (cursor.moveToNext()) { | 753 | + tags = new ArrayList<>(cursor.getCount()); | 
| 563 | - tags.add(cursor.getString(cursor | 754 | + while (cursor.moveToNext()) { | 
| 564 | - .getColumnIndex(KEY_TAG))); | 755 | + tags.add(cursor.getString(cursor.getColumnIndex(KEY_TAG))); | 
| 756 | + } | ||
| 757 | + } | ||
| 758 | + } finally { | ||
| 759 | + if (cursor != null) { | ||
| 760 | + cursor.close(); | ||
| 565 | } | 761 | } | 
| 566 | - cursor.close(); | 762 | + // Don't close the database here to improve performance | 
| 567 | } | 763 | } | 
| 568 | - | ||
| 569 | - closeDb(); | ||
| 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 | ... | ... | 
| ... | @@ -2,6 +2,7 @@ package ly.warp.sdk.utils; | ... | @@ -2,6 +2,7 @@ package ly.warp.sdk.utils; | 
| 2 | 2 | ||
| 3 | import android.content.ContentProvider; | 3 | import android.content.ContentProvider; | 
| 4 | import android.content.ContentValues; | 4 | import android.content.ContentValues; | 
| 5 | +import android.content.Context; | ||
| 5 | import android.database.Cursor; | 6 | import android.database.Cursor; | 
| 6 | import android.net.Uri; | 7 | import android.net.Uri; | 
| 7 | 8 | ||
| ... | @@ -9,6 +10,8 @@ import androidx.annotation.NonNull; | ... | @@ -9,6 +10,8 @@ import androidx.annotation.NonNull; | 
| 9 | import androidx.annotation.Nullable; | 10 | import androidx.annotation.Nullable; | 
| 10 | import androidx.appcompat.app.AppCompatDelegate; | 11 | import androidx.appcompat.app.AppCompatDelegate; | 
| 11 | 12 | ||
| 13 | +import ly.warp.sdk.db.WarplyDBHelper; | ||
| 14 | + | ||
| 12 | /** | 15 | /** | 
| 13 | * Created by Panagiotis Triantafyllou on 05/Αυγ/2022. | 16 | * Created by Panagiotis Triantafyllou on 05/Αυγ/2022. | 
| 14 | */ | 17 | */ | 
| ... | @@ -16,7 +19,14 @@ public class WarplyProvider extends ContentProvider { | ... | @@ -16,7 +19,14 @@ public class WarplyProvider extends ContentProvider { | 
| 16 | 19 | ||
| 17 | @Override | 20 | @Override | 
| 18 | public boolean onCreate() { | 21 | public boolean onCreate() { | 
| 19 | - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); | 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 | + } | ||
| 20 | // ViewPump.init(ViewPump.builder() | 30 | // ViewPump.init(ViewPump.builder() | 
| 21 | // .addInterceptor(new CalligraphyInterceptor( | 31 | // .addInterceptor(new CalligraphyInterceptor( | 
| 22 | // new CalligraphyConfig.Builder() | 32 | // new CalligraphyConfig.Builder() | 
| ... | @@ -34,6 +44,18 @@ public class WarplyProvider extends ContentProvider { | ... | @@ -34,6 +44,18 @@ public class WarplyProvider extends ContentProvider { | 
| 34 | return true; | 44 | return true; | 
| 35 | } | 45 | } | 
| 36 | 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 | + | ||
| 37 | @Nullable | 59 | @Nullable | 
| 38 | @Override | 60 | @Override | 
| 39 | public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { | 61 | public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) { | ... | ... | 
- 
Please register or login to post a comment
