import android.content.BroadcastReceiver;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_PROFILE;
-import android.database.Cursor;
+
import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
-import android.os.Environment;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.storage.IMountService;
import android.os.ServiceManager;
-import android.os.storage.StorageManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
-import android.security.KeyChain;
-import android.security.KeyChain.KeyChainConnection;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.ILockSettingsObserver;
import com.android.internal.widget.LockPatternUtils;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
*/
public class LockSettingsService extends ILockSettings.Stub {
- private static final String PERMISSION = "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE";
+ private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- private final DatabaseHelper mOpenHelper;
- private static final String TAG = "LockSettingsService";
- private static final String TABLE = "locksettings";
- private static final String COLUMN_KEY = "name";
- private static final String COLUMN_USERID = "user";
- private static final String COLUMN_VALUE = "value";
+ private static final String TAG = "LockSettingsService";
- private static final String[] COLUMNS_FOR_QUERY = {
- COLUMN_VALUE
- };
+ private final Context mContext;
- private static final String SYSTEM_DIRECTORY = "/system/";
- private static final String LOCK_PATTERN_FILE = "gesture.key";
- private static final String LOCK_PASSWORD_FILE = "password.key";
+ private final LockSettingsStorage mStorage;
- private final Context mContext;
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
public LockSettingsService(Context context) {
mContext = context;
// Open the database
- mOpenHelper = new DatabaseHelper(mContext);
mLockPatternUtils = new LockPatternUtils(context);
mFirstCallToVold = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
+ mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
+ @Override
+ public void initialize(SQLiteDatabase db) {
+ // Get the lockscreen default from a system property, if available
+ boolean lockScreenDisable = SystemProperties.getBoolean(
+ "ro.lockscreen.disable.default", false);
+ if (lockScreenDisable) {
+ mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
+ }
+ }
+ });
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void setBoolean(String key, boolean value, int userId) throws RemoteException {
checkWritePermission(userId);
-
- writeToDb(key, value ? "1" : "0", userId);
+ setStringUnchecked(key, userId, value ? "1" : "0");
}
@Override
public void setLong(String key, long value, int userId) throws RemoteException {
checkWritePermission(userId);
-
- writeToDb(key, Long.toString(value), userId);
+ setStringUnchecked(key, userId, Long.toString(value));
}
@Override
public void setString(String key, String value, int userId) throws RemoteException {
checkWritePermission(userId);
+ setStringUnchecked(key, userId, value);
+ }
- writeToDb(key, value, userId);
+ private void setStringUnchecked(String key, int userId, String value) {
+ mStorage.writeKeyValue(key, value, userId);
+ notifyObservers(key, userId);
}
@Override
public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
- String value = readFromDb(key, null, userId);
+ String value = mStorage.readKeyValue(key, null, userId);
return TextUtils.isEmpty(value) ?
defaultValue : (value.equals("1") || value.equals("true"));
}
public long getLong(String key, long defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
- String value = readFromDb(key, null, userId);
+ String value = mStorage.readKeyValue(key, null, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
}
public String getString(String key, String defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
- return readFromDb(key, defaultValue, userId);
+ return mStorage.readKeyValue(key, defaultValue, userId);
}
@Override
}
}
- private int getUserParentOrSelfId(int userId) {
- if (userId != 0) {
- final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
- final UserInfo pi = um.getProfileParent(userId);
- if (pi != null) {
- return pi.id;
- }
- }
- return userId;
- }
-
- private String getLockPatternFilename(int userId) {
- String dataSystemDirectory =
- android.os.Environment.getDataDirectory().getAbsolutePath() +
- SYSTEM_DIRECTORY;
- userId = getUserParentOrSelfId(userId);
- if (userId == 0) {
- // Leave it in the same place for user 0
- return dataSystemDirectory + LOCK_PATTERN_FILE;
- } else {
- return new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
- .getAbsolutePath();
- }
- }
-
- private String getLockPasswordFilename(int userId) {
- userId = getUserParentOrSelfId(userId);
- String dataSystemDirectory =
- android.os.Environment.getDataDirectory().getAbsolutePath() +
- SYSTEM_DIRECTORY;
- if (userId == 0) {
- // Leave it in the same place for user 0
- return dataSystemDirectory + LOCK_PASSWORD_FILE;
- } else {
- return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
- .getAbsolutePath();
- }
- }
-
@Override
public boolean havePassword(int userId) throws RemoteException {
// Do we need a permissions check here?
- return new File(getLockPasswordFilename(userId)).length() > 0;
+ return mStorage.hasPassword(userId);
}
@Override
public boolean havePattern(int userId) throws RemoteException {
// Do we need a permissions check here?
- return new File(getLockPatternFilename(userId)).length() > 0;
+ return mStorage.hasPattern(userId);
}
private void maybeUpdateKeystore(String password, int userHandle) {
final byte[] hash = LockPatternUtils.patternToHash(
LockPatternUtils.stringToPattern(pattern));
- writeFile(getLockPatternFilename(userId), hash);
+ mStorage.writePatternHash(hash, userId);
}
@Override
maybeUpdateKeystore(password, userId);
- writeFile(getLockPasswordFilename(userId),
- mLockPatternUtils.passwordToHash(password, userId));
+ mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
}
@Override
public boolean checkPattern(String pattern, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- try {
- // Read all the bytes from the file
- RandomAccessFile raf = new RandomAccessFile(getLockPatternFilename(userId), "r");
- final byte[] stored = new byte[(int) raf.length()];
- int got = raf.read(stored, 0, stored.length);
- raf.close();
- if (got <= 0) {
- return true;
- }
- // Compare the hash from the file with the entered pattern's hash
- final byte[] hash = LockPatternUtils.patternToHash(
- LockPatternUtils.stringToPattern(pattern));
- final boolean matched = Arrays.equals(stored, hash);
- if (matched && !TextUtils.isEmpty(pattern)) {
- maybeUpdateKeystore(pattern, userId);
- }
- return matched;
- } catch (FileNotFoundException fnfe) {
- Slog.e(TAG, "Cannot read file " + fnfe);
- } catch (IOException ioe) {
- Slog.e(TAG, "Cannot read file " + ioe);
+ byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern));
+ byte[] storedHash = mStorage.readPatternHash(userId);
+
+ if (storedHash == null) {
+ return true;
}
- return true;
+
+ boolean matched = Arrays.equals(hash, storedHash);
+ if (matched && !TextUtils.isEmpty(pattern)) {
+ maybeUpdateKeystore(pattern, userId);
+ }
+ return matched;
}
@Override
public boolean checkPassword(String password, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- try {
- // Read all the bytes from the file
- RandomAccessFile raf = new RandomAccessFile(getLockPasswordFilename(userId), "r");
- final byte[] stored = new byte[(int) raf.length()];
- int got = raf.read(stored, 0, stored.length);
- raf.close();
- if (got <= 0) {
- return true;
- }
- // Compare the hash from the file with the entered password's hash
- final byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
- final boolean matched = Arrays.equals(stored, hash);
- if (matched && !TextUtils.isEmpty(password)) {
- maybeUpdateKeystore(password, userId);
- }
- return matched;
- } catch (FileNotFoundException fnfe) {
- Slog.e(TAG, "Cannot read file " + fnfe);
- } catch (IOException ioe) {
- Slog.e(TAG, "Cannot read file " + ioe);
+ byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
+ byte[] storedHash = mStorage.readPasswordHash(userId);
+
+ if (storedHash == null) {
+ return true;
+ }
+
+ boolean matched = Arrays.equals(hash, storedHash);
+ if (matched && !TextUtils.isEmpty(password)) {
+ maybeUpdateKeystore(password, userId);
}
- return true;
+ return matched;
}
@Override
- public boolean checkVoldPassword(int userId) throws RemoteException {
+ public boolean checkVoldPassword(int userId) throws RemoteException {
if (!mFirstCallToVold) {
return false;
}
public void removeUser(int userId) {
checkWritePermission(userId);
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- try {
- final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
- final UserInfo parentInfo = um.getProfileParent(userId);
- if (parentInfo == null) {
- // This user owns its lock settings files - safe to delete them
- File file = new File(getLockPasswordFilename(userId));
- if (file.exists()) {
- file.delete();
- }
- file = new File(getLockPatternFilename(userId));
- if (file.exists()) {
- file.delete();
- }
- }
-
- db.beginTransaction();
- db.delete(TABLE, COLUMN_USERID + "='" + userId + "'", null);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
+ mStorage.removeUser(userId);
+ notifyObservers(null /* key */, userId);
final KeyStore ks = KeyStore.getInstance();
final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID);
ks.resetUid(userUid);
}
- private void writeFile(String name, byte[] hash) {
- try {
- // Write the hash to file
- RandomAccessFile raf = new RandomAccessFile(name, "rw");
- // Truncate the file if pattern is null, to clear the lock
- if (hash == null || hash.length == 0) {
- raf.setLength(0);
- } else {
- raf.write(hash, 0, hash.length);
- }
- raf.close();
- } catch (IOException ioe) {
- Slog.e(TAG, "Error writing to file " + ioe);
- }
- }
-
- private void writeToDb(String key, String value, int userId) {
- writeToDb(mOpenHelper.getWritableDatabase(), key, value, userId);
- notifyObservers(key, userId);
- }
-
- private void writeToDb(SQLiteDatabase db, String key, String value, int userId) {
- ContentValues cv = new ContentValues();
- cv.put(COLUMN_KEY, key);
- cv.put(COLUMN_USERID, userId);
- cv.put(COLUMN_VALUE, value);
-
- db.beginTransaction();
- try {
- db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
- new String[] {key, Integer.toString(userId)});
- db.insert(TABLE, null, cv);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- private String readFromDb(String key, String defaultValue, int userId) {
- Cursor cursor;
- String result = defaultValue;
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
- COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
- new String[] { Integer.toString(userId), key },
- null, null, null)) != null) {
- if (cursor.moveToFirst()) {
- result = cursor.getString(0);
- }
- cursor.close();
- }
- return result;
- }
-
- class DatabaseHelper extends SQLiteOpenHelper {
- private static final String TAG = "LockSettingsDB";
- private static final String DATABASE_NAME = "locksettings.db";
-
- private static final int DATABASE_VERSION = 2;
-
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- setWriteAheadLoggingEnabled(true);
- }
-
- private void createTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE + " (" +
- "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
- COLUMN_KEY + " TEXT," +
- COLUMN_USERID + " INTEGER," +
- COLUMN_VALUE + " TEXT" +
- ");");
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- createTable(db);
- initializeDefaults(db);
- }
-
- private void initializeDefaults(SQLiteDatabase db) {
- // Get the lockscreen default from a system property, if available
- boolean lockScreenDisable = SystemProperties.getBoolean("ro.lockscreen.disable.default",
- false);
- if (lockScreenDisable) {
- writeToDb(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
- }
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
- int upgradeVersion = oldVersion;
- if (upgradeVersion == 1) {
- // Set the initial value for {@link LockPatternUtils#LOCKSCREEN_WIDGETS_ENABLED}
- // during upgrade based on whether each user previously had widgets in keyguard.
- maybeEnableWidgetSettingForUsers(db);
- upgradeVersion = 2;
- }
-
- if (upgradeVersion != DATABASE_VERSION) {
- Log.w(TAG, "Failed to upgrade database!");
- }
- }
-
- private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) {
- final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
- final ContentResolver cr = mContext.getContentResolver();
- final List<UserInfo> users = um.getUsers();
- for (int i = 0; i < users.size(); i++) {
- final int userId = users.get(i).id;
- final boolean enabled = mLockPatternUtils.hasWidgetsEnabledInKeyguard(userId);
- Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled="
- + enabled + ", w[]=" + mLockPatternUtils.getAppWidgets());
- loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled);
- }
- }
-
- private void loadSetting(SQLiteDatabase db, String key, int userId, boolean value) {
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement(
- "INSERT OR REPLACE INTO locksettings(name,user,value) VALUES(?,?,?);");
- stmt.bindString(1, key);
- stmt.bindLong(2, userId);
- stmt.bindLong(3, value ? 1 : 0);
- stmt.execute();
- } finally {
- if (stmt != null) stmt.close();
- }
- }
- }
-
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
--- /dev/null
+/*
+ * Copyright (C) 2014 The Android Open Source 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 com.android.server;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Environment;
+import android.os.UserManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import static android.content.Context.USER_SERVICE;
+
+/**
+ * Storage for the lock settings service.
+ */
+class LockSettingsStorage {
+
+ private static final String TAG = "LockSettingsStorage";
+ private static final String TABLE = "locksettings";
+
+ private static final String COLUMN_KEY = "name";
+ private static final String COLUMN_USERID = "user";
+ private static final String COLUMN_VALUE = "value";
+
+ private static final String[] COLUMNS_FOR_QUERY = {
+ COLUMN_VALUE
+ };
+
+ private static final String SYSTEM_DIRECTORY = "/system/";
+ private static final String LOCK_PATTERN_FILE = "gesture.key";
+ private static final String LOCK_PASSWORD_FILE = "password.key";
+
+ private final DatabaseHelper mOpenHelper;
+ private final Context mContext;
+ private final Object mFileWriteLock = new Object();
+
+ LockSettingsStorage(Context context, Callback callback) {
+ mContext = context;
+ mOpenHelper = new DatabaseHelper(context, callback);
+ }
+
+ void writeKeyValue(String key, String value, int userId) {
+ writeKeyValue(mOpenHelper.getWritableDatabase(), key, value, userId);
+ }
+
+ void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) {
+ ContentValues cv = new ContentValues();
+ cv.put(COLUMN_KEY, key);
+ cv.put(COLUMN_USERID, userId);
+ cv.put(COLUMN_VALUE, value);
+
+ db.beginTransaction();
+ try {
+ db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
+ new String[] {key, Integer.toString(userId)});
+ db.insert(TABLE, null, cv);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ }
+
+ String readKeyValue(String key, String defaultValue, int userId) {
+ Cursor cursor;
+ String result = defaultValue;
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
+ COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
+ new String[] { Integer.toString(userId), key },
+ null, null, null)) != null) {
+ if (cursor.moveToFirst()) {
+ result = cursor.getString(0);
+ }
+ cursor.close();
+ }
+ return result;
+ }
+
+ byte[] readPasswordHash(int userId) {
+ final byte[] stored = readFile(getLockPasswordFilename(userId), userId);
+ if (stored != null && stored.length > 0) {
+ return stored;
+ }
+ return null;
+ }
+
+ byte[] readPatternHash(int userId) {
+ final byte[] stored = readFile(getLockPatternFilename(userId), userId);
+ if (stored != null && stored.length > 0) {
+ return stored;
+ }
+ return null;
+ }
+
+ boolean hasPassword(int userId) {
+ return hasFile(getLockPasswordFilename(userId), userId);
+ }
+
+ boolean hasPattern(int userId) {
+ return hasFile(getLockPatternFilename(userId), userId);
+ }
+
+ private boolean hasFile(String name, int userId) {
+ byte[] contents = readFile(name, userId);
+ return contents != null && contents.length > 0;
+ }
+
+ private byte[] readFile(String name, int userId) {
+ RandomAccessFile raf = null;
+ byte[] stored = null;
+ try {
+ raf = new RandomAccessFile(name, "r");
+ stored = new byte[(int) raf.length()];
+ raf.readFully(stored, 0, stored.length);
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Cannot read file " + e);
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error closing file " + e);
+ }
+ }
+ }
+ return stored;
+ }
+
+ private void writeFile(String name, byte[] hash, int userId) {
+ synchronized (mFileWriteLock) {
+ RandomAccessFile raf = null;
+ try {
+ // Write the hash to file
+ raf = new RandomAccessFile(name, "rw");
+ // Truncate the file if pattern is null, to clear the lock
+ if (hash == null || hash.length == 0) {
+ raf.setLength(0);
+ } else {
+ raf.write(hash, 0, hash.length);
+ }
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error writing to file " + e);
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error closing file " + e);
+ }
+ }
+ }
+ }
+ }
+
+ public void writePatternHash(byte[] hash, int userId) {
+ writeFile(getLockPatternFilename(userId), hash, userId);
+ }
+
+ public void writePasswordHash(byte[] hash, int userId) {
+ writeFile(getLockPasswordFilename(userId), hash, userId);
+ }
+
+
+ private String getLockPatternFilename(int userId) {
+ String dataSystemDirectory =
+ android.os.Environment.getDataDirectory().getAbsolutePath() +
+ SYSTEM_DIRECTORY;
+ userId = getUserParentOrSelfId(userId);
+ if (userId == 0) {
+ // Leave it in the same place for user 0
+ return dataSystemDirectory + LOCK_PATTERN_FILE;
+ } else {
+ return new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
+ .getAbsolutePath();
+ }
+ }
+
+ private String getLockPasswordFilename(int userId) {
+ userId = getUserParentOrSelfId(userId);
+ String dataSystemDirectory =
+ android.os.Environment.getDataDirectory().getAbsolutePath() +
+ SYSTEM_DIRECTORY;
+ if (userId == 0) {
+ // Leave it in the same place for user 0
+ return dataSystemDirectory + LOCK_PASSWORD_FILE;
+ } else {
+ return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
+ .getAbsolutePath();
+ }
+ }
+
+ private int getUserParentOrSelfId(int userId) {
+ if (userId != 0) {
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final UserInfo pi = um.getProfileParent(userId);
+ if (pi != null) {
+ return pi.id;
+ }
+ }
+ return userId;
+ }
+
+
+ public void removeUser(int userId) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final UserInfo parentInfo = um.getProfileParent(userId);
+
+ synchronized (mFileWriteLock) {
+ if (parentInfo == null) {
+ // This user owns its lock settings files - safe to delete them
+ File file = new File(getLockPasswordFilename(userId));
+ if (file.exists()) {
+ file.delete();
+ }
+ file = new File(getLockPatternFilename(userId));
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+ }
+
+ try {
+ db.beginTransaction();
+ db.delete(TABLE, COLUMN_USERID + "='" + userId + "'", null);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+
+ interface Callback {
+ void initialize(SQLiteDatabase db);
+ }
+
+ class DatabaseHelper extends SQLiteOpenHelper {
+ private static final String TAG = "LockSettingsDB";
+ private static final String DATABASE_NAME = "locksettings.db";
+
+ private static final int DATABASE_VERSION = 2;
+
+ private final Callback mCallback;
+
+ public DatabaseHelper(Context context, Callback callback) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ setWriteAheadLoggingEnabled(true);
+ mCallback = callback;
+ }
+
+ private void createTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE + " (" +
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+ COLUMN_KEY + " TEXT," +
+ COLUMN_USERID + " INTEGER," +
+ COLUMN_VALUE + " TEXT" +
+ ");");
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ createTable(db);
+ mCallback.initialize(db);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
+ int upgradeVersion = oldVersion;
+ if (upgradeVersion == 1) {
+ // Previously migrated lock screen widget settings. Now defunct.
+ upgradeVersion = 2;
+ }
+
+ if (upgradeVersion != DATABASE_VERSION) {
+ Log.w(TAG, "Failed to upgrade database!");
+ }
+ }
+ }
+}