replicant-vendor_cmsdk/packages/CMSettingsProvider/src/org/cyanogenmod/cmsettings/CMDatabaseHelper.java

532 lines
20 KiB
Java

/**
* Copyright (c) 2015, The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cyanogenmod.cmsettings;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.os.Build;
import android.os.Environment;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import cyanogenmod.providers.CMSettings;
import java.io.File;
/**
* The CMDatabaseHelper allows creation of a database to store CM specific settings for a user
* in System, Secure, and Global tables.
*/
public class CMDatabaseHelper extends SQLiteOpenHelper{
private static final String TAG = "CMDatabaseHelper";
private static final boolean LOCAL_LOGV = false;
private static final String DATABASE_NAME = "cmsettings.db";
private static final int DATABASE_VERSION = 7;
public static class CMTableNames {
public static final String TABLE_SYSTEM = "system";
public static final String TABLE_SECURE = "secure";
public static final String TABLE_GLOBAL = "global";
}
private static final String CREATE_TABLE_SQL_FORMAT = "CREATE TABLE %s (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT UNIQUE ON CONFLICT REPLACE," +
"value TEXT" +
");)";
private static final String CREATE_INDEX_SQL_FORMAT = "CREATE INDEX %sIndex%d ON %s (name);";
private static final String DROP_TABLE_SQL_FORMAT = "DROP TABLE IF EXISTS %s;";
private static final String DROP_INDEX_SQL_FORMAT = "DROP INDEX IF EXISTS %sIndex%d;";
private static final String MCC_PROP_NAME = "ro.prebundled.mcc";
private Context mContext;
private int mUserHandle;
private String mPublicSrcDir;
/**
* Gets the appropriate database path for a specific user
* @param userId The database path for this user
* @return The database path string
*/
static String dbNameForUser(final int userId) {
// The owner gets the unadorned db name;
if (userId == UserHandle.USER_OWNER) {
return DATABASE_NAME;
} else {
// Place the database in the user-specific data tree so that it's
// cleaned up automatically when the user is deleted.
File databaseFile = new File(
Environment.getUserSystemDirectory(userId), DATABASE_NAME);
return databaseFile.getPath();
}
}
/**
* Creates an instance of {@link CMDatabaseHelper}
* @param context
* @param userId
*/
public CMDatabaseHelper(Context context, int userId) {
super(context, dbNameForUser(userId), null, DATABASE_VERSION);
mContext = context;
mUserHandle = userId;
try {
String packageName = mContext.getPackageName();
mPublicSrcDir = mContext.getPackageManager().getApplicationInfo(packageName, 0)
.publicSourceDir;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
/**
* Creates System, Secure, and Global tables in the specified {@link SQLiteDatabase} and loads
* default values into the created tables.
* @param db The database.
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.beginTransaction();
try {
createDbTable(db, CMTableNames.TABLE_SYSTEM);
createDbTable(db, CMTableNames.TABLE_SECURE);
if (mUserHandle == UserHandle.USER_OWNER) {
createDbTable(db, CMTableNames.TABLE_GLOBAL);
}
loadSettings(db);
db.setTransactionSuccessful();
if (LOCAL_LOGV) Log.d(TAG, "Successfully created tables for cm settings db");
} finally {
db.endTransaction();
}
}
/**
* Creates a table and index for the specified database and table name
* @param db The {@link SQLiteDatabase} to create the table and index in.
* @param tableName The name of the database table to create.
*/
private void createDbTable(SQLiteDatabase db, String tableName) {
if (LOCAL_LOGV) Log.d(TAG, "Creating table and index for: " + tableName);
String createTableSql = String.format(CREATE_TABLE_SQL_FORMAT, tableName);
db.execSQL(createTableSql);
String createIndexSql = String.format(CREATE_INDEX_SQL_FORMAT, tableName, 1, tableName);
db.execSQL(createIndexSql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (LOCAL_LOGV) Log.d(TAG, "Upgrading from version: " + oldVersion + " to " + newVersion);
int upgradeVersion = oldVersion;
if (upgradeVersion < 2) {
db.beginTransaction();
try {
loadSettings(db);
db.setTransactionSuccessful();
upgradeVersion = 2;
} finally {
db.endTransaction();
}
}
if (upgradeVersion < 3) {
db.beginTransaction();
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT INTO secure(name,value)"
+ " VALUES(?,?);");
loadStringSetting(stmt, CMSettings.Secure.PROTECTED_COMPONENT_MANAGERS,
R.string.def_protected_component_managers);
db.setTransactionSuccessful();
} finally {
if (stmt != null) stmt.close();
db.endTransaction();
}
upgradeVersion = 3;
}
if (upgradeVersion < 4) {
if (mUserHandle == UserHandle.USER_OWNER) {
db.beginTransaction();
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT INTO secure(name,value)"
+ " VALUES(?,?);");
final String provisionedFlag = Settings.Global.getString(
mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED);
loadSetting(stmt, CMSettings.Secure.CM_SETUP_WIZARD_COMPLETED, provisionedFlag);
db.setTransactionSuccessful();
} finally {
if (stmt != null) stmt.close();
db.endTransaction();
}
}
upgradeVersion = 4;
}
if (upgradeVersion < 5) {
if (mUserHandle == UserHandle.USER_OWNER) {
db.beginTransaction();
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT INTO global(name,value)"
+ " VALUES(?,?);");
loadIntegerSetting(stmt, CMSettings.Global.WEATHER_TEMPERATURE_UNIT,
R.integer.def_temperature_unit);
db.setTransactionSuccessful();
} finally {
if (stmt != null) stmt.close();
db.endTransaction();
}
}
upgradeVersion = 5;
}
if (upgradeVersion < 6) {
// Move force_show_navbar to global
if (mUserHandle == UserHandle.USER_OWNER) {
moveSettingsToNewTable(db, CMTableNames.TABLE_SECURE,
CMTableNames.TABLE_GLOBAL, new String[] {
CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR
}, true);
}
upgradeVersion = 6;
}
if (upgradeVersion < 7) {
if (mUserHandle == UserHandle.USER_OWNER) {
db.beginTransaction();
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("UPDATE system SET value = 0 WHERE name IN (?,?,?);");
stmt.bindString(1, CMSettings.System.ENABLE_FORWARD_LOOKUP);
stmt.bindString(2, CMSettings.System.ENABLE_PEOPLE_LOOKUP);
stmt.bindString(3, CMSettings.System.ENABLE_REVERSE_LOOKUP);
stmt.execute();
db.setTransactionSuccessful();
} finally {
if (stmt != null) stmt.close();
db.endTransaction();
}
}
upgradeVersion = 7;
}
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion < newVersion) {
Log.w(TAG, "Got stuck trying to upgrade db. Old version: " + oldVersion
+ ", version stuck at: " + upgradeVersion + ", new version: "
+ newVersion + ". Must wipe the cm settings provider.");
dropDbTable(db, CMTableNames.TABLE_SYSTEM);
dropDbTable(db, CMTableNames.TABLE_SECURE);
if (mUserHandle == UserHandle.USER_OWNER) {
dropDbTable(db, CMTableNames.TABLE_GLOBAL);
}
onCreate(db);
}
}
private void moveSettingsToNewTable(SQLiteDatabase db,
String sourceTable, String destTable,
String[] settingsToMove, boolean doIgnore) {
// Copy settings values from the source table to the dest, and remove from the source
SQLiteStatement insertStmt = null;
SQLiteStatement deleteStmt = null;
db.beginTransaction();
try {
insertStmt = db.compileStatement("INSERT "
+ (doIgnore ? " OR IGNORE " : "")
+ " INTO " + destTable + " (name,value) SELECT name,value FROM "
+ sourceTable + " WHERE name=?");
deleteStmt = db.compileStatement("DELETE FROM " + sourceTable + " WHERE name=?");
for (String setting : settingsToMove) {
insertStmt.bindString(1, setting);
insertStmt.execute();
deleteStmt.bindString(1, setting);
deleteStmt.execute();
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
if (insertStmt != null) {
insertStmt.close();
}
if (deleteStmt != null) {
deleteStmt.close();
}
}
}
/**
* Drops the table and index for the specified database and table name
* @param db The {@link SQLiteDatabase} to drop the table and index in.
* @param tableName The name of the database table to drop.
*/
private void dropDbTable(SQLiteDatabase db, String tableName) {
if (LOCAL_LOGV) Log.d(TAG, "Dropping table and index for: " + tableName);
String dropTableSql = String.format(DROP_TABLE_SQL_FORMAT, tableName);
db.execSQL(dropTableSql);
String dropIndexSql = String.format(DROP_INDEX_SQL_FORMAT, tableName, 1);
db.execSQL(dropIndexSql);
}
/**
* Loads default values for specific settings into the database.
* @param db The {@link SQLiteDatabase} to insert into.
*/
private void loadSettings(SQLiteDatabase db) {
loadSystemSettings(db);
loadSecureSettings(db);
// The global table only exists for the 'owner' user
if (mUserHandle == UserHandle.USER_OWNER) {
loadGlobalSettings(db);
}
}
private void loadSecureSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ " VALUES(?,?);");
// Secure
loadBooleanSetting(stmt, CMSettings.Secure.ADVANCED_MODE,
R.bool.def_advanced_mode);
loadRegionLockedStringSetting(stmt,
CMSettings.Secure.DEFAULT_THEME_COMPONENTS, R.string.def_theme_components);
loadRegionLockedStringSetting(stmt,
CMSettings.Secure.DEFAULT_THEME_PACKAGE, R.string.def_theme_package);
loadIntegerSetting(stmt, CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR,
R.integer.def_force_show_navbar);
loadStringSetting(stmt, CMSettings.Secure.QS_TILES,
org.cyanogenmod.platform.internal.
R.string.config_defaultQuickSettingsTiles);
loadBooleanSetting(stmt, CMSettings.Secure.QS_USE_MAIN_TILES,
R.bool.def_sysui_qs_main_tiles);
loadBooleanSetting(stmt, CMSettings.Secure.STATS_COLLECTION,
R.bool.def_stats_collection);
loadBooleanSetting(stmt, CMSettings.Secure.LOCKSCREEN_VISUALIZER_ENABLED,
R.bool.def_lockscreen_visualizer);
loadStringSetting(stmt,
CMSettings.Secure.PROTECTED_COMPONENT_MANAGERS,
R.string.def_protected_component_managers);
loadStringSetting(stmt,
CMSettings.Secure.ENABLED_EVENT_LIVE_LOCKS_KEY,
R.string.def_enabled_event_lls_components);
final String provisionedFlag = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED);
loadSetting(stmt, CMSettings.Secure.CM_SETUP_WIZARD_COMPLETED, provisionedFlag);
} finally {
if (stmt != null) stmt.close();
}
}
private void loadSystemSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ " VALUES(?,?);");
// System
loadIntegerSetting(stmt, CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN,
R.integer.def_qs_quick_pulldown);
loadIntegerSetting(stmt, CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
R.integer.def_notification_brightness_level);
loadBooleanSetting(stmt, CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE,
R.bool.def_notification_multiple_leds);
loadBooleanSetting(stmt, CMSettings.System.SYSTEM_PROFILES_ENABLED,
R.bool.def_profiles_enabled);
loadIntegerSetting(stmt, CMSettings.System.ENABLE_FORWARD_LOOKUP,
R.integer.def_forward_lookup);
loadIntegerSetting(stmt, CMSettings.System.ENABLE_PEOPLE_LOOKUP,
R.integer.def_people_lookup);
loadIntegerSetting(stmt, CMSettings.System.ENABLE_REVERSE_LOOKUP,
R.integer.def_reverse_lookup);
loadBooleanSetting(stmt, CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE,
R.bool.def_notification_pulse_custom_enable);
loadBooleanSetting(stmt, CMSettings.System.SWAP_VOLUME_KEYS_ON_ROTATION,
R.bool.def_swap_volume_keys_on_rotation);
loadIntegerSetting(stmt, CMSettings.System.STATUS_BAR_BATTERY_STYLE,
R.integer.def_battery_style);
if (mContext.getResources().getBoolean(R.bool.def_notification_pulse_custom_enable)) {
loadStringSetting(stmt, CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES,
R.string.def_notification_pulse_custom_value);
}
} finally {
if (stmt != null) stmt.close();
}
}
private void loadGlobalSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+ " VALUES(?,?);");
// Global
loadBooleanSetting(stmt,
CMSettings.Global.POWER_NOTIFICATIONS_ENABLED,
R.bool.def_power_notifications_enabled);
loadBooleanSetting(stmt,
CMSettings.Global.POWER_NOTIFICATIONS_VIBRATE,
R.bool.def_power_notifications_vibrate);
loadStringSetting(stmt,
CMSettings.Global.POWER_NOTIFICATIONS_RINGTONE,
R.string.def_power_notifications_ringtone);
loadIntegerSetting(stmt, CMSettings.Global.WEATHER_TEMPERATURE_UNIT,
R.integer.def_temperature_unit);
} finally {
if (stmt != null) stmt.close();
}
}
/**
* Loads a region locked string setting into a database table. If the resource for the specific
* mcc is not found, the setting is loaded from the default resources.
* @param stmt The SQLLiteStatement (transaction) for this setting.
* @param name The name of the value to insert into the table.
* @param resId The name of the string resource.
*/
private void loadRegionLockedStringSetting(SQLiteStatement stmt, String name, int resId) {
String mcc = SystemProperties.get(MCC_PROP_NAME);
Resources customResources = null;
if (!TextUtils.isEmpty(mcc)) {
Configuration tempConfiguration = new Configuration();
boolean useTempConfig = false;
try {
tempConfiguration.mcc = Integer.parseInt(mcc);
useTempConfig = true;
} catch (NumberFormatException e) {
// not able to parse mcc, catch exception and exit out of this logic
e.printStackTrace();
}
if (useTempConfig) {
AssetManager assetManager = new AssetManager();
if (!TextUtils.isEmpty(mPublicSrcDir)) {
assetManager.addAssetPath(mPublicSrcDir);
}
customResources = new Resources(assetManager, new DisplayMetrics(),
tempConfiguration);
}
}
String value = customResources == null ? mContext.getResources().getString(resId)
: customResources.getString(resId);
loadSetting(stmt, name, value);
}
/**
* Loads a string resource into a database table. If a conflict occurs, that value is not
* inserted into the database table.
* @param stmt The SQLLiteStatement (transaction) for this setting.
* @param name The name of the value to insert into the table.
* @param resId The name of the string resource.
*/
private void loadStringSetting(SQLiteStatement stmt, String name, int resId) {
loadSetting(stmt, name, mContext.getResources().getString(resId));
}
/**
* Loads a boolean resource into a database table. If a conflict occurs, that value is not
* inserted into the database table.
* @param stmt The SQLLiteStatement (transaction) for this setting.
* @param name The name of the value to insert into the table.
* @param resId The name of the boolean resource.
*/
private void loadBooleanSetting(SQLiteStatement stmt, String name, int resId) {
loadSetting(stmt, name,
mContext.getResources().getBoolean(resId) ? "1" : "0");
}
/**
* Loads an integer resource into a database table. If a conflict occurs, that value is not
* inserted into the database table.
* @param stmt The SQLLiteStatement (transaction) for this setting.
* @param name The name of the value to insert into the table.
* @param resId The name of the integer resource.
*/
private void loadIntegerSetting(SQLiteStatement stmt, String name, int resId) {
loadSetting(stmt, name,
Integer.toString(mContext.getResources().getInteger(resId)));
}
private void loadSetting(SQLiteStatement stmt, String key, Object value) {
stmt.bindString(1, key);
stmt.bindString(2, value.toString());
stmt.execute();
}
}