LockSettingsService.java revision de1af08dd3a073f007ae4b8a114352cae3775028
152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani/*
252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Copyright (C) 2012 The Android Open Source Project
352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *
452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Licensed under the Apache License, Version 2.0 (the "License");
552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * you may not use this file except in compliance with the License.
652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * You may obtain a copy of the License at
752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *
852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *      http://www.apache.org/licenses/LICENSE-2.0
952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *
1052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Unless required by applicable law or agreed to in writing, software
1152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * distributed under the License is distributed on an "AS IS" BASIS,
1252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * See the License for the specific language governing permissions and
1452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * limitations under the License.
1552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani */
1652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
177a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeypackage com.android.server;
1852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
19f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Millerimport android.app.ActivityManagerNative;
2052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.content.ContentResolver;
2152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.content.ContentValues;
2252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.content.Context;
23158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Millerimport android.content.pm.PackageManager;
24187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Millerimport android.content.pm.UserInfo;
25187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
26187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Millerimport static android.content.Context.USER_SERVICE;
27158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Millerimport static android.Manifest.permission.READ_PROFILE;
2852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.database.Cursor;
2952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.database.sqlite.SQLiteDatabase;
3052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.database.sqlite.SQLiteOpenHelper;
31f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Millerimport android.database.sqlite.SQLiteStatement;
32f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Millerimport android.media.AudioManager;
33f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Millerimport android.media.AudioService;
3452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.os.Binder;
3561f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasaniimport android.os.Environment;
3652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.os.RemoteException;
37d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasaniimport android.os.SystemProperties;
38f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
39187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Millerimport android.os.UserManager;
4052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.provider.Settings;
4152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.provider.Settings.Secure;
42187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Millerimport android.provider.Settings.SettingNotFoundException;
43de1af08dd3a073f007ae4b8a114352cae3775028Jim Millerimport android.security.KeyStore;
4452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.text.TextUtils;
45f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Millerimport android.util.Log;
4652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.util.Slog;
4752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
487a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport com.android.internal.widget.ILockSettings;
497a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport com.android.internal.widget.LockPatternUtils;
507a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey
5152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.File;
5252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.FileNotFoundException;
5352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.IOException;
5452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.RandomAccessFile;
5552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.util.Arrays;
56187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Millerimport java.util.List;
5752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
5852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani/**
5952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Keeps the lock pattern/password data and related settings for each user.
6052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Used by LockPatternUtils. Needs to be a service because Settings app also needs
6152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * to be able to save lockscreen information for secondary users.
6252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * @hide
6352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani */
6452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasanipublic class LockSettingsService extends ILockSettings.Stub {
6552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
665ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Miller    private static final String PERMISSION = "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE";
6752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private final DatabaseHelper mOpenHelper;
6852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String TAG = "LockSettingsService";
6952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
7052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String TABLE = "locksettings";
7152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String COLUMN_KEY = "name";
7252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String COLUMN_USERID = "user";
7352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String COLUMN_VALUE = "value";
7452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
7552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String[] COLUMNS_FOR_QUERY = {
7652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        COLUMN_VALUE
7752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    };
7852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
7952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String SYSTEM_DIRECTORY = "/system/";
8052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String LOCK_PATTERN_FILE = "gesture.key";
8152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String LOCK_PASSWORD_FILE = "password.key";
8252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
8352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private final Context mContext;
84de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    private LockPatternUtils mLockPatternUtils;
8552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
8652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public LockSettingsService(Context context) {
8752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        mContext = context;
8852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        // Open the database
8952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        mOpenHelper = new DatabaseHelper(mContext);
90de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller
91de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        mLockPatternUtils = new LockPatternUtils(context);
9252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
9352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
9452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void systemReady() {
9552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        migrateOldData();
9652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
9752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
9852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private void migrateOldData() {
9952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
100187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            // These Settings moved before multi-user was enabled, so we only have to do it for the
101187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            // root user.
102187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            if (getString("migrated", null, 0) == null) {
103187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                final ContentResolver cr = mContext.getContentResolver();
104187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                for (String validSetting : VALID_SETTINGS) {
105187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                    String value = Settings.Secure.getString(cr, validSetting);
106187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                    if (value != null) {
107187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                        setString(validSetting, value, 0);
108187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                    }
109187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                }
110187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                // No need to move the password / pattern files. They're already in the right place.
111187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                setString("migrated", "true", 0);
112187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                Slog.i(TAG, "Migrated lock settings to new location");
11352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
11452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
115187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            // These Settings changed after multi-user was enabled, hence need to be moved per user.
116187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            if (getString("migrated_user_specific", null, 0) == null) {
117187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
118187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                final ContentResolver cr = mContext.getContentResolver();
119187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                List<UserInfo> users = um.getUsers();
120187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                for (int user = 0; user < users.size(); user++) {
1212d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    // Migrate owner info
1222d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    final int userId = users.get(user).id;
1232d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
1242d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
1252d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    if (ownerInfo != null) {
1262d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        setString(OWNER_INFO, ownerInfo, userId);
1272d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
1282d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    }
129187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
1302d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    // Migrate owner info enabled.  Note there was a bug where older platforms only
1312d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    // stored this value if the checkbox was toggled at least once. The code detects
1322d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    // this case by handling the exception.
1332d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
1342d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    boolean enabled;
1352d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    try {
1362d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
1372d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        enabled = ivalue != 0;
1382d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
1392d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    } catch (SettingNotFoundException e) {
1402d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        // Setting was never stored. Store it if the string is not empty.
1412d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                        if (!TextUtils.isEmpty(ownerInfo)) {
1422d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                            setLong(OWNER_INFO_ENABLED, 1, userId);
143187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                        }
144187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                    }
1452d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller                    Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
14652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                }
147187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                // No need to move the password / pattern files. They're already in the right place.
148187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                setString("migrated_user_specific", "true", 0);
149187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller                Slog.i(TAG, "Migrated per-user lock settings to new location");
15052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
15152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
152187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            Slog.e(TAG, "Unable to migrate old data", re);
15352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
15452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
15552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
1565ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Miller    private final void checkWritePermission(int userId) {
1575ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Miller        mContext.checkCallingOrSelfPermission(PERMISSION);
15852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
15952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
1605ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Miller    private final void checkPasswordReadPermission(int userId) {
1615ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Miller        mContext.checkCallingOrSelfPermission(PERMISSION);
16252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
16352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
164158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller    private final void checkReadPermission(String requestedKey, int userId) {
16552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        final int callingUid = Binder.getCallingUid();
166158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller        for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
167158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller            String key = READ_PROFILE_PROTECTED_SETTINGS[i];
168158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
169158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller                    != PackageManager.PERMISSION_GRANTED) {
170158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller                throw new SecurityException("uid=" + callingUid
171158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller                        + " needs permission " + READ_PROFILE + " to read "
172158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller                        + requestedKey + " for user " + userId);
173158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller            }
17452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
17552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
17652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
17752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
17852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setBoolean(String key, boolean value, int userId) throws RemoteException {
17952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
18052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
18152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeToDb(key, value ? "1" : "0", userId);
18252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
18352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
18452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
18552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setLong(String key, long value, int userId) throws RemoteException {
18652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
18752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
18852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeToDb(key, Long.toString(value), userId);
18952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
19052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
19152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
19252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setString(String key, String value, int userId) throws RemoteException {
19352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
19452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
19552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeToDb(key, value, userId);
19652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
19752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
19852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
19952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
200158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller        checkReadPermission(key, userId);
20152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
20252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String value = readFromDb(key, null, userId);
20352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return TextUtils.isEmpty(value) ?
20452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                defaultValue : (value.equals("1") || value.equals("true"));
20552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
20652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
20752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
20852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public long getLong(String key, long defaultValue, int userId) throws RemoteException {
209158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller        checkReadPermission(key, userId);
21052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
21152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String value = readFromDb(key, null, userId);
21252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
21352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
21452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
21552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
21652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public String getString(String key, String defaultValue, int userId) throws RemoteException {
217158fe19ff88e577ceda4b92c26d3dfb8dfbed117Jim Miller        checkReadPermission(key, userId);
21852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
21952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return readFromDb(key, defaultValue, userId);
22052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
22152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
22252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private String getLockPatternFilename(int userId) {
22352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String dataSystemDirectory =
22452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                android.os.Environment.getDataDirectory().getAbsolutePath() +
22552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                SYSTEM_DIRECTORY;
22652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if (userId == 0) {
22752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Leave it in the same place for user 0
22852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return dataSystemDirectory + LOCK_PATTERN_FILE;
22952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } else {
23061f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani            return  new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
23161f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani                    .getAbsolutePath();
23252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
23352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
23452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
23552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private String getLockPasswordFilename(int userId) {
23652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String dataSystemDirectory =
23752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                android.os.Environment.getDataDirectory().getAbsolutePath() +
23852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                SYSTEM_DIRECTORY;
23952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if (userId == 0) {
24052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Leave it in the same place for user 0
24152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return dataSystemDirectory + LOCK_PASSWORD_FILE;
24252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } else {
24361f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani            return  new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
24461f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani                    .getAbsolutePath();
24552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
24652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
24752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
24852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
24952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean havePassword(int userId) throws RemoteException {
25052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        // Do we need a permissions check here?
25152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
25252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return new File(getLockPasswordFilename(userId)).length() > 0;
25352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
25452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
25552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
25652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean havePattern(int userId) throws RemoteException {
25752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        // Do we need a permissions check here?
25852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
25952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return new File(getLockPatternFilename(userId)).length() > 0;
26052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
26152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
262de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    private void maybeUpdateKeystore(String password, int userId) {
263de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        if (userId == UserHandle.USER_OWNER) {
264de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            final KeyStore keyStore = KeyStore.getInstance();
265de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            // Conditionally reset the keystore if empty. If non-empty, we are just
266de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            // switching key guard type
267de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            if (TextUtils.isEmpty(password) && keyStore.isEmpty()) {
268de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                keyStore.reset();
269de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            } else {
270de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                // Update the keystore password
271de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                keyStore.password(password);
272de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            }
273de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        }
274de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    }
275de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller
27652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
277de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    public void setLockPattern(String pattern, int userId) throws RemoteException {
27852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
27952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
280de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        maybeUpdateKeystore(pattern, userId);
281de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller
282de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        final byte[] hash = LockPatternUtils.patternToHash(
283de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                LockPatternUtils.stringToPattern(pattern));
28452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeFile(getLockPatternFilename(userId), hash);
28552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
28652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
28752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
288de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    public void setLockPassword(String password, int userId) throws RemoteException {
289de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        checkWritePermission(userId);
290de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller
291de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        maybeUpdateKeystore(password, userId);
292de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller
293de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        writeFile(getLockPasswordFilename(userId), mLockPatternUtils.passwordToHash(password));
294de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    }
295de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller
296de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    @Override
297de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    public boolean checkPattern(String pattern, int userId) throws RemoteException {
29852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkPasswordReadPermission(userId);
29952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
30052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Read all the bytes from the file
30152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            RandomAccessFile raf = new RandomAccessFile(getLockPatternFilename(userId), "r");
30252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            final byte[] stored = new byte[(int) raf.length()];
30352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            int got = raf.read(stored, 0, stored.length);
30452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            raf.close();
30552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (got <= 0) {
30652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                return true;
30752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
30852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Compare the hash from the file with the entered pattern's hash
309de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            final byte[] hash = LockPatternUtils.patternToHash(
310de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                    LockPatternUtils.stringToPattern(pattern));
311de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            final boolean matched = Arrays.equals(stored, hash);
312de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            if (matched && !TextUtils.isEmpty(pattern)) {
313de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                maybeUpdateKeystore(pattern, userId);
314de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            }
315de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            return matched;
31652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (FileNotFoundException fnfe) {
31752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + fnfe);
31852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (IOException ioe) {
31952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + ioe);
32052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
321de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        return true;
32252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
32352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
32452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
325de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    public boolean checkPassword(String password, int userId) throws RemoteException {
32652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkPasswordReadPermission(userId);
32752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
32852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
32952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Read all the bytes from the file
33052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            RandomAccessFile raf = new RandomAccessFile(getLockPasswordFilename(userId), "r");
33152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            final byte[] stored = new byte[(int) raf.length()];
33252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            int got = raf.read(stored, 0, stored.length);
33352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            raf.close();
33452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (got <= 0) {
33552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                return true;
33652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
33752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Compare the hash from the file with the entered password's hash
338de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            final byte[] hash = mLockPatternUtils.passwordToHash(password);
339de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            final boolean matched = Arrays.equals(stored, hash);
340de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            if (matched && !TextUtils.isEmpty(password)) {
341de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                maybeUpdateKeystore(password, userId);
342de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            }
343de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller            return matched;
34452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (FileNotFoundException fnfe) {
34552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + fnfe);
34652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (IOException ioe) {
34752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + ioe);
34852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
349de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller        return true;
35052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
35152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
35252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
35352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void removeUser(int userId) {
35452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
35552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
35652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
35752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
35852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            File file = new File(getLockPasswordFilename(userId));
35952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (file.exists()) {
36052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                file.delete();
36152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
36252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            file = new File(getLockPatternFilename(userId));
36352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (file.exists()) {
36452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                file.delete();
36552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
36652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
36752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.beginTransaction();
36852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.delete(TABLE, COLUMN_USERID + "='" + userId + "'", null);
36952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.setTransactionSuccessful();
37052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } finally {
37152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.endTransaction();
37252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
37352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
37452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
37552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private void writeFile(String name, byte[] hash) {
37652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
37752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Write the hash to file
37852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            RandomAccessFile raf = new RandomAccessFile(name, "rw");
37952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Truncate the file if pattern is null, to clear the lock
38052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (hash == null || hash.length == 0) {
38152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                raf.setLength(0);
38252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            } else {
38352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                raf.write(hash, 0, hash.length);
38452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
38552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            raf.close();
38652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (IOException ioe) {
38752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Error writing to file " + ioe);
38852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
38952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
39052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
39152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private void writeToDb(String key, String value, int userId) {
392d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani        writeToDb(mOpenHelper.getWritableDatabase(), key, value, userId);
393d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani    }
394d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani
395d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani    private void writeToDb(SQLiteDatabase db, String key, String value, int userId) {
39652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        ContentValues cv = new ContentValues();
39752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        cv.put(COLUMN_KEY, key);
39852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        cv.put(COLUMN_USERID, userId);
39952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        cv.put(COLUMN_VALUE, value);
40052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
40152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        db.beginTransaction();
40252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
40352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
40452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    new String[] {key, Integer.toString(userId)});
40552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.insert(TABLE, null, cv);
40652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.setTransactionSuccessful();
40752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } finally {
40852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.endTransaction();
40952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
41052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
41152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
41252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private String readFromDb(String key, String defaultValue, int userId) {
41352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Cursor cursor;
41452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String result = defaultValue;
41552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
41652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
41752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
41852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                new String[] { Integer.toString(userId), key },
41952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                null, null, null)) != null) {
42052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (cursor.moveToFirst()) {
42152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                result = cursor.getString(0);
42252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
42352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            cursor.close();
42452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
42552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return result;
42652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
42752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
42852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    class DatabaseHelper extends SQLiteOpenHelper {
42952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private static final String TAG = "LockSettingsDB";
43052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private static final String DATABASE_NAME = "locksettings.db";
43152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
432f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller        private static final int DATABASE_VERSION = 2;
43352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
43452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        public DatabaseHelper(Context context) {
43552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            super(context, DATABASE_NAME, null, DATABASE_VERSION);
43652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            setWriteAheadLoggingEnabled(true);
43752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
43852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
43952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private void createTable(SQLiteDatabase db) {
44052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.execSQL("CREATE TABLE " + TABLE + " (" +
44152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
44252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    COLUMN_KEY + " TEXT," +
44352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    COLUMN_USERID + " INTEGER," +
44452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    COLUMN_VALUE + " TEXT" +
44552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    ");");
44652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
44752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
44852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        @Override
44952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        public void onCreate(SQLiteDatabase db) {
45052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            createTable(db);
451d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            initializeDefaults(db);
452d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani        }
453d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani
454d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani        private void initializeDefaults(SQLiteDatabase db) {
455d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            // Get the lockscreen default from a system property, if available
456d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            boolean lockScreenDisable = SystemProperties.getBoolean("ro.lockscreen.disable.default",
457d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani                    false);
458d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            if (lockScreenDisable) {
459d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani                writeToDb(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
460d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            }
46152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
46252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
46352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        @Override
46452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
465f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            int upgradeVersion = oldVersion;
466f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            if (upgradeVersion == 1) {
467f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                // Set the initial value for {@link LockPatternUtils#LOCKSCREEN_WIDGETS_ENABLED}
468f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                // during upgrade based on whether each user previously had widgets in keyguard.
469f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                maybeEnableWidgetSettingForUsers(db);
470f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                upgradeVersion = 2;
471f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            }
472f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller
473f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            if (upgradeVersion != DATABASE_VERSION) {
474f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                Log.w(TAG, "Failed to upgrade database!");
475f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            }
476f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller        }
477f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller
478f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller        private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) {
479f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
480f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            final ContentResolver cr = mContext.getContentResolver();
481f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            final List<UserInfo> users = um.getUsers();
482f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            for (int i = 0; i < users.size(); i++) {
483f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                final int userId = users.get(i).id;
484de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                final boolean enabled = mLockPatternUtils.hasWidgetsEnabledInKeyguard(userId);
485f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled="
486de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller                        + enabled + ", w[]=" + mLockPatternUtils.getAppWidgets());
487f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled);
488f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            }
489f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller        }
490f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller
491f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller        private void loadSetting(SQLiteDatabase db, String key, int userId, boolean value) {
492f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            SQLiteStatement stmt = null;
493f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            try {
494f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                stmt = db.compileStatement(
495f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                        "INSERT OR REPLACE INTO locksettings(name,user,value) VALUES(?,?,?);");
496f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                stmt.bindString(1, key);
497f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                stmt.bindLong(2, userId);
498f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                stmt.bindLong(3, value ? 1 : 0);
499f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                stmt.execute();
500f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            } finally {
501f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller                if (stmt != null) stmt.close();
502f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            }
50352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
50452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
50552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
50652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String[] VALID_SETTINGS = new String[] {
50752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKOUT_PERMANENT_KEY,
50852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
50952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
51052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PASSWORD_TYPE_KEY,
51152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
51252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
51352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
51452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKSCREEN_OPTIONS,
51552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
51652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
51752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
51852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PASSWORD_HISTORY_KEY,
51952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_PATTERN_ENABLED,
52052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
52152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_PATTERN_VISIBLE,
52252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
523187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    };
524187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
5252d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller    // These are protected with a read permission
5262d8ecf9df0ba4f503a09e87f91d12433f29faf52Jim Miller    private static final String[] READ_PROFILE_PROTECTED_SETTINGS = new String[] {
527187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller        Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
528187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller        Secure.LOCK_SCREEN_OWNER_INFO
529187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    };
53052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani}
531