diff options
Diffstat (limited to 'packages')
7 files changed, 277 insertions, 132 deletions
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 02e1f07..4635f48 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -5,6 +5,7 @@ import com.android.internal.content.PackageHelper; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; +import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Package; @@ -28,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import android.os.FileUtils; +import android.os.storage.IMountService; import android.provider.Settings; /* @@ -86,46 +88,51 @@ public class DefaultContainerService extends IntentService { * specified by file uri location. * @param fileUri the uri of resource to be copied. Should be a * file uri - * @return Returns - * PackageHelper.RECOMMEND_INSTALL_INTERNAL to install on internal storage - * PackageHelper.RECOMMEND_INSTALL_EXTERNAL to install on external media - * PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE for storage errors - * PackageHelper.RECOMMEND_FAILED_INVALID_APK for parse errors. + * @return Returns PackageInfoLite object containing + * the package info and recommended app location. */ - public int getRecommendedInstallLocation(final Uri fileUri) { + public PackageInfoLite getMinimalPackageInfo(final Uri fileUri) { + PackageInfoLite ret = new PackageInfoLite(); if (fileUri == null) { Log.i(TAG, "Invalid package uri " + fileUri); - return PackageHelper.RECOMMEND_FAILED_INVALID_APK; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; + return ret; } String scheme = fileUri.getScheme(); if (scheme != null && !scheme.equals("file")) { Log.w(TAG, "Falling back to installing on internal storage only"); - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; + return ret; } String archiveFilePath = fileUri.getPath(); PackageParser packageParser = new PackageParser(archiveFilePath); File sourceFile = new File(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); - PackageParser.Package pkg = packageParser.parsePackage(sourceFile, - archiveFilePath, metrics, 0); + PackageParser.PackageLite pkg = packageParser.parsePackageLite( + archiveFilePath, 0); + ret.packageName = pkg.packageName; + ret.installLocation = pkg.installLocation; // Nuke the parser reference right away and force a gc Runtime.getRuntime().gc(); packageParser = null; if (pkg == null) { Log.w(TAG, "Failed to parse package"); - return PackageHelper.RECOMMEND_FAILED_INVALID_APK; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; + return ret; } - int loc = recommendAppInstallLocation(pkg); + ret.packageName = pkg.packageName; + int loc = recommendAppInstallLocation(pkg.installLocation, archiveFilePath); if (loc == PackageManager.INSTALL_EXTERNAL) { - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } else if (loc == ERR_LOC) { Log.i(TAG, "Failed to install insufficient storage"); - return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } else { // Implies install on internal storage. - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; } + return ret; } }; @@ -171,62 +178,37 @@ public class DefaultContainerService extends IntentService { String codePath = packageURI.getPath(); File codeFile = new File(codePath); String newCachePath = null; - final int CREATE_FAILED = 1; - final int COPY_FAILED = 2; - final int FINALIZE_FAILED = 3; - final int PASS = 4; - int errCode = CREATE_FAILED; // Create new container if ((newCachePath = PackageHelper.createSdDir(codeFile, - newCid, key, Process.myUid())) != null) { - if (localLOGV) Log.i(TAG, "Created container for " + newCid - + " at path : " + newCachePath); - File resFile = new File(newCachePath, resFileName); - errCode = COPY_FAILED; - // Copy file from codePath - if (FileUtils.copyFile(new File(codePath), resFile)) { - if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); - errCode = FINALIZE_FAILED; - if (PackageHelper.finalizeSdDir(newCid)) { - if (localLOGV) Log.i(TAG, "Finalized container " + newCid); - errCode = PASS; - } - } - } - // Print error based on errCode - String errMsg = ""; - switch (errCode) { - case CREATE_FAILED: - errMsg = "CREATE_FAILED"; - break; - case COPY_FAILED: - errMsg = "COPY_FAILED"; - if (localLOGV) Log.i(TAG, "Destroying " + newCid + - " at path " + newCachePath + " after " + errMsg); - PackageHelper.destroySdDir(newCid); - break; - case FINALIZE_FAILED: - errMsg = "FINALIZE_FAILED"; - if (localLOGV) Log.i(TAG, "Destroying " + newCid + - " at path " + newCachePath + " after " + errMsg); - PackageHelper.destroySdDir(newCid); - break; - default: - errMsg = "PASS"; - if (PackageHelper.isContainerMounted(newCid)) { - if (localLOGV) Log.i(TAG, "Unmounting " + newCid + - " at path " + newCachePath + " after " + errMsg); - // Force a gc to avoid being killed. - Runtime.getRuntime().gc(); - PackageHelper.unMountSdDir(newCid); - } else { - if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted"); - } - break; + newCid, key, Process.myUid())) == null) { + Log.e(TAG, "Failed to create container " + newCid); + return null; } - if (errCode != PASS) { + if (localLOGV) Log.i(TAG, "Created container for " + newCid + + " at path : " + newCachePath); + File resFile = new File(newCachePath, resFileName); + if (!FileUtils.copyFile(new File(codePath), resFile)) { + Log.e(TAG, "Failed to copy " + codePath + " to " + resFile); + // Clean up container + PackageHelper.destroySdDir(newCid); return null; } + if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); + if (!PackageHelper.finalizeSdDir(newCid)) { + Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath); + // Clean up container + PackageHelper.destroySdDir(newCid); + } + if (localLOGV) Log.i(TAG, "Finalized container " + newCid); + if (PackageHelper.isContainerMounted(newCid)) { + if (localLOGV) Log.i(TAG, "Unmounting " + newCid + + " at path " + newCachePath); + // Force a gc to avoid being killed. + Runtime.getRuntime().gc(); + PackageHelper.unMountSdDir(newCid); + } else { + if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted"); + } return newCachePath; } @@ -307,29 +289,28 @@ public class DefaultContainerService extends IntentService { private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); private static final int ERR_LOC = -1; - public int recommendAppInstallLocation(Package pkg) { + private int recommendAppInstallLocation(int installLocation, + String archiveFilePath) { // Initial implementation: // Package size = code size + cache size + data size // If code size > 1 MB, install on SD card. // Else install on internal NAND flash, unless space on NAND is less than 10% - - if (pkg == null) { - return ERR_LOC; + String status = Environment.getExternalStorageState(); + long availSDSize = -1; + if (status.equals(Environment.MEDIA_MOUNTED)) { + StatFs sdStats = new StatFs( + Environment.getExternalStorageDirectory().getPath()); + availSDSize = (long)sdStats.getAvailableBlocks() * + (long)sdStats.getBlockSize(); } + StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); + long totalInternalSize = (long)internalStats.getBlockCount() * + (long)internalStats.getBlockSize(); + long availInternalSize = (long)internalStats.getAvailableBlocks() * + (long)internalStats.getBlockSize(); - StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath()); - StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); - - long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() * - (long)internalFlashStats.getBlockSize(); - long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() * - (long)internalFlashStats.getBlockSize(); - long availSDSize = (long)sdcardStats.getAvailableBlocks() * - (long)sdcardStats.getBlockSize(); - - double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize; + double pctNandFree = (double)availInternalSize / (double)totalInternalSize; - final String archiveFilePath = pkg.mScanPath; File apkFile = new File(archiveFilePath); long pkgLen = apkFile.length(); @@ -339,15 +320,15 @@ public class DefaultContainerService extends IntentService { // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. long reqInternalSize = 0; boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); - boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize); + boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk && - (reqInternalSize < availInternalFlashSize); + (reqInternalSize < availInternalSize); boolean fitsOnInt = intThresholdOk && intAvailOk; // Consider application flags preferences as well... - boolean installOnlyOnSd = (pkg.installLocation == + boolean installOnlyOnSd = (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - boolean installOnlyInternal = (pkg.installLocation == + boolean installOnlyInternal = (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); if (installOnlyInternal) { // If set explicitly in manifest, diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 1e9c312..bd131e0 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -60,7 +60,7 @@ <!-- user interface sound effects --> <integer name="def_power_sounds_enabled">1</integer> - <string name="def_low_battery_sound" translatable="false">/system/media/ui/LowBattery.ogg</string> + <string name="def_low_battery_sound" translatable="false">/system/media/audio/ui/LowBattery.ogg</string> <integer name="def_dock_sounds_enabled">0</integer> <string name="def_desk_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string> <string name="def_desk_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 18e247e..bccf7d2 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -38,6 +38,7 @@ import android.net.ConnectivityManager; import android.os.Environment; import android.os.SystemProperties; import android.provider.Settings; +import android.provider.Settings.Secure; import android.speech.RecognitionService; import android.speech.RecognizerIntent; import android.text.TextUtils; @@ -76,7 +77,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 51; + private static final int DATABASE_VERSION = 52; private Context mContext; @@ -232,18 +233,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } if (upgradeVersion == 27) { - // Copy settings values from 'system' to 'secure' and delete them from 'system' - SQLiteStatement insertStmt = null; - SQLiteStatement deleteStmt = null; - - db.beginTransaction(); - try { - insertStmt = - db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM " - + "system WHERE name=?"); - deleteStmt = db.compileStatement("DELETE FROM system WHERE name=?"); - - String[] settingsToMove = { + String[] settingsToMove = { Settings.Secure.ADB_ENABLED, Settings.Secure.ANDROID_ID, Settings.Secure.BLUETOOTH_ON, @@ -276,24 +266,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, }; - - 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(); - } - } + moveFromSystemToSecure(db, settingsToMove); upgradeVersion = 28; } @@ -661,6 +634,23 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 51; } + if (upgradeVersion == 51) { + /* Move the lockscreen related settings to Secure, including some private ones. */ + String[] settingsToMove = { + Secure.LOCK_PATTERN_ENABLED, + Secure.LOCK_PATTERN_VISIBLE, + Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, + "lockscreen.password_type", + "lockscreen.lockoutattemptdeadline", + "lockscreen.patterneverchosen", + "lock_pattern_autolock", + "lockscreen.lockedoutpermanently", + "lockscreen.password_salt" + }; + moveFromSystemToSecure(db, settingsToMove); + upgradeVersion = 52; + } + if (upgradeVersion != currentVersion) { Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion + ", must wipe the settings provider"); @@ -684,6 +674,38 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } + private void moveFromSystemToSecure(SQLiteDatabase db, String [] settingsToMove) { + // Copy settings values from 'system' to 'secure' and delete them from 'system' + SQLiteStatement insertStmt = null; + SQLiteStatement deleteStmt = null; + + db.beginTransaction(); + try { + insertStmt = + db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM " + + "system WHERE name=?"); + deleteStmt = db.compileStatement("DELETE FROM system 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(); + } + } + } + private void upgradeLockPatternLocation(SQLiteDatabase db) { Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'", null, null, null, null); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 2738efb..d5c9855 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -30,9 +30,9 @@ import java.io.IOException; import java.util.Arrays; import java.util.zip.CRC32; -import android.backup.BackupDataInput; -import android.backup.BackupDataOutput; -import android.backup.BackupHelperAgent; +import android.app.backup.BackupDataInput; +import android.app.backup.BackupDataOutput; +import android.app.backup.BackupHelperAgent; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index d24814d..0e75fbc 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -20,8 +20,8 @@ import java.util.Locale; import android.app.ActivityManagerNative; import android.app.IActivityManager; -import android.backup.BackupDataInput; -import android.backup.IBackupManager; +import android.app.backup.BackupDataInput; +import android.app.backup.IBackupManager; import android.content.ContentResolver; import android.content.Context; import android.content.IContentService; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index db802d3..942d32d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -20,8 +20,10 @@ import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.LinkedHashMap; +import java.util.Map; -import android.backup.BackupManager; +import android.app.backup.BackupManager; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; @@ -30,9 +32,11 @@ import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteQueryBuilder; import android.media.RingtoneManager; import android.net.Uri; +import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; import android.provider.DrmStore; @@ -48,6 +52,16 @@ public class SettingsProvider extends ContentProvider { private static final String TABLE_FAVORITES = "favorites"; private static final String TABLE_OLD_FAVORITES = "old_favorites"; + private static final String[] COLUMN_VALUE = new String[] { "value" }; + + // Cache for settings, access-ordered for acting as LRU. + // Guarded by themselves. + private static final int MAX_CACHE_ENTRIES = 50; + private static final SettingsCache sSystemCache = new SettingsCache(); + private static final SettingsCache sSecureCache = new SettingsCache(); + + private static final Bundle NULL_SETTING = Bundle.forPair("value", null); + protected DatabaseHelper mOpenHelper; private BackupManager mBackupManager; @@ -189,7 +203,7 @@ public class SettingsProvider extends ContentProvider { final Cursor c = query(Settings.Secure.CONTENT_URI, new String[] { Settings.NameValueTable.VALUE }, Settings.NameValueTable.NAME + "=?", - new String[]{Settings.Secure.ANDROID_ID}, null); + new String[] { Settings.Secure.ANDROID_ID }, null); try { final String value = c.moveToNext() ? c.getString(0) : null; if (value == null) { @@ -220,6 +234,51 @@ public class SettingsProvider extends ContentProvider { } } + /** + * Fast path that avoids the use of chatty remoted Cursors. + */ + @Override + public Bundle call(String method, String request, Bundle args) { + if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) { + return lookupValue("system", sSystemCache, request); + } + if (Settings.CALL_METHOD_GET_SECURE.equals(method)) { + return lookupValue("secure", sSecureCache, request); + } + return null; + } + + // Looks up value 'key' in 'table' and returns either a single-pair Bundle, + // possibly with a null value, or null on failure. + private Bundle lookupValue(String table, SettingsCache cache, String key) { + synchronized (cache) { + if (cache.containsKey(key)) { + return cache.get(key); + } + } + + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Cursor cursor = null; + try { + cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key}, + null, null, null, null); + if (cursor != null && cursor.getCount() == 1) { + cursor.moveToFirst(); + String value = cursor.getString(0); + Bundle bundle = (value == null) ? NULL_SETTING : Bundle.forPair("value", value); + cache.putIfAbsentLocked(key, bundle); + return bundle; + } + } catch (SQLiteException e) { + Log.w(TAG, "settings lookup error", e); + return null; + } finally { + if (cursor != null) cursor.close(); + } + cache.putIfAbsentLocked(key, NULL_SETTING); + return NULL_SETTING; + } + @Override public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) { SqlArguments args = new SqlArguments(url, where, whereArgs); @@ -271,6 +330,7 @@ public class SettingsProvider extends ContentProvider { return 0; } checkWritePermissions(args); + SettingsCache cache = SettingsCache.forTable(args.table); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); db.beginTransaction(); @@ -278,6 +338,7 @@ public class SettingsProvider extends ContentProvider { int numValues = values.length; for (int i = 0; i < numValues; i++) { if (db.insert(args.table, null, values[i]) < 0) return 0; + SettingsCache.populate(cache, values[i]); if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + values[i]); } db.setTransactionSuccessful(); @@ -294,6 +355,9 @@ public class SettingsProvider extends ContentProvider { * This setting contains a list of the currently enabled location providers. * But helper functions in android.providers.Settings can enable or disable * a single provider by using a "+" or "-" prefix before the provider name. + * + * @returns whether the database needs to be updated or not, also modifying + * 'initialValues' if needed. */ private boolean parseProviderList(Uri url, ContentValues initialValues) { String value = initialValues.getAsString(Settings.Secure.VALUE); @@ -351,7 +415,7 @@ public class SettingsProvider extends ContentProvider { } } } - + return true; } @@ -374,6 +438,9 @@ public class SettingsProvider extends ContentProvider { final long rowId = db.insert(args.table, null, initialValues); if (rowId <= 0) return null; + SettingsCache cache = SettingsCache.forTable(args.table); + SettingsCache.populate(cache, initialValues); // before we notify + if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues); url = getUriFor(url, initialValues, rowId); sendNotify(url); @@ -392,7 +459,10 @@ public class SettingsProvider extends ContentProvider { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count = db.delete(args.table, args.where, args.args); - if (count > 0) sendNotify(url); + if (count > 0) { + SettingsCache.wipe(args.table); // before we notify + sendNotify(url); + } if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted"); return count; } @@ -407,7 +477,10 @@ public class SettingsProvider extends ContentProvider { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count = db.update(args.table, initialValues, args.where, args.args); - if (count > 0) sendNotify(url); + if (count > 0) { + SettingsCache.wipe(args.table); // before we notify + sendNotify(url); + } if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues); return count; } @@ -512,4 +585,73 @@ public class SettingsProvider extends ContentProvider { // Note that this will end up calling openFile() above. return super.openAssetFile(uri, mode); } + + /** + * In-memory LRU Cache of system and secure settings, along with + * associated helper functions to keep cache coherent with the + * database. + */ + private static final class SettingsCache extends LinkedHashMap<String, Bundle> { + public SettingsCache() { + super(MAX_CACHE_ENTRIES, 0.75f /* load factor */, true /* access ordered */); + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > MAX_CACHE_ENTRIES; + } + + public void putIfAbsentLocked(String key, Bundle value) { + synchronized (this) { + if (containsKey(key)) { + // Lost a race. + return; + } + put(key, value); + } + } + + public static SettingsCache forTable(String tableName) { + if ("system".equals(tableName)) { + return SettingsProvider.sSystemCache; + } + if ("secure".equals(tableName)) { + return SettingsProvider.sSecureCache; + } + return null; + } + + /** + * Populates a key in a given (possibly-null) cache. + */ + public static void populate(SettingsCache cache, ContentValues contentValues) { + if (cache == null) { + return; + } + String name = contentValues.getAsString(Settings.NameValueTable.NAME); + if (name == null) { + Log.w(TAG, "null name populating settings cache."); + return; + } + String value = contentValues.getAsString(Settings.NameValueTable.VALUE); + synchronized (cache) { + cache.put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value)); + } + } + + /** + * Used for wiping a whole cache on deletes when we're not + * sure what exactly was deleted or changed. + */ + public static void wipe(String tableName) { + SettingsCache cache = SettingsCache.forTable(tableName); + if (cache == null) { + return; + } + synchronized (cache) { + cache.clear(); + } + } + + } } diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java index 6255275..cd46c05 100755 --- a/packages/TtsService/src/android/tts/SynthProxy.java +++ b/packages/TtsService/src/android/tts/SynthProxy.java @@ -36,9 +36,9 @@ public class SynthProxy { // Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at // the output of the synthesis. The low shelving filter removes it, leaving room for // amplification. - private final static float PICO_FILTER_GAIN = 5.5f; // linear gain - private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB - private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f; // in Hz + private final static float PICO_FILTER_GAIN = 4.0f; // linear gain + private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -16.0f; // in dB + private final static float PICO_FILTER_TRANSITION_FREQ = 1000.0f; // in Hz private final static float PICO_FILTER_SHELF_SLOPE = 1.0f; // Q // @@ -50,7 +50,7 @@ public class SynthProxy { */ public SynthProxy(String nativeSoLib) { boolean applyFilter = nativeSoLib.toLowerCase().contains("pico"); - Log.v(TtsService.SERVICE_TAG, "about to load "+ nativeSoLib + ", applyFilter="+applyFilter); + Log.v(TtsService.SERVICE_TAG, "About to load "+ nativeSoLib + ", applyFilter="+applyFilter); native_setup(new WeakReference<SynthProxy>(this), nativeSoLib); native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION, PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE); |