Add helper methods for reading and writing settings

Add new private methods readSetting, readIntegerSetting,
readLongSetting, writeSetting, and writeSettingIfNotPresent
to reduce boilerplate and potential for code errors.

Change-Id: I9872cc50db86056cdc1588741600b66ee9d40f9f
diff --git a/packages/LineageSettingsProvider/src/org/lineageos/lineagesettings/LineageDatabaseHelper.java b/packages/LineageSettingsProvider/src/org/lineageos/lineagesettings/LineageDatabaseHelper.java
index c688604..3643a25 100644
--- a/packages/LineageSettingsProvider/src/org/lineageos/lineagesettings/LineageDatabaseHelper.java
+++ b/packages/LineageSettingsProvider/src/org/lineageos/lineagesettings/LineageDatabaseHelper.java
@@ -48,6 +48,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -472,6 +473,7 @@
                     Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, oldSetting.equals(1) ? 0 : 1);
             upgradeVersion = 19;
         }
+
         // *** Remember to update DATABASE_VERSION above!
         if (upgradeVersion != newVersion) {
             Log.wtf(TAG, "warning: upgrading settings database to version "
@@ -725,4 +727,119 @@
         stmt.bindString(2, value.toString());
         stmt.execute();
     }
+
+    private static void ensureTableIsValid(final String tableName) {
+        switch (tableName) {
+            case LineageTableNames.TABLE_GLOBAL:
+            case LineageTableNames.TABLE_SECURE:
+            case LineageTableNames.TABLE_SYSTEM:
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Table '" + tableName + "' is not a valid Lineage database table");
+        }
+    }
+
+    /**
+     * Read a setting from a given database table.
+     * @param db The {@link SQLiteDatabase} to read from.
+     * @param tableName The name of the database table to read from.
+     * @param name The name of the setting to read.
+     * @param defaultValue the value to return if setting cannot be read.
+     */
+    private static String readSetting(final SQLiteDatabase db, final String tableName,
+            final String name, final String defaultValue) {
+        ensureTableIsValid(tableName);
+        SQLiteStatement stmt = null;
+        try {
+            stmt = db.compileStatement("SELECT value FROM " + tableName + " WHERE name=?");
+            stmt.bindString(1, name);
+            return stmt.simpleQueryForString();
+        } catch (SQLiteDoneException ex) {
+            // Value is not set
+        } finally {
+            if (stmt != null) stmt.close();
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Read an Integer setting from a given database table.
+     * @param db The {@link SQLiteDatabase} to read from.
+     * @param tableName The name of the database table to read from.
+     * @param name The name of the setting to read.
+     * @param defaultValue the value to return if setting cannot be read or is not an Integer.
+     */
+    private static Integer readIntegerSetting(final SQLiteDatabase db, final String tableName,
+            final String name, final Integer defaultValue) {
+        ensureTableIsValid(tableName);
+        final String value = readSetting(db, tableName, name, null);
+        try {
+            return value != null ? Integer.parseInt(value) : defaultValue;
+        } catch (NumberFormatException ex) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Read a Long setting from a given database table.
+     * @param db The {@link SQLiteDatabase} to read from.
+     * @param tableName The name of the database table to read from.
+     * @param name The name of the setting to read.
+     * @param defaultValue the value to return if setting cannot be read or is not a Long.
+     */
+    private static Long readLongSetting(final SQLiteDatabase db, final String tableName,
+            final String name, final Long defaultValue) {
+        ensureTableIsValid(tableName);
+        final String value = readSetting(db, tableName, name, null);
+        try {
+            return value != null ? Long.parseLong(value) : defaultValue;
+        } catch (NumberFormatException ex) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Write a setting to a given database table, overriding existing values
+     * @param db The {@link SQLiteDatabase} to write to.
+     * @param tableName The name of the database table to write to.
+     * @param name The name of the setting to write.
+     * @param value the value of the setting to write.
+     */
+    private static void writeSetting(final SQLiteDatabase db, final String tableName,
+            final String name, final Object value) throws SQLiteDoneException {
+        writeSetting(db, tableName, name, value, true /* replaceIfExists */);
+    }
+
+    /**
+     * Write a setting to a given database table, only if it doesn't already exist
+     * @param db The {@link SQLiteDatabase} to write to.
+     * @param tableName The name of the database table to write to.
+     * @param name The name of the setting to write.
+     * @param value the value of the setting to write.
+     */
+    private static void writeSettingIfNotPresent(final SQLiteDatabase db, final String tableName,
+            final String name, final Object value) throws SQLiteDoneException {
+        writeSetting(db, tableName, name, value, false /* replaceIfExists */);
+    }
+
+    /** Write a setting to a given database table. */
+    private static void writeSetting(final SQLiteDatabase db, final String tableName,
+            final String name, final Object value, final boolean replaceIfExists)
+            throws SQLiteDoneException {
+        ensureTableIsValid(tableName);
+        SQLiteStatement stmt = null;
+        try {
+            stmt = db.compileStatement("INSERT OR " + (replaceIfExists ? "REPLACE" : "IGNORE")
+                    + " INTO " + tableName + "(name,value) VALUES(?,?);");
+            stmt.bindString(1, name);
+            stmt.bindString(2, Objects.toString(value));
+            stmt.execute();
+        } catch (SQLiteDoneException ex) {
+            // Value is not set
+            throw ex;
+        } finally {
+            if (stmt != null) stmt.close();
+        }
+    }
 }