diff options
author | Amith Yamasani <yamasani@google.com> | 2012-04-05 14:43:22 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-04-05 14:43:22 -0700 |
commit | 2184a985da15eddd010e53120ebb1da9f8af53e1 (patch) | |
tree | 6bf5df31475ba7ae659bedb689cad6dbdbe44220 /core/java/com | |
parent | e4d8a5dd42070d919dbd774f24c6684ecf1e350e (diff) | |
parent | 52c489cd63cca0361f374f7cb392018fabfa8bcc (diff) | |
download | frameworks_base-2184a985da15eddd010e53120ebb1da9f8af53e1.zip frameworks_base-2184a985da15eddd010e53120ebb1da9f8af53e1.tar.gz frameworks_base-2184a985da15eddd010e53120ebb1da9f8af53e1.tar.bz2 |
Merge "Lockscreen settings per user"
Diffstat (limited to 'core/java/com')
3 files changed, 529 insertions, 117 deletions
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl new file mode 100644 index 0000000..c72c770 --- /dev/null +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2012 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.internal.widget; + +/** {@hide} */ +interface ILockSettings { + void setBoolean(in String key, in boolean value, in int userId); + void setLong(in String key, in long value, in int userId); + void setString(in String key, in String value, in int userId); + boolean getBoolean(in String key, in boolean defaultValue, in int userId); + long getLong(in String key, in long defaultValue, in int userId); + String getString(in String key, in String defaultValue, in int userId); + void setLockPattern(in byte[] hash, int userId); + boolean checkPattern(in byte[] hash, int userId); + void setLockPassword(in byte[] hash, int userId); + boolean checkPassword(in byte[] hash, int userId); + boolean havePattern(int userId); + boolean havePassword(int userId); + void removeUser(int userId); +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 93f90f6..4d308dd 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -21,15 +21,20 @@ import com.android.internal.telephony.ITelephony; import com.google.android.collect.Lists; import android.app.admin.DevicePolicyManager; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.FileObserver; import android.os.IBinder; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.UserId; import android.os.storage.IMountService; import android.provider.Settings; import android.security.KeyStore; @@ -59,10 +64,6 @@ public class LockPatternUtils { private static final String TAG = "LockPatternUtils"; - 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"; - /** * The maximum number of incorrect attempts before the user is prevented * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}. @@ -111,14 +112,14 @@ public class LockPatternUtils { */ public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1; - private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; - private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; - private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; + protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; + protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; + protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type"; public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate"; - private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt"; - private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled"; - private final static String LOCKSCREEN_OPTIONS = "lockscreen.options"; + protected final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt"; + protected final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled"; + protected final static String LOCKSCREEN_OPTIONS = "lockscreen.options"; public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK = "lockscreen.biometric_weak_fallback"; public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY @@ -126,35 +127,13 @@ public class LockPatternUtils { public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS = "lockscreen.power_button_instantly_locks"; - private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory"; + protected final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory"; private final Context mContext; private final ContentResolver mContentResolver; private DevicePolicyManager mDevicePolicyManager; - private static String sLockPatternFilename; - private static String sLockPasswordFilename; - - private static final AtomicBoolean sHaveNonZeroPatternFile = new AtomicBoolean(false); - private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false); - - private static FileObserver sPasswordObserver; - - private static class PasswordFileObserver extends FileObserver { - public PasswordFileObserver(String path, int mask) { - super(path, mask); - } - - @Override - public void onEvent(int event, String path) { - if (LOCK_PATTERN_FILE.equals(path)) { - Log.d(TAG, "lock pattern file changed"); - sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0); - } else if (LOCK_PASSWORD_FILE.equals(path)) { - Log.d(TAG, "lock password file changed"); - sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0); - } - } - } + private ILockSettings mLockSettingsService; + private int mCurrentUserId = 0; public DevicePolicyManager getDevicePolicyManager() { if (mDevicePolicyManager == null) { @@ -167,34 +146,27 @@ public class LockPatternUtils { } return mDevicePolicyManager; } + /** * @param contentResolver Used to look up and save settings. */ public LockPatternUtils(Context context) { mContext = context; mContentResolver = context.getContentResolver(); + } - // Initialize the location of gesture & PIN lock files - if (sLockPatternFilename == null) { - String dataSystemDirectory = - android.os.Environment.getDataDirectory().getAbsolutePath() + - SYSTEM_DIRECTORY; - sLockPatternFilename = dataSystemDirectory + LOCK_PATTERN_FILE; - sLockPasswordFilename = dataSystemDirectory + LOCK_PASSWORD_FILE; - sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0); - sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0); - int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE | - FileObserver.MOVED_TO | FileObserver.CREATE; - sPasswordObserver = new PasswordFileObserver(dataSystemDirectory, fileObserverMask); - sPasswordObserver.startWatching(); + private ILockSettings getLockSettings() { + if (mLockSettingsService == null) { + mLockSettingsService = ILockSettings.Stub.asInterface( + (IBinder) ServiceManager.getService("lock_settings")); } + return mLockSettingsService; } public int getRequestedMinimumPasswordLength() { return getDevicePolicyManager().getPasswordMinimumLength(null); } - /** * Gets the device policy password mode. If the mode is non-specific, returns * MODE_PATTERN which allows the user to choose anything. @@ -243,6 +215,33 @@ public class LockPatternUtils { getDevicePolicyManager().reportSuccessfulPasswordAttempt(); } + public void setCurrentUser(int userId) { + if (Process.myUid() == Process.SYSTEM_UID) { + mCurrentUserId = userId; + } else { + throw new SecurityException("Only the system process can set the current user"); + } + } + + public void removeUser(int userId) { + if (Process.myUid() == Process.SYSTEM_UID) { + try { + getLockSettings().removeUser(userId); + } catch (RemoteException re) { + Log.e(TAG, "Couldn't remove lock settings for user " + userId); + } + } + } + + private int getCurrentOrCallingUserId() { + int callingUid = Binder.getCallingUid(); + if (callingUid == android.os.Process.SYSTEM_UID) { + return mCurrentUserId; + } else { + return UserId.getUserId(callingUid); + } + } + /** * Check to see if a pattern matches the saved pattern. If no pattern exists, * always returns true. @@ -250,20 +249,10 @@ public class LockPatternUtils { * @return Whether the pattern matches the stored one. */ public boolean checkPattern(List<LockPatternView.Cell> pattern) { + int userId = getCurrentOrCallingUserId(); try { - // Read all the bytes from the file - RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "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 - return Arrays.equals(stored, LockPatternUtils.patternToHash(pattern)); - } catch (FileNotFoundException fnfe) { - return true; - } catch (IOException ioe) { + return getLockSettings().checkPattern(patternToHash(pattern), userId); + } catch (RemoteException re) { return true; } } @@ -275,20 +264,10 @@ public class LockPatternUtils { * @return Whether the password matches the stored one. */ public boolean checkPassword(String password) { + int userId = getCurrentOrCallingUserId(); try { - // Read all the bytes from the file - RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "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 - return Arrays.equals(stored, passwordToHash(password)); - } catch (FileNotFoundException fnfe) { - return true; - } catch (IOException ioe) { + return getLockSettings().checkPassword(passwordToHash(password), userId); + } catch (RemoteException re) { return true; } } @@ -325,7 +304,11 @@ public class LockPatternUtils { * @return Whether a saved pattern exists. */ public boolean savedPatternExists() { - return sHaveNonZeroPatternFile.get(); + try { + return getLockSettings().havePattern(getCurrentOrCallingUserId()); + } catch (RemoteException re) { + return false; + } } /** @@ -333,7 +316,11 @@ public class LockPatternUtils { * @return Whether a saved pattern exists. */ public boolean savedPasswordExists() { - return sHaveNonZeroPasswordFile.get(); + try { + return getLockSettings().havePassword(getCurrentOrCallingUserId()); + } catch (RemoteException re) { + return false; + } } /** @@ -471,15 +458,7 @@ public class LockPatternUtils { // Compute the hash final byte[] hash = LockPatternUtils.patternToHash(pattern); try { - // Write the hash to file - RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "rw"); - // Truncate the file if pattern is null, to clear the lock - if (pattern == null) { - raf.setLength(0); - } else { - raf.write(hash, 0, hash.length); - } - raf.close(); + getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId()); DevicePolicyManager dpm = getDevicePolicyManager(); KeyStore keyStore = KeyStore.getInstance(); if (pattern != null) { @@ -505,13 +484,8 @@ public class LockPatternUtils { dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0); } - } catch (FileNotFoundException fnfe) { - // Cant do much, unless we want to fail over to using the settings - // provider - Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename); - } catch (IOException ioe) { - // Cant do much - Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename); + } catch (RemoteException re) { + Log.e(TAG, "Couldn't save lock pattern " + re); } } @@ -586,15 +560,7 @@ public class LockPatternUtils { // Compute the hash final byte[] hash = passwordToHash(password); try { - // Write the hash to file - RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "rw"); - // Truncate the file if pattern is null, to clear the lock - if (password == null) { - raf.setLength(0); - } else { - raf.write(hash, 0, hash.length); - } - raf.close(); + getLockSettings().setLockPassword(hash, getCurrentOrCallingUserId()); DevicePolicyManager dpm = getDevicePolicyManager(); KeyStore keyStore = KeyStore.getInstance(); if (password != null) { @@ -676,12 +642,9 @@ public class LockPatternUtils { dpm.setActivePasswordState( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0); } - } catch (FileNotFoundException fnfe) { - // Cant do much, unless we want to fail over to using the settings provider - Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename); - } catch (IOException ioe) { + } catch (RemoteException re) { // Cant do much - Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename); + Log.e(TAG, "Unable to save lock password " + re); } } @@ -1013,30 +976,57 @@ public class LockPatternUtils { } private boolean getBoolean(String secureSettingKey, boolean defaultValue) { - return 1 == - android.provider.Settings.Secure.getInt(mContentResolver, secureSettingKey, - defaultValue ? 1 : 0); + try { + return getLockSettings().getBoolean(secureSettingKey, defaultValue, + getCurrentOrCallingUserId()); + } catch (RemoteException re) { + return defaultValue; + } } private void setBoolean(String secureSettingKey, boolean enabled) { - android.provider.Settings.Secure.putInt(mContentResolver, secureSettingKey, - enabled ? 1 : 0); + try { + getLockSettings().setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId()); + } catch (RemoteException re) { + // What can we do? + Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re); + } } - private long getLong(String secureSettingKey, long def) { - return android.provider.Settings.Secure.getLong(mContentResolver, secureSettingKey, def); + private long getLong(String secureSettingKey, long defaultValue) { + try { + return getLockSettings().getLong(secureSettingKey, defaultValue, + getCurrentOrCallingUserId()); + } catch (RemoteException re) { + return defaultValue; + } } private void setLong(String secureSettingKey, long value) { - android.provider.Settings.Secure.putLong(mContentResolver, secureSettingKey, value); + try { + getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId()); + } catch (RemoteException re) { + // What can we do? + Log.e(TAG, "Couldn't write long " + secureSettingKey + re); + } } private String getString(String secureSettingKey) { - return android.provider.Settings.Secure.getString(mContentResolver, secureSettingKey); + try { + return getLockSettings().getString(secureSettingKey, null, + getCurrentOrCallingUserId()); + } catch (RemoteException re) { + return null; + } } private void setString(String secureSettingKey, String value) { - android.provider.Settings.Secure.putString(mContentResolver, secureSettingKey, value); + try { + getLockSettings().setString(secureSettingKey, value, getCurrentOrCallingUserId()); + } catch (RemoteException re) { + // What can we do? + Log.e(TAG, "Couldn't write string " + secureSettingKey + re); + } } public boolean isSecure() { diff --git a/core/java/com/android/internal/widget/LockSettingsService.java b/core/java/com/android/internal/widget/LockSettingsService.java new file mode 100644 index 0000000..24c7161 --- /dev/null +++ b/core/java/com/android/internal/widget/LockSettingsService.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2012 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.internal.widget; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.os.Binder; +import android.os.RemoteException; +import android.os.UserId; +import android.provider.Settings; +import android.provider.Settings.Secure; +import android.text.TextUtils; +import android.util.Slog; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Arrays; + +/** + * Keeps the lock pattern/password data and related settings for each user. + * Used by LockPatternUtils. Needs to be a service because Settings app also needs + * to be able to save lockscreen information for secondary users. + * @hide + */ +public class LockSettingsService extends ILockSettings.Stub { + + 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[] 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 Context mContext; + + public LockSettingsService(Context context) { + mContext = context; + // Open the database + mOpenHelper = new DatabaseHelper(mContext); + } + + public void systemReady() { + migrateOldData(); + } + + private void migrateOldData() { + try { + if (getString("migrated", null, 0) != null) { + // Already migrated + return; + } + + final ContentResolver cr = mContext.getContentResolver(); + for (String validSetting : VALID_SETTINGS) { + String value = Settings.Secure.getString(cr, validSetting); + if (value != null) { + setString(validSetting, value, 0); + } + } + // No need to move the password / pattern files. They're already in the right place. + setString("migrated", "true", 0); + Slog.i(TAG, "Migrated lock settings to new location"); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to migrate old data"); + } + } + + private static final void checkWritePermission(int userId) { + final int callingUid = Binder.getCallingUid(); + if (UserId.getAppId(callingUid) != android.os.Process.SYSTEM_UID) { + throw new SecurityException("uid=" + callingUid + + " not authorized to write lock settings"); + } + } + + private static final void checkPasswordReadPermission(int userId) { + final int callingUid = Binder.getCallingUid(); + if (UserId.getAppId(callingUid) != android.os.Process.SYSTEM_UID) { + throw new SecurityException("uid=" + callingUid + + " not authorized to read lock password"); + } + } + + private static final void checkReadPermission(int userId) { + final int callingUid = Binder.getCallingUid(); + if (UserId.getAppId(callingUid) != android.os.Process.SYSTEM_UID + && UserId.getUserId(callingUid) != userId) { + throw new SecurityException("uid=" + callingUid + + " not authorized to read settings of user " + userId); + } + } + + @Override + public void setBoolean(String key, boolean value, int userId) throws RemoteException { + checkWritePermission(userId); + + writeToDb(key, value ? "1" : "0", userId); + } + + @Override + public void setLong(String key, long value, int userId) throws RemoteException { + checkWritePermission(userId); + + writeToDb(key, Long.toString(value), userId); + } + + @Override + public void setString(String key, String value, int userId) throws RemoteException { + checkWritePermission(userId); + + writeToDb(key, value, userId); + } + + @Override + public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { + //checkReadPermission(userId); + + String value = readFromDb(key, null, userId); + return TextUtils.isEmpty(value) ? + defaultValue : (value.equals("1") || value.equals("true")); + } + + @Override + public long getLong(String key, long defaultValue, int userId) throws RemoteException { + //checkReadPermission(userId); + + String value = readFromDb(key, null, userId); + return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); + } + + @Override + public String getString(String key, String defaultValue, int userId) throws RemoteException { + //checkReadPermission(userId); + + return readFromDb(key, defaultValue, userId); + } + + private String getLockPatternFilename(int 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_PATTERN_FILE; + } else { + return dataSystemDirectory + "users/" + userId + "/" + LOCK_PATTERN_FILE; + } + } + + private String getLockPasswordFilename(int 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 dataSystemDirectory + "users/" + userId + "/" + LOCK_PASSWORD_FILE; + } + } + + @Override + public boolean havePassword(int userId) throws RemoteException { + // Do we need a permissions check here? + + return new File(getLockPasswordFilename(userId)).length() > 0; + } + + @Override + public boolean havePattern(int userId) throws RemoteException { + // Do we need a permissions check here? + + return new File(getLockPatternFilename(userId)).length() > 0; + } + + @Override + public void setLockPattern(byte[] hash, int userId) throws RemoteException { + checkWritePermission(userId); + + writeFile(getLockPatternFilename(userId), hash); + } + + @Override + public boolean checkPattern(byte[] hash, 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 + return Arrays.equals(stored, hash); + } catch (FileNotFoundException fnfe) { + Slog.e(TAG, "Cannot read file " + fnfe); + return true; + } catch (IOException ioe) { + Slog.e(TAG, "Cannot read file " + ioe); + return true; + } + } + + @Override + public void setLockPassword(byte[] hash, int userId) throws RemoteException { + checkWritePermission(userId); + + writeFile(getLockPasswordFilename(userId), hash); + } + + @Override + public boolean checkPassword(byte[] hash, 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 + return Arrays.equals(stored, hash); + } catch (FileNotFoundException fnfe) { + Slog.e(TAG, "Cannot read file " + fnfe); + return true; + } catch (IOException ioe) { + Slog.e(TAG, "Cannot read file " + ioe); + return true; + } + } + + @Override + public void removeUser(int userId) { + checkWritePermission(userId); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + try { + 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(); + } + } + + 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) { + ContentValues cv = new ContentValues(); + cv.put(COLUMN_KEY, key); + cv.put(COLUMN_USERID, userId); + cv.put(COLUMN_VALUE, value); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + 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 = 1; + + 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); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) { + // Nothing yet + } + } + + private static final String[] VALID_SETTINGS = new String[] { + LockPatternUtils.LOCKOUT_PERMANENT_KEY, + LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, + LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, + LockPatternUtils.PASSWORD_TYPE_KEY, + LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, + LockPatternUtils.LOCK_PASSWORD_SALT_KEY, + LockPatternUtils.DISABLE_LOCKSCREEN_KEY, + LockPatternUtils.LOCKSCREEN_OPTIONS, + LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, + LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY, + LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, + LockPatternUtils.PASSWORD_HISTORY_KEY, + Secure.LOCK_PATTERN_ENABLED, + Secure.LOCK_BIOMETRIC_WEAK_FLAGS, + Secure.LOCK_PATTERN_VISIBLE, + Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED + }; +} |