19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
20682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
21682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
22682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
23682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
24682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
25682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
26682d16758010e311910133fb40868133c05b3fe6Rubin Xuimport static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
27682d16758010e311910133fb40868133c05b3fe6Rubin Xu
28b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport android.annotation.IntDef;
29e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggiimport android.annotation.Nullable;
3087bba1ee14279bb14a28d42e27c4ef66d9967bf8Dianne Hackbornimport android.app.admin.DevicePolicyManager;
315f9e6f37b276fac7be6db982c9cb7fbd93150c4aAndrew Scullimport android.app.admin.PasswordMetrics;
32b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport android.app.trust.IStrongAuthTracker;
3382142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roosimport android.app.trust.TrustManager;
3482142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roosimport android.content.ComponentName;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
3631f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Millerimport android.content.Context;
37a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarriimport android.content.pm.UserInfo;
383a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrenceimport android.os.AsyncTask;
39b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport android.os.Handler;
40f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.os.IBinder;
41aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xiaimport android.os.Looper;
42b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport android.os.Message;
4369ac9887459a65a0eebc6f9c450a5b6c2313d713Jim Millerimport android.os.RemoteException;
4469ac9887459a65a0eebc6f9c450a5b6c2313d713Jim Millerimport android.os.ServiceManager;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
46f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
47a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarriimport android.os.UserManager;
482250d56a0b47b93016018340c8f4040325aa5611Sudheer Shankaimport android.os.storage.IStorageManager;
498e39736f91a08961cf59c87075e61d9026833b50Paul Lawrenceimport android.os.storage.StorageManager;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
53b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport android.util.SparseIntArray;
54a3e5582fac1cc259022c06d027e73c767dc1c117Kevin Chynimport android.util.SparseLongArray;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
560cbc19e4a66f7db51596b57ca91afc6f5b27f3b4Rubin Xuimport com.android.internal.annotations.VisibleForTesting;
57fcd49f993ede363d0b17900565dfe37066362480Rubin Xuimport com.android.server.LocalServices;
581254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport com.google.android.collect.Lists;
599dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
601de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xuimport libcore.util.HexEncoding;
611de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
62b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport java.lang.annotation.Retention;
63b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roosimport java.lang.annotation.RetentionPolicy;
6478108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamathimport java.nio.charset.StandardCharsets;
65929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstromimport java.security.MessageDigest;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.NoSuchAlgorithmException;
6711b019d07f4de0b25e2f863a7bcaad112d847d56Jim Millerimport java.security.SecureRandom;
6882142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roosimport java.util.ArrayList;
69f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xuimport java.util.Arrays;
7082142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roosimport java.util.Collection;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
72f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xuimport java.util.StringJoiner;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
745cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom * Utilities for the lock pattern and its settings.
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class LockPatternUtils {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "LockPatternUtils";
79a0ee004abf1e8988ece2d19ff5a3bef333763c9bBrian Colonna    private static final boolean DEBUG = false;
808370e472cdf22d30e5485c8cdd884767ea482571Adrian Roos    private static final boolean FRP_CREDENTIAL_ENABLED = true;
8169aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
831de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * The key to identify when the lock pattern enabled flag is being accessed for legacy reasons.
844614596a395b6c86fff3f35a07edda2e848d743cBryce Lee     */
854614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
864614596a395b6c86fff3f35a07edda2e848d743cBryce Lee
874614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    /**
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The number of incorrect attempts before which we fall back on an alternative
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method of verifying the user, and resetting their lock pattern.
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The interval of the countdown for showing progress of the lockout.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
984f36995777a4136e8e63ea51cef2ff61df48790dJim Miller
994f36995777a4136e8e63ea51cef2ff61df48790dJim Miller    /**
1004f36995777a4136e8e63ea51cef2ff61df48790dJim Miller     * This dictates when we start telling the user that continued failed attempts will wipe
1014f36995777a4136e8e63ea51cef2ff61df48790dJim Miller     * their device.
1024f36995777a4136e8e63ea51cef2ff61df48790dJim Miller     */
1034f36995777a4136e8e63ea51cef2ff61df48790dJim Miller    public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
1044f36995777a4136e8e63ea51cef2ff61df48790dJim Miller
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The minimum number of dots in a valid pattern.
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MIN_LOCK_PATTERN_SIZE = 4;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
111f80e66ce9a57c4d3abf97e582c89292623b3904dAdrian Roos     * The minimum size of a valid password.
112f80e66ce9a57c4d3abf97e582c89292623b3904dAdrian Roos     */
113f80e66ce9a57c4d3abf97e582c89292623b3904dAdrian Roos    public static final int MIN_LOCK_PASSWORD_SIZE = 4;
114f80e66ce9a57c4d3abf97e582c89292623b3904dAdrian Roos
115f80e66ce9a57c4d3abf97e582c89292623b3904dAdrian Roos    /**
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The minimum number of dots the user must include in a wrong pattern
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * attempt for it to be counted against the counts that affect
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1204f36995777a4136e8e63ea51cef2ff61df48790dJim Miller    public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1221de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    public static final int CREDENTIAL_TYPE_NONE = -1;
1231de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
1241de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    public static final int CREDENTIAL_TYPE_PATTERN = 1;
1251de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
1261de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    public static final int CREDENTIAL_TYPE_PASSWORD = 2;
1271de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
1287374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos    /**
1297374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos     * Special user id for triggering the FRP verification flow.
1307374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos     */
1317374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos    public static final int USER_FRP = UserHandle.USER_NULL + 1;
1327374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos
1339dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    @Deprecated
1347a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey    public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
1357a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey    public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
13669aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
137230635efe7ffb09d6dc56bfd9193aa1d89c8a898Adrian Roos    @Deprecated
138230635efe7ffb09d6dc56bfd9193aa1d89c8a898Adrian Roos    public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
1397a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey    public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
1407a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey    public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
1417a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey    public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
142230635efe7ffb09d6dc56bfd9193aa1d89c8a898Adrian Roos    @Deprecated
1436edf2637e96139735df83907c221cce16d4d7eaaJim Miller    public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
1446edf2637e96139735df83907c221cce16d4d7eaaJim Miller            = "lockscreen.biometric_weak_fallback";
145230635efe7ffb09d6dc56bfd9193aa1d89c8a898Adrian Roos    @Deprecated
1467a07219a1fc8cb94ea2694025e26f70d652ad2a1Danielle Millett    public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
1477a07219a1fc8cb94ea2694025e26f70d652ad2a1Danielle Millett            = "lockscreen.biometricweakeverchosen";
148a4edd151c5266a2c794c95444fed67d19740cee3Jim Miller    public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
149a4edd151c5266a2c794c95444fed67d19740cee3Jim Miller            = "lockscreen.power_button_instantly_locks";
150230635efe7ffb09d6dc56bfd9193aa1d89c8a898Adrian Roos    @Deprecated
151f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller    public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1537a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey    public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
154863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev
155187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
156187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
157187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller            Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
158187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
1596644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
1606644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu
16182142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
162c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos    private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
16382142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos
164d398244513c62c9ea14a0f1c6ffef832e803c16fRicky Wai    public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
165d398244513c62c9ea14a0f1c6ffef832e803c16fRicky Wai    public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
1663bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_";
1673bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu
1683bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
1693bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
170f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    private static final String HISTORY_DELIMITER = ",";
171d398244513c62c9ea14a0f1c6ffef832e803c16fRicky Wai
172df83afaf299666e99c519aa86e7e082b7c116e95Dianne Hackborn    private final Context mContext;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final ContentResolver mContentResolver;
17431f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller    private DevicePolicyManager mDevicePolicyManager;
17552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private ILockSettings mLockSettingsService;
176a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    private UserManager mUserManager;
1777a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos    private final Handler mHandler;
178a3e5582fac1cc259022c06d027e73c767dc1c117Kevin Chyn    private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
179ee82f8fa2d47fc1dbfc29582ae348b3c45ff8fe0Jim Miller
180c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos    /**
181c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos     * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
182c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos     *
183c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos     * This returns the lazily-peristed value and should only be used by TrustManagerService.
184c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos     */
185c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos    public boolean isTrustUsuallyManaged(int userId) {
186c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
187c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos            throw new IllegalStateException("May only be called by TrustManagerService. "
188c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos                    + "Use TrustManager.isTrustUsuallyManaged()");
189c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        }
190c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        try {
191c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos            return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
192c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        } catch (RemoteException e) {
193c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos            return false;
194c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        }
195c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos    }
196c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos
197c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos    public void setTrustUsuallyManaged(boolean managed, int userId) {
198c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        try {
199c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos            getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
200c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        } catch (RemoteException e) {
201c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos            // System dead.
202c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos        }
203c13723f22e476b4558061942c001ee62eaca79e4Adrian Roos    }
2042397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales
2054ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos    public void userPresent(int userId) {
2064ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos        try {
2074ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos            getLockSettings().userPresent(userId);
2084ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos        } catch (RemoteException e) {
2094ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos            throw e.rethrowFromSystemServer();
2104ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos        }
2114ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos    }
2124ab7e595a5deef72448da950f2f973bc0c90fe18Adrian Roos
2132397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales    public static final class RequestThrottledException extends Exception {
2142397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        private int mTimeoutMs;
2152397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        public RequestThrottledException(int timeoutMs) {
2162397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            mTimeoutMs = timeoutMs;
2172397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        }
2182397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales
2192397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        /**
2202397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales         * @return The amount of time in ms before another request may
2212397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales         * be executed
2222397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales         */
2232397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        public int getTimeoutMs() {
2242397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            return mTimeoutMs;
2252397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        }
2262397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales
2272397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales    }
2282397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales
229cd70988401be5919e8d1889727bb01c91d56627cJim Miller    public DevicePolicyManager getDevicePolicyManager() {
2305b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller        if (mDevicePolicyManager == null) {
2315b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller            mDevicePolicyManager =
2325b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller                (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
2335b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller            if (mDevicePolicyManager == null) {
2345b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller                Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
2355b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller                        new IllegalStateException("Stack trace:"));
2365b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller            }
2375b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller        }
2385b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller        return mDevicePolicyManager;
2395b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller    }
24052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
241a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    private UserManager getUserManager() {
242a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri        if (mUserManager == null) {
243a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri            mUserManager = UserManager.get(mContext);
244a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri        }
245a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri        return mUserManager;
246a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    }
247a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri
24882142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    private TrustManager getTrustManager() {
24982142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
25082142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        if (trust == null) {
25182142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            Log.e(TAG, "Can't get TrustManagerService: is it running?",
25282142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos                    new IllegalStateException("Stack trace:"));
25382142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        }
25482142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        return trust;
25582142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    }
25682142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos
25731f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller    public LockPatternUtils(Context context) {
258df83afaf299666e99c519aa86e7e082b7c116e95Dianne Hackborn        mContext = context;
25931f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller        mContentResolver = context.getContentResolver();
2607a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos
2617a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos        Looper looper = Looper.myLooper();
2627a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos        mHandler = looper != null ? new Handler(looper) : null;
26352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
26490881005182936e443cb6cd9fb7eff21f83206f5Brad Fitzpatrick
2650cbc19e4a66f7db51596b57ca91afc6f5b27f3b4Rubin Xu    @VisibleForTesting
2660cbc19e4a66f7db51596b57ca91afc6f5b27f3b4Rubin Xu    public ILockSettings getLockSettings() {
26752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if (mLockSettingsService == null) {
268450ce9fc8a1522819aec151433e6f509dfe60690Adrian Roos            ILockSettings service = ILockSettings.Stub.asInterface(
269450ce9fc8a1522819aec151433e6f509dfe60690Adrian Roos                    ServiceManager.getService("lock_settings"));
270138b83347b8da29166ee2eb09fa8126686bda3c7Adrian Roos            mLockSettingsService = service;
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return mLockSettingsService;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2758150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedMinimumPasswordLength(int userId) {
2768150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumLength(null, userId);
27731f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller    }
27831f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller
27931f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller    /**
28031f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller     * Gets the device policy password mode. If the mode is non-specific, returns
28131f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller     * MODE_PATTERN which allows the user to choose anything.
28231f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller     */
2838150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordQuality(int userId) {
2848150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordQuality(null, userId);
2859dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    }
2869dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
2879dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    private int getRequestedPasswordHistoryLength(int userId) {
2889dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
2893255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev    }
2903255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev
2918150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordMinimumLetters(int userId) {
2928150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumLetters(null, userId);
293a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev    }
294a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev
2958150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordMinimumUpperCase(int userId) {
2968150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumUpperCase(null, userId);
297a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev    }
298a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev
2998150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordMinimumLowerCase(int userId) {
3008150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumLowerCase(null, userId);
301a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev    }
302a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev
3038150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordMinimumNumeric(int userId) {
3048150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumNumeric(null, userId);
305a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev    }
306a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev
3078150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordMinimumSymbols(int userId) {
3088150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumSymbols(null, userId);
309a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev    }
310a15dcfaf2bc7cbd13b30db6766afe3bbaa01db97Konstantin Lopyrev
3118150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public int getRequestedPasswordMinimumNonLetter(int userId) {
3128150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getDevicePolicyManager().getPasswordMinimumNonLetter(null, userId);
313c857740f242169f2ca7fd42f0d1268661b399ad6Konstantin Lopyrev    }
314599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani
3158150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public void reportFailedPasswordAttempt(int userId) {
3162adc263ce97ae6c8291653490868879841d31a63Adrian Roos        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
3177374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos            return;
3187374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos        }
3194f994eb2ddbe68b0eada89dcaae34c079df55c7eAdrian Roos        getDevicePolicyManager().reportFailedPasswordAttempt(userId);
3204f994eb2ddbe68b0eada89dcaae34c079df55c7eAdrian Roos        getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
32131f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller    }
32231f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller
3238150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public void reportSuccessfulPasswordAttempt(int userId) {
3242adc263ce97ae6c8291653490868879841d31a63Adrian Roos        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
3257374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos            return;
3267374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos        }
3278150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
3288150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
32931f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller    }
33031f90b62e8c83270094f5b0b4c75a0e06d72cd75Jim Miller
331327323d2b337077433fe02438a79cc98e91799e3Zachary Iqbal    public void reportPasswordLockout(int timeoutMs, int userId) {
3322adc263ce97ae6c8291653490868879841d31a63Adrian Roos        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
3337374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos            return;
3347374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos        }
335327323d2b337077433fe02438a79cc98e91799e3Zachary Iqbal        getTrustManager().reportUnlockLockout(timeoutMs, userId);
336327323d2b337077433fe02438a79cc98e91799e3Zachary Iqbal    }
337327323d2b337077433fe02438a79cc98e91799e3Zachary Iqbal
33851e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri    public int getCurrentFailedPasswordAttempts(int userId) {
3392adc263ce97ae6c8291653490868879841d31a63Adrian Roos        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
3407374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos            return 0;
3417374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos        }
34251e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri        return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
34351e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri    }
34451e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri
34551e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri    public int getMaximumFailedPasswordsForWipe(int userId) {
3462adc263ce97ae6c8291653490868879841d31a63Adrian Roos        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
3477374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos            return 0;
3487374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos        }
34951e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri        return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
35051e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri                null /* componentName */, userId);
35151e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri    }
35251e41ad887a2e30a1366f0a3b4750f0204912b8eClara Bayarri
3531de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    private byte[] verifyCredential(String credential, int type, long challenge, int userId)
3542397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            throws RequestThrottledException {
355d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales        try {
3561de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
3571de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                    type, challenge, userId);
3582397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
3592397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales                return response.getPayload();
3602397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
3612397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales                throw new RequestThrottledException(response.getTimeout());
3622397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            } else {
3632397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales                return null;
3642397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            }
365d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales        } catch (RemoteException re) {
366d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales            return null;
367d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales        }
368d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales    }
369d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales
3701de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    private boolean checkCredential(String credential, int type, int userId,
3711de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            @Nullable CheckCredentialProgressCallback progressCallback)
3721de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            throws RequestThrottledException {
3731de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        try {
3741de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,
3751de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                    userId, wrapCallback(progressCallback));
3761de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
3771de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
3781de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                return true;
3791de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
3801de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                throw new RequestThrottledException(response.getTimeout());
3811de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            } else {
3821de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                return false;
3831de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            }
3841de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        } catch (RemoteException re) {
3851de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            return false;
3861de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        }
3871de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    }
3881de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
3891de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    /**
3901de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * Check to see if a pattern matches the saved pattern.
3911de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * If pattern matches, return an opaque attestation that the challenge
3921de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * was verified.
3931de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     *
3941de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * @param pattern The pattern to check.
3951de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * @param challenge The challenge to verify against the pattern
3961de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     * @return the attestation that the challenge was verified, or null.
3971de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu     */
3981de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
3991de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu            throws RequestThrottledException {
4001de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        throwIfCalledOnMainThread();
4011de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
4021de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                userId);
4031de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu    }
4041de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu
405d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales    /**
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Check to see if a pattern matches the saved pattern.  If no pattern exists,
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * always returns true.
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pattern The pattern to check.
40969aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @return Whether the pattern matches the stored one.
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4112397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales    public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
4122397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            throws RequestThrottledException {
413e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        return checkPattern(pattern, userId, null /* progressCallback */);
414e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    }
415e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi
416e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    /**
417e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * Check to see if a pattern matches the saved pattern.  If no pattern exists,
418e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * always returns true.
419e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * @param pattern The pattern to check.
420e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * @return Whether the pattern matches the stored one.
421e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     */
422e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,
423e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            @Nullable CheckCredentialProgressCallback progressCallback)
424e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            throws RequestThrottledException {
425aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia        throwIfCalledOnMainThread();
4261de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
4271de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                progressCallback);
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
431d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     * Check to see if a password matches the saved password.
432d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     * If password matches, return an opaque attestation that the challenge
433d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     * was verified.
434d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     *
435d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     * @param password The password to check.
436d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     * @param challenge The challenge to verify against the password
437d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     * @return the attestation that the challenge was verified, or null.
438d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales     */
4392397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales    public byte[] verifyPassword(String password, long challenge, int userId)
4402397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            throws RequestThrottledException {
441aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia        throwIfCalledOnMainThread();
4421de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
44353940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai    }
44453940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai
44553940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai
44653940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai    /**
44753940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     * Check to see if a password matches the saved password.
44853940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     * If password matches, return an opaque attestation that the challenge
44953940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     * was verified.
45053940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     *
45153940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     * @param password The password to check.
45253940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     * @param challenge The challenge to verify against the password
45353940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     * @return the attestation that the challenge was verified, or null.
45453940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai     */
45553940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai    public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
45653940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai            int userId) throws RequestThrottledException {
45753940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai        throwIfCalledOnMainThread();
45853940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai        try {
45953940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai            VerifyCredentialResponse response =
4601de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                    getLockSettings().verifyTiedProfileChallenge(password,
4611de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu                            isPattern ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_PASSWORD, challenge,
46253940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai                            userId);
46353940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai
46453940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
46553940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai                return response.getPayload();
46653940d4c7f45a26d8b571982a1f8f4b8094aa5e0Ricky Wai            } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
4672397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales                throw new RequestThrottledException(response.getTimeout());
4682397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            } else {
4692397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales                return null;
4702397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales            }
471d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales        } catch (RemoteException re) {
472d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales            return null;
473d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales        }
474d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales    }
475d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales
476d9fc85ac27742adbe89e54fd35f3cb2469e94b91Andres Morales    /**
47769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * Check to see if a password matches the saved password.  If no password exists,
47869aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * always returns true.
47969aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @param password The password to check.
48069aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @return Whether the password matches the stored one.
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4822397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales    public boolean checkPassword(String password, int userId) throws RequestThrottledException {
483e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        return checkPassword(password, userId, null /* progressCallback */);
484e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    }
485e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi
486e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    /**
487e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * Check to see if a password matches the saved password.  If no password exists,
488e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * always returns true.
489e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * @param password The password to check.
490e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * @return Whether the password matches the stored one.
491e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     */
492e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    public boolean checkPassword(String password, int userId,
493e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            @Nullable CheckCredentialProgressCallback progressCallback)
494e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            throws RequestThrottledException {
495aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia        throwIfCalledOnMainThread();
4961de89b3bec2f296763f3ecde9a36ecbca2110f3dRubin Xu        return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
49769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    }
49869aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
49969aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    /**
500945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence     * Check to see if vold already has the password.
501945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence     * Note that this also clears vold's copy of the password.
502945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence     * @return Whether the vold password matches or not.
503945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence     */
5048150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public boolean checkVoldPassword(int userId) {
505945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence        try {
506945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence            return getLockSettings().checkVoldPassword(userId);
507945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence        } catch (RemoteException re) {
508945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence            return false;
509945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence        }
510945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence    }
511945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence
512945490c12e32b1c13b9097c00702558260b2011fPaul Lawrence    /**
513f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * Returns the password history hash factor, needed to check new password against password
514f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * history with {@link #checkPasswordHistory(String, byte[], int)}
515f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     */
516f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
517f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        try {
518f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return getLockSettings().getHashFactor(currentPassword, userId);
519f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        } catch (RemoteException e) {
520f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            Log.e(TAG, "failed to get hash factor", e);
521f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return null;
522f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        }
523f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    }
524f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu
525f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    /**
526863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev     * Check to see if a password matches any of the passwords stored in the
527863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev     * password history.
528863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev     *
529f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * @param passwordToCheck The password to check.
530f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * @param hashFactor Hash factor of the current user returned from
531f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     *        {@link ILockSettings#getHashFactor}
532863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev     * @return Whether the password matches any in the history.
533863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev     */
534f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
535f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        if (TextUtils.isEmpty(passwordToCheck)) {
536f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            Log.e(TAG, "checkPasswordHistory: empty password");
537f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return false;
538f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        }
539dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos        String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
540f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        if (TextUtils.isEmpty(passwordHistory)) {
5413255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev            return false;
5423255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev        }
5438150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        int passwordHistoryLength = getRequestedPasswordHistoryLength(userId);
5443255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev        if(passwordHistoryLength == 0) {
5453255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev            return false;
5463255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev        }
547f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        String legacyHash = legacyPasswordToHash(passwordToCheck, userId);
548f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId);
549f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        String[] history = passwordHistory.split(HISTORY_DELIMITER);
550f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        // Password History may be too long...
551f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) {
552f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) {
553f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                return true;
554f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            }
5553255823de062e981f7bfc7994919207988697e45Konstantin Lopyrev        }
556f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        return false;
557863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev    }
558863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev
559863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev    /**
56069aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * Check to see if the user has stored a lock pattern.
56169aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @return Whether a saved pattern exists.
56269aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     */
5639dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    private boolean savedPatternExists(int userId) {
56452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
56550bfeec868157106e8b60abf8964cb24462af182Adrian Roos            return getLockSettings().havePattern(userId);
56652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
56752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return false;
56852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
56969aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    }
57069aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
57169aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    /**
57269aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * Check to see if the user has stored a lock pattern.
57369aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @return Whether a saved pattern exists.
57469aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     */
5759dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    private boolean savedPasswordExists(int userId) {
57652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
57750bfeec868157106e8b60abf8964cb24462af182Adrian Roos            return getLockSettings().havePassword(userId);
57852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
57952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return false;
58052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
58169aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    }
58269aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
58369aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    /**
584ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project     * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
585ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project     * currently cleared.
586ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project     *
587ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project     * @return True if the user has ever chosen a pattern.
588ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project     */
5898150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public boolean isPatternEverChosen(int userId) {
5908150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
591dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos    }
592dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos
593dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos    /**
594e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney     * Records that the user has chosen a pattern at some time, even if the pattern is
595e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney     * currently cleared.
596e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney     */
597e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    public void reportPatternWasChosen(int userId) {
598e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney        setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
599e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    }
600e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney
601e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    /**
602dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos     * Used by device policy manager to validate the current password
603dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos     * information it has.
604dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos     */
605dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos    public int getActivePasswordQuality(int userId) {
6069dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        int quality = getKeyguardStoredPasswordQuality(userId);
6079dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
6089dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        if (isLockPasswordEnabled(quality, userId)) {
6099dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            // Quality is a password and a password exists. Return the quality.
6109dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            return quality;
6119dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        }
6129dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
6139dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        if (isLockPatternEnabled(quality, userId)) {
6149dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            // Quality is a pattern and a pattern exists. Return the quality.
6159dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            return quality;
61685f2c9ce5a0e074df2429a5d66e1754e368a0430Dianne Hackborn        }
617c8fb532d456b009e61d38e919277e00939cf894aDanielle Millett
618682d16758010e311910133fb40868133c05b3fe6Rubin Xu        return PASSWORD_QUALITY_UNSPECIFIED;
61985f2c9ce5a0e074df2429a5d66e1754e368a0430Dianne Hackborn    }
620cd70988401be5919e8d1889727bb01c91d56627cJim Miller
62185f2c9ce5a0e074df2429a5d66e1754e368a0430Dianne Hackborn    /**
6224613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai     * Use it to reset keystore without wiping work profile
6234613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai     */
6244613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai    public void resetKeyStore(int userId) {
6254613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai        try {
6264613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai            getLockSettings().resetKeyStore(userId);
6274613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai        } catch (RemoteException e) {
6284613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai            // It should not happen
6294613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai            Log.e(TAG, "Couldn't reset keystore " + e);
6304613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai        }
6314613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai    }
6324613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai
6334613fe41ac9e817e76d7087de45bf01f4a6584d6Ricky Wai    /**
634df83afaf299666e99c519aa86e7e082b7c116e95Dianne Hackborn     * Clear any lock pattern or password.
635df83afaf299666e99c519aa86e7e082b7c116e95Dianne Hackborn     */
636a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu    public void clearLock(String savedCredential, int userHandle) {
637682d16758010e311910133fb40868133c05b3fe6Rubin Xu        final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
638682d16758010e311910133fb40868133c05b3fe6Rubin Xu        setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
6399dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
640a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        try{
641a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu            getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
642682d16758010e311910133fb40868133c05b3fe6Rubin Xu                    PASSWORD_QUALITY_UNSPECIFIED, userHandle);
643682d16758010e311910133fb40868133c05b3fe6Rubin Xu        } catch (Exception e) {
644682d16758010e311910133fb40868133c05b3fe6Rubin Xu            Log.e(TAG, "Failed to clear lock", e);
645682d16758010e311910133fb40868133c05b3fe6Rubin Xu            setKeyguardStoredPasswordQuality(currentQuality, userHandle);
646682d16758010e311910133fb40868133c05b3fe6Rubin Xu            return;
6479dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        }
6489dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
64986c69ddefd503e93887d7728b5ce072522747527Xiaohui Chen        if (userHandle == UserHandle.USER_SYSTEM) {
6509dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            // Set the encryption password to default.
6519dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
652d39113ea00b650f5778ed3d5dea6664c5d06f5b4Robin Lee            setCredentialRequiredToDecrypt(false);
6539dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        }
6549dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
655f8f56bce428bb2b89d1d572ccd2d604761dbbce8Adrian Roos        onAfterChangingPassword(userHandle);
656df83afaf299666e99c519aa86e7e082b7c116e95Dianne Hackborn    }
6575b0fb3a7e8070ed366a85acc1904d2f34030445dJim Miller
658df83afaf299666e99c519aa86e7e082b7c116e95Dianne Hackborn    /**
65951ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * Disable showing lock screen at all for a given user.
66051ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * This is only meaningful if pattern, pin or password are not set.
6612a98a4cbaaf3300036434dd1d44b891ea8a8c932Jim Miller     *
66251ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * @param disable Disables lock screen when true
66351ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * @param userId User ID of the user this has effect on
66451ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     */
66551ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz    public void setLockScreenDisabled(boolean disable, int userId) {
66651ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz        setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
66751ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz    }
66851ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz
66951ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz    /**
67051ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * Determine if LockScreen is disabled for the current user. This is used to decide whether
67151ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * LockScreen is shown after reboot or after screen timeout / short press on power.
67251ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     *
67351ed794e2f4489c57e1e854fa872aef352d6c28aBenjamin Franz     * @return true if lock screen is disabled
6742a98a4cbaaf3300036434dd1d44b891ea8a8c932Jim Miller     */
6758150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public boolean isLockScreenDisabled(int userId) {
6762eff745087f71ec9f5909bec272cda1132462609Evan Rosky        if (isSecure(userId)) {
6772eff745087f71ec9f5909bec272cda1132462609Evan Rosky            return false;
6782eff745087f71ec9f5909bec272cda1132462609Evan Rosky        }
6792eff745087f71ec9f5909bec272cda1132462609Evan Rosky        boolean disabledByDefault = mContext.getResources().getBoolean(
6802eff745087f71ec9f5909bec272cda1132462609Evan Rosky                com.android.internal.R.bool.config_disableLockscreenByDefault);
6812eff745087f71ec9f5909bec272cda1132462609Evan Rosky        boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
6825856be889f5e631eea822e13e560fd386c3907b8Christine Franks        UserInfo userInfo = getUserManager().getUserInfo(userId);
6835856be889f5e631eea822e13e560fd386c3907b8Christine Franks        boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
6845856be889f5e631eea822e13e560fd386c3907b8Christine Franks                && userInfo.isDemo();
6852eff745087f71ec9f5909bec272cda1132462609Evan Rosky        return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
6865856be889f5e631eea822e13e560fd386c3907b8Christine Franks                || (disabledByDefault && !isSystemUser)
6875856be889f5e631eea822e13e560fd386c3907b8Christine Franks                || isDemoUser;
6882a98a4cbaaf3300036434dd1d44b891ea8a8c932Jim Miller    }
6892a98a4cbaaf3300036434dd1d44b891ea8a8c932Jim Miller
6902a98a4cbaaf3300036434dd1d44b891ea8a8c932Jim Miller    /**
6916edf2637e96139735df83907c221cce16d4d7eaaJim Miller     * Save a lock pattern.
6926edf2637e96139735df83907c221cce16d4d7eaaJim Miller     * @param pattern The new pattern to save.
6938150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos     * @param userId the user whose pattern is to be saved.
6942364a222fcba233d66d0a9cde691d1d6e82227dbDanielle Millett     */
6958fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
6968fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales        this.saveLockPattern(pattern, null, userId);
6978fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales    }
6982364a222fcba233d66d0a9cde691d1d6e82227dbDanielle Millett    /**
6992364a222fcba233d66d0a9cde691d1d6e82227dbDanielle Millett     * Save a lock pattern.
7002364a222fcba233d66d0a9cde691d1d6e82227dbDanielle Millett     * @param pattern The new pattern to save.
7018fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales     * @param savedPattern The previously saved pattern, converted to String format
702f8f56bce428bb2b89d1d572ccd2d604761dbbce8Adrian Roos     * @param userId the user whose pattern is to be saved.
703f8f56bce428bb2b89d1d572ccd2d604761dbbce8Adrian Roos     */
7048fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales    public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
705682d16758010e311910133fb40868133c05b3fe6Rubin Xu        if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
706682d16758010e311910133fb40868133c05b3fe6Rubin Xu            throw new IllegalArgumentException("pattern must not be null and at least "
707682d16758010e311910133fb40868133c05b3fe6Rubin Xu                    + MIN_LOCK_PATTERN_SIZE + " dots long.");
708682d16758010e311910133fb40868133c05b3fe6Rubin Xu        }
7099dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
710682d16758010e311910133fb40868133c05b3fe6Rubin Xu        final String stringPattern = patternToString(pattern);
711682d16758010e311910133fb40868133c05b3fe6Rubin Xu        final int currentQuality = getKeyguardStoredPasswordQuality(userId);
712682d16758010e311910133fb40868133c05b3fe6Rubin Xu        setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
713682d16758010e311910133fb40868133c05b3fe6Rubin Xu        try {
714682d16758010e311910133fb40868133c05b3fe6Rubin Xu            getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
715682d16758010e311910133fb40868133c05b3fe6Rubin Xu                    savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
716682d16758010e311910133fb40868133c05b3fe6Rubin Xu        } catch (Exception e) {
717682d16758010e311910133fb40868133c05b3fe6Rubin Xu            Log.e(TAG, "Couldn't save lock pattern", e);
718682d16758010e311910133fb40868133c05b3fe6Rubin Xu            setKeyguardStoredPasswordQuality(currentQuality, userId);
719682d16758010e311910133fb40868133c05b3fe6Rubin Xu            return;
720682d16758010e311910133fb40868133c05b3fe6Rubin Xu        }
721682d16758010e311910133fb40868133c05b3fe6Rubin Xu        // Update the device encryption password.
722682d16758010e311910133fb40868133c05b3fe6Rubin Xu        if (userId == UserHandle.USER_SYSTEM
723682d16758010e311910133fb40868133c05b3fe6Rubin Xu                && LockPatternUtils.isDeviceEncryptionEnabled()) {
724682d16758010e311910133fb40868133c05b3fe6Rubin Xu            if (!shouldEncryptWithCredentials(true)) {
725682d16758010e311910133fb40868133c05b3fe6Rubin Xu                clearEncryptionPassword();
726682d16758010e311910133fb40868133c05b3fe6Rubin Xu            } else {
727682d16758010e311910133fb40868133c05b3fe6Rubin Xu                updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
7289dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            }
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
730682d16758010e311910133fb40868133c05b3fe6Rubin Xu
731682d16758010e311910133fb40868133c05b3fe6Rubin Xu        reportPatternWasChosen(userId);
732682d16758010e311910133fb40868133c05b3fe6Rubin Xu        onAfterChangingPassword(userId);
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7359dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    private void updateCryptoUserInfo(int userId) {
73686c69ddefd503e93887d7728b5ce072522747527Xiaohui Chen        if (userId != UserHandle.USER_SYSTEM) {
737e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence            return;
738e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        }
739e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence
7409dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
741e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence
742e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        IBinder service = ServiceManager.getService("mount");
743e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        if (service == null) {
744e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence            Log.e(TAG, "Could not find the mount service to update the user info");
745e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence            return;
746e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        }
747e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence
7482250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka        IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
749e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        try {
750e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence            Log.d(TAG, "Setting owner info");
7512250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka            storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
752e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        } catch (RemoteException e) {
753e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence            Log.e(TAG, "Error changing user info", e);
754e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence        }
755e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence    }
756e51dcf98a4ddb1340cffba88059ad89f0b90909aPaul Lawrence
757187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    public void setOwnerInfo(String info, int userId) {
758187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller        setString(LOCK_SCREEN_OWNER_INFO, info, userId);
7599dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        updateCryptoUserInfo(userId);
760187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    }
761187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
7628150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public void setOwnerInfoEnabled(boolean enabled, int userId) {
7639dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
7649dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        updateCryptoUserInfo(userId);
765187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    }
766187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
767187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    public String getOwnerInfo(int userId) {
768dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos        return getString(LOCK_SCREEN_OWNER_INFO, userId);
769187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    }
770187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
7718150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public boolean isOwnerInfoEnabled(int userId) {
7729dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
773187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller    }
774187ec581c66fec49a5ee7db8edec6d9eb0e209fcJim Miller
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7766644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu     * Sets the device owner information. If the information is {@code null} or empty then the
7776644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu     * device owner info is cleared.
7786644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu     *
7796644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu     * @param info Device owner information which will be displayed instead of the user
7806644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu     * owner info.
7816644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu     */
7826644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    public void setDeviceOwnerInfo(String info) {
7836644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu        if (info != null && info.isEmpty()) {
7846644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu            info = null;
7856644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu        }
7866644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu
7876644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu        setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
7886644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    }
7896644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu
7906644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    public String getDeviceOwnerInfo() {
7916644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu        return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
7926644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    }
7936644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu
7946644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    public boolean isDeviceOwnerInfoEnabled() {
7956644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu        return getDeviceOwnerInfo() != null;
7966644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu    }
7976644cd9630be363a25af5e1327f41e16ca868556Andrei Stingaceanu
798f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    /** Update the encryption password if it is enabled **/
7993a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence    private void updateEncryptionPassword(final int type, final String password) {
800cd410ba4e816b657020cafb23e69206734726b42Amith Yamasani        if (!isDeviceEncryptionEnabled()) {
801f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return;
802f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
8033a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence        final IBinder service = ServiceManager.getService("mount");
804f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (service == null) {
805f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            Log.e(TAG, "Could not find the mount service to update the encryption password");
806f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return;
807f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
808f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
8093a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence        new AsyncTask<Void, Void, Void>() {
8103a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence            @Override
8113a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence            protected Void doInBackground(Void... dummy) {
8122250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka                IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
8133a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence                try {
8142250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka                    storageManager.changeEncryptionPassword(type, password);
8153a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence                } catch (RemoteException e) {
8163a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence                    Log.e(TAG, "Error changing encryption password", e);
8173a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence                }
8183a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence                return null;
8193a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence            }
8203a5a0be61ec7ea08884c80817c226f7cfe531a67Paul Lawrence        }.execute();
821f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    }
822f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
8239327f4f671de3cbb795612bf4f314ceff88de865Dianne Hackborn    /**
824cd70988401be5919e8d1889727bb01c91d56627cJim Miller     * Save a lock password.  Does not ensure that the password is as good
8259327f4f671de3cbb795612bf4f314ceff88de865Dianne Hackborn     * as the requested mode, but will adjust the mode to be as good as the
8268150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos     * password.
82769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @param password The password to save
8288fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales     * @param savedPassword The previously saved lock password, or null if none
8297374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos     * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
830599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani     * @param userHandle The userId of the user to change the password for
831599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani     */
8327374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos    public void saveLockPassword(String password, String savedPassword, int requestedQuality,
8338fa5665f0e757cec0063fb4cf1354f1596f93a91Andres Morales            int userHandle) {
834682d16758010e311910133fb40868133c05b3fe6Rubin Xu        if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
835682d16758010e311910133fb40868133c05b3fe6Rubin Xu            throw new IllegalArgumentException("password must not be null and at least "
836682d16758010e311910133fb40868133c05b3fe6Rubin Xu                    + "of length " + MIN_LOCK_PASSWORD_SIZE);
837682d16758010e311910133fb40868133c05b3fe6Rubin Xu        }
8389dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
839682d16758010e311910133fb40868133c05b3fe6Rubin Xu        final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
840682d16758010e311910133fb40868133c05b3fe6Rubin Xu        setKeyguardStoredPasswordQuality(
841682d16758010e311910133fb40868133c05b3fe6Rubin Xu                computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
842682d16758010e311910133fb40868133c05b3fe6Rubin Xu                userHandle);
843682d16758010e311910133fb40868133c05b3fe6Rubin Xu        try {
844682d16758010e311910133fb40868133c05b3fe6Rubin Xu            getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
845682d16758010e311910133fb40868133c05b3fe6Rubin Xu                    savedPassword, requestedQuality, userHandle);
846682d16758010e311910133fb40868133c05b3fe6Rubin Xu        } catch (Exception e) {
847682d16758010e311910133fb40868133c05b3fe6Rubin Xu            Log.e(TAG, "Unable to save lock password", e);
848682d16758010e311910133fb40868133c05b3fe6Rubin Xu            setKeyguardStoredPasswordQuality(currentQuality, userHandle);
849682d16758010e311910133fb40868133c05b3fe6Rubin Xu            return;
85069aa4a953f040277c19c23208bb830f52796c8c6Jim Miller        }
851682d16758010e311910133fb40868133c05b3fe6Rubin Xu
852682d16758010e311910133fb40868133c05b3fe6Rubin Xu        updateEncryptionPasswordIfNeeded(password,
853682d16758010e311910133fb40868133c05b3fe6Rubin Xu                PasswordMetrics.computeForPassword(password).quality, userHandle);
854682d16758010e311910133fb40868133c05b3fe6Rubin Xu        updatePasswordHistory(password, userHandle);
855f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        onAfterChangingPassword(userHandle);
85669aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    }
85769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
858f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    /**
859f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * Update device encryption password if calling user is USER_SYSTEM and device supports
860f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * encryption.
861f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     */
862f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
863a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        // Update the device encryption password.
864a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        if (userHandle == UserHandle.USER_SYSTEM
865a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu                && LockPatternUtils.isDeviceEncryptionEnabled()) {
866a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu            if (!shouldEncryptWithCredentials(true)) {
867a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu                clearEncryptionPassword();
868a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu            } else {
869682d16758010e311910133fb40868133c05b3fe6Rubin Xu                boolean numeric = quality == PASSWORD_QUALITY_NUMERIC;
870682d16758010e311910133fb40868133c05b3fe6Rubin Xu                boolean numericComplex = quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
871a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu                int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
872a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu                        : StorageManager.CRYPT_TYPE_PASSWORD;
873a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu                updateEncryptionPassword(type, password);
874a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu            }
875a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        }
876a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu    }
877a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu
878f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    /**
879f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * Store the hash of the *current* password in the password history list, if device policy
880f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * enforces password history requirement.
881f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     */
882a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu    private void updatePasswordHistory(String password, int userHandle) {
883f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        if (TextUtils.isEmpty(password)) {
884f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            Log.e(TAG, "checkPasswordHistory: empty password");
885f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return;
886f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        }
887a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        // Add the password to the password history. We assume all
888a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        // password hashes have the same length for simplicity of implementation.
889a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
890a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        if (passwordHistory == null) {
891a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu            passwordHistory = "";
892a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        }
893a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
894a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        if (passwordHistoryLength == 0) {
895a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu            passwordHistory = "";
896a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        } else {
897f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle);
898f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            String hash = passwordToHistoryHash(password, hashFactor, userHandle);
899f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            if (hash == null) {
900f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                Log.e(TAG, "Compute new style password hash failed, fallback to legacy style");
901f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                hash = legacyPasswordToHash(password, userHandle);
902f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            }
903f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            if (TextUtils.isEmpty(passwordHistory)) {
904f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                passwordHistory = hash;
905f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            } else {
906f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                String[] history = passwordHistory.split(HISTORY_DELIMITER);
907f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER);
908f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                joiner.add(hash);
909f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
910f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                    joiner.add(history[i]);
911f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                }
912f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu                passwordHistory = joiner.toString();
913f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            }
914a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        }
915a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu        setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
916a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu    }
917a55b168b5d5a0584b2411793f870a7849c5014f1Rubin Xu
918cd70988401be5919e8d1889727bb01c91d56627cJim Miller    /**
9196848dc8e3b54fb27047836d8026c4c9971754607Jim Miller     * Determine if the device supports encryption, even if it's set to default. This
9206848dc8e3b54fb27047836d8026c4c9971754607Jim Miller     * differs from isDeviceEncrypted() in that it returns true even if the device is
9216848dc8e3b54fb27047836d8026c4c9971754607Jim Miller     * encrypted with the default password.
9226848dc8e3b54fb27047836d8026c4c9971754607Jim Miller     * @return true if device encryption is enabled
9236848dc8e3b54fb27047836d8026c4c9971754607Jim Miller     */
9246848dc8e3b54fb27047836d8026c4c9971754607Jim Miller    public static boolean isDeviceEncryptionEnabled() {
92520be5d62471d520eed3a52d90c11944464a71c07Paul Lawrence        return StorageManager.isEncrypted();
9266848dc8e3b54fb27047836d8026c4c9971754607Jim Miller    }
9276848dc8e3b54fb27047836d8026c4c9971754607Jim Miller
9286848dc8e3b54fb27047836d8026c4c9971754607Jim Miller    /**
9295c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence     * Determine if the device is file encrypted
9305c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence     * @return true if device is file encrypted
9315c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence     */
9325c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence    public static boolean isFileEncryptionEnabled() {
93320be5d62471d520eed3a52d90c11944464a71c07Paul Lawrence        return StorageManager.isFileEncryptedNativeOrEmulated();
9345c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence    }
9355c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence
9365c21c7037192128b2cbcc42c596e290c001f4090Paul Lawrence    /**
93716e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav     * Clears the encryption password.
93816e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav     */
93916e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav    public void clearEncryptionPassword() {
94016e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav        updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
94116e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav    }
94216e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav
94316e4a1aade2b73edfdaa42aa86a3893fd039fc62Svetoslav    /**
9441572ee379e1d070c7ad1c37a626ed25db5341a3eAdrian Roos     * Retrieves the quality mode for {@param userHandle}.
9451572ee379e1d070c7ad1c37a626ed25db5341a3eAdrian Roos     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
9461572ee379e1d070c7ad1c37a626ed25db5341a3eAdrian Roos     *
9471572ee379e1d070c7ad1c37a626ed25db5341a3eAdrian Roos     * @return stored password quality
9481572ee379e1d070c7ad1c37a626ed25db5341a3eAdrian Roos     */
9491572ee379e1d070c7ad1c37a626ed25db5341a3eAdrian Roos    public int getKeyguardStoredPasswordQuality(int userHandle) {
950682d16758010e311910133fb40868133c05b3fe6Rubin Xu        return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
951682d16758010e311910133fb40868133c05b3fe6Rubin Xu    }
952682d16758010e311910133fb40868133c05b3fe6Rubin Xu
953682d16758010e311910133fb40868133c05b3fe6Rubin Xu    private void setKeyguardStoredPasswordQuality(int quality, int userHandle) {
954682d16758010e311910133fb40868133c05b3fe6Rubin Xu        setLong(PASSWORD_TYPE_KEY, quality, userHandle);
9556edf2637e96139735df83907c221cce16d4d7eaaJim Miller    }
9566edf2637e96139735df83907c221cce16d4d7eaaJim Miller
95758396984ef49080d5550919130fc0d869ccf840bDanielle Millett    /**
9587cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * Returns the password quality of the given credential, promoting it to a higher level
9597cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * if DevicePolicyManager has a stronger quality requirement. This value will be written
9607cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * to PASSWORD_TYPE_KEY.
9617cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     */
9627cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu    private int computePasswordQuality(int type, String credential, int requestedQuality) {
9637cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu        final int quality;
9647cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu        if (type == CREDENTIAL_TYPE_PASSWORD) {
9657cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu            int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
9667cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu            quality = Math.max(requestedQuality, computedQuality);
9677cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu        } else if (type == CREDENTIAL_TYPE_PATTERN)  {
968682d16758010e311910133fb40868133c05b3fe6Rubin Xu            quality = PASSWORD_QUALITY_SOMETHING;
9697cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu        } else /* if (type == CREDENTIAL_TYPE_NONE) */ {
970682d16758010e311910133fb40868133c05b3fe6Rubin Xu            quality = PASSWORD_QUALITY_UNSPECIFIED;
9717cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu        }
9727cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu        return quality;
9737cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu    }
9747cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu
9757cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu    /**
976a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri     * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
977a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri     * for user handles that do not belong to a managed profile.
978dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai     *
979dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai     * @param userHandle Managed profile user id
980dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai     * @param enabled True if separate challenge is enabled
981dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai     * @param managedUserPassword Managed profile previous password. Null when {@param enabled} is
982dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai     *            true
983a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri     */
984dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai    public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
985dc283a897680ffd33c4d15535ebe778ba5b42c43Ricky Wai            String managedUserPassword) {
986b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        if (!isManagedProfile(userHandle)) {
987b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            return;
988b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        }
989b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        try {
990b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
991b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov                    managedUserPassword);
992b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            onAfterChangingPassword(userHandle);
993b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        } catch (RemoteException e) {
994b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            Log.e(TAG, "Couldn't update work profile challenge enabled");
995a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri        }
996a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    }
997a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri
998a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    /**
999b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov     * Returns true if {@param userHandle} is a managed profile with separate challenge.
1000a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri     */
1001a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    public boolean isSeparateProfileChallengeEnabled(int userHandle) {
1002b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
1003b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    }
1004b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov
1005b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    /**
1006b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov     * Returns true if {@param userHandle} is a managed profile with unified challenge.
1007b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov     */
1008b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    public boolean isManagedProfileWithUnifiedChallenge(int userHandle) {
1009b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
1010a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    }
1011a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri
1012a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    /**
1013a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri     * Retrieves whether the current DPM allows use of the Profile Challenge.
1014a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri     */
1015a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
1016b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        return isManagedProfile(userHandle)
1017b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov                && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
1018a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    }
1019a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri
1020a1771110d67fa7361f92d92f2e91019882ce3305Clara Bayarri    /**
1021d7693917a7c7348cb12692116d2693314c29e809Clara Bayarri     * Retrieves whether the current profile and device locks can be unified.
1022c4f87e9ceb4d5ce78c1663912bc166e0d41554aaPavel Grafov     * @param userHandle profile user handle.
1023d7693917a7c7348cb12692116d2693314c29e809Clara Bayarri     */
1024d7693917a7c7348cb12692116d2693314c29e809Clara Bayarri    public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
1025c4f87e9ceb4d5ce78c1663912bc166e0d41554aaPavel Grafov        return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle)
1026c4f87e9ceb4d5ce78c1663912bc166e0d41554aaPavel Grafov                && !getUserManager().hasUserRestriction(
1027c4f87e9ceb4d5ce78c1663912bc166e0d41554aaPavel Grafov                        UserManager.DISALLOW_UNIFIED_PASSWORD, UserHandle.of(userHandle));
1028d7693917a7c7348cb12692116d2693314c29e809Clara Bayarri    }
1029d7693917a7c7348cb12692116d2693314c29e809Clara Bayarri
1030b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    private boolean hasSeparateChallenge(int userHandle) {
1031b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        try {
1032b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
1033b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        } catch (RemoteException e) {
1034b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            Log.e(TAG, "Couldn't get separate profile challenge enabled");
1035b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            // Default value is false
1036b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov            return false;
1037b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        }
1038b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    }
1039b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov
1040b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    private boolean isManagedProfile(int userHandle) {
1041b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        final UserInfo info = getUserManager().getUserInfo(userHandle);
1042b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov        return info != null && info.isManagedProfile();
1043b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov    }
1044b31912544661f0ea3d05e07a8250530660101c0bPavel Grafov
1045d7693917a7c7348cb12692116d2693314c29e809Clara Bayarri    /**
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Deserialize a pattern.
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param string The pattern serialized with {@link #patternToString}
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The pattern.
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static List<LockPatternView.Cell> stringToPattern(String string) {
10519dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        if (string == null) {
10529dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos            return null;
10539dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        }
10549dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        List<LockPatternView.Cell> result = Lists.newArrayList();
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final byte[] bytes = string.getBytes();
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < bytes.length; i++) {
1059e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales            byte b = (byte) (bytes[i] - '1');
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result.add(LockPatternView.Cell.of(b / 3, b % 3));
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return result;
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Serialize a pattern.
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pattern The pattern.
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The pattern in string form.
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String patternToString(List<LockPatternView.Cell> pattern) {
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pattern == null) {
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "";
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int patternSize = pattern.size();
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] res = new byte[patternSize];
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < patternSize; i++) {
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LockPatternView.Cell cell = pattern.get(i);
1079e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
1080e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        }
1081e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        return new String(res);
1082e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales    }
1083e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales
1084e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales    public static String patternStringToBaseZero(String pattern) {
1085e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        if (pattern == null) {
1086e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales            return "";
1087e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        }
1088e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        final int patternSize = pattern.length();
1089e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales
1090e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        byte[] res = new byte[patternSize];
1091e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        final byte[] bytes = pattern.getBytes();
1092e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales        for (int i = 0; i < patternSize; i++) {
1093e40bad8cf9397becdf05776c775c8286d3de46faAndres Morales            res[i] = (byte) (bytes[i] - '1');
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new String(res);
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
109769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * at least a second level of protection. First level is that the file
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is in a location only readable by the system process.
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pattern the gesture pattern.
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the hash of the pattern in a byte array.
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1105de1af08dd3a073f007ae4b8a114352cae3775028Jim Miller    public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pattern == null) {
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
110969aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int patternSize = pattern.size();
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] res = new byte[patternSize];
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < patternSize; i++) {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LockPatternView.Cell cell = pattern.get(i);
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MessageDigest md = MessageDigest.getInstance("SHA-1");
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            byte[] hash = md.digest(res);
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return hash;
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (NoSuchAlgorithmException nsa) {
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return res;
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1125987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard    private String getSalt(int userId) {
1126987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0, userId);
112711b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller        if (salt == 0) {
112811b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller            try {
112911b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller                salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
1130987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard                setLong(LOCK_PASSWORD_SALT_KEY, salt, userId);
1131987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard                Log.v(TAG, "Initialized lock password salt for user: " + userId);
113211b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller            } catch (NoSuchAlgorithmException e) {
113311b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller                // Throw an exception rather than storing a password we'll never be able to recover
113411b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller                throw new IllegalStateException("Couldn't get SecureRandom number", e);
113511b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller            }
113611b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller        }
113711b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller        return Long.toHexString(salt);
113811b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller    }
113911b019d07f4de0b25e2f863a7bcaad112d847d56Jim Miller
1140f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    /**
114169aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
114269aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * Not the most secure, but it is at least a second level of protection. First level is that
114369aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * the file is in a location only readable by the system process.
114478108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath     *
114569aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @param password the gesture pattern.
114678108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath     *
114769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     * @return the hash of the pattern in a byte array.
114869aa4a953f040277c19c23208bb830f52796c8c6Jim Miller     */
1149f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    public String legacyPasswordToHash(String password, int userId) {
115069aa4a953f040277c19c23208bb830f52796c8c6Jim Miller        if (password == null) {
115169aa4a953f040277c19c23208bb830f52796c8c6Jim Miller            return null;
115269aa4a953f040277c19c23208bb830f52796c8c6Jim Miller        }
115378108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath
115469aa4a953f040277c19c23208bb830f52796c8c6Jim Miller        try {
1155987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard            byte[] saltedPassword = (password + getSalt(userId)).getBytes();
115678108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
115778108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
115869aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
115978108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            byte[] combined = new byte[sha1.length + md5.length];
116078108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            System.arraycopy(sha1, 0, combined, 0, sha1.length);
116178108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            System.arraycopy(md5, 0, combined, sha1.length, md5.length);
116278108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath
116378108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            final char[] hexEncoded = HexEncoding.encode(combined);
1164f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return new String(hexEncoded);
1165f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        } catch (NoSuchAlgorithmException e) {
1166f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            throw new AssertionError("Missing digest algorithm: ", e);
1167f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        }
1168f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    }
1169f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu
1170f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    /**
1171f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     * Hash the password for password history check purpose.
1172f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu     */
1173f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu    private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) {
1174f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) {
1175f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return null;
1176f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        }
1177f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu        try {
1178f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
1179f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            sha256.update(hashFactor);
1180f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            sha256.update((passwordToHash + getSalt(userId)).getBytes());
1181f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            return new String(HexEncoding.encode(sha256.digest()));
118278108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath        } catch (NoSuchAlgorithmException e) {
118378108a3e52c20ad0a481a8419c2d2c9722b53400Narayan Kamath            throw new AssertionError("Missing digest algorithm: ", e);
118469aa4a953f040277c19c23208bb830f52796c8c6Jim Miller        }
118569aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    }
118669aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
118769aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    /**
11889dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos     * @param userId the user for which to report the value
11899dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos     * @return Whether the lock screen is secured.
11909dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos     */
11919dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    public boolean isSecure(int userId) {
11929dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        int mode = getKeyguardStoredPasswordQuality(userId);
11939dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
1194dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos    }
1195dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos
1196dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos    public boolean isLockPasswordEnabled(int userId) {
11979dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
11989dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    }
11999dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos
12009dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    private boolean isLockPasswordEnabled(int mode, int userId) {
1201682d16758010e311910133fb40868133c05b3fe6Rubin Xu        final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC
1202682d16758010e311910133fb40868133c05b3fe6Rubin Xu                || mode == PASSWORD_QUALITY_NUMERIC
1203682d16758010e311910133fb40868133c05b3fe6Rubin Xu                || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX
1204682d16758010e311910133fb40868133c05b3fe6Rubin Xu                || mode == PASSWORD_QUALITY_ALPHANUMERIC
1205682d16758010e311910133fb40868133c05b3fe6Rubin Xu                || mode == PASSWORD_QUALITY_COMPLEX
1206682d16758010e311910133fb40868133c05b3fe6Rubin Xu                || mode == PASSWORD_QUALITY_MANAGED;
12079dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        return passwordEnabled && savedPasswordExists(userId);
120869aa4a953f040277c19c23208bb830f52796c8c6Jim Miller    }
120969aa4a953f040277c19c23208bb830f52796c8c6Jim Miller
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1211230635efe7ffb09d6dc56bfd9193aa1d89c8a898Adrian Roos     * @return Whether the lock pattern is enabled
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
121350bfeec868157106e8b60abf8964cb24462af182Adrian Roos    public boolean isLockPatternEnabled(int userId) {
12149dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos        return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
1215925a7d8f062c2ef275ccb7579889d6f83d0d378eDanielle Millett    }
1216925a7d8f062c2ef275ccb7579889d6f83d0d378eDanielle Millett
12174614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    @Deprecated
12184614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    public boolean isLegacyLockPatternEnabled(int userId) {
12194614596a395b6c86fff3f35a07edda2e848d743cBryce Lee        // Note: this value should default to {@code true} to avoid any reset that might result.
12204614596a395b6c86fff3f35a07edda2e848d743cBryce Lee        // We must use a special key to read this value, since it will by default return the value
12214614596a395b6c86fff3f35a07edda2e848d743cBryce Lee        // based on the new logic.
12224614596a395b6c86fff3f35a07edda2e848d743cBryce Lee        return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
12234614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    }
12244614596a395b6c86fff3f35a07edda2e848d743cBryce Lee
12254614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    @Deprecated
12264614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    public void setLegacyLockPatternEnabled(int userId) {
12274614596a395b6c86fff3f35a07edda2e848d743cBryce Lee        setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
12284614596a395b6c86fff3f35a07edda2e848d743cBryce Lee    }
12294614596a395b6c86fff3f35a07edda2e848d743cBryce Lee
12309dd16ebcf2a25c189a39b72847d3db2b1189cb4dAdrian Roos    private boolean isLockPatternEnabled(int mode, int userId) {
1231682d16758010e311910133fb40868133c05b3fe6Rubin Xu        return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId);
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the visible pattern is enabled.
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12378150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public boolean isVisiblePatternEnabled(int userId) {
12388150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set whether the visible pattern is enabled.
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12448150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public void setVisiblePatternEnabled(boolean enabled, int userId) {
1245dce0122ea2d27474890d5e18ba4b7e4d06303e53Adrian Roos        setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
1246878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence
1247878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        // Update for crypto if owner
124886c69ddefd503e93887d7728b5ce072522747527Xiaohui Chen        if (userId != UserHandle.USER_SYSTEM) {
1249878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence            return;
1250878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        }
1251878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence
1252878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        IBinder service = ServiceManager.getService("mount");
1253878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        if (service == null) {
1254878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence            Log.e(TAG, "Could not find the mount service to update the user info");
1255878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence            return;
1256878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        }
1257878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence
12582250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka        IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
1259878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        try {
12602250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka            storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
1261878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        } catch (RemoteException e) {
1262878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence            Log.e(TAG, "Error changing pattern visible state", e);
1263878ba0a266246f29e8145612a2a58e5e997b018cPaul Lawrence        }
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1266e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    public boolean isVisiblePatternEverChosen(int userId) {
1267e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney        return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
1268e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    }
1269e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1271d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence     * Set whether the visible password is enabled for cryptkeeper screen.
1272d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence     */
1273d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence    public void setVisiblePasswordEnabled(boolean enabled, int userId) {
1274d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        // Update for crypto if owner
127586c69ddefd503e93887d7728b5ce072522747527Xiaohui Chen        if (userId != UserHandle.USER_SYSTEM) {
1276d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence            return;
1277d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        }
1278d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence
1279d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        IBinder service = ServiceManager.getService("mount");
1280d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        if (service == null) {
1281d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence            Log.e(TAG, "Could not find the mount service to update the user info");
1282d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence            return;
1283d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        }
1284d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence
12852250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka        IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
1286d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        try {
12872250d56a0b47b93016018340c8f4040325aa5611Sudheer Shanka            storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
1288d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        } catch (RemoteException e) {
1289d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence            Log.e(TAG, "Error changing password visible state", e);
1290d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence        }
1291d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence    }
1292d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence
1293d8fdb338918e63bbab2e65bdb2f4d12320a1b24aPaul Lawrence    /**
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether tactile feedback for the pattern is enabled.
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isTactileFeedbackEnabled() {
12975ed9d680409c83fbfd7b617d7f257305d3c34b62Jeff Sharkey        return Settings.System.getIntForUser(mContentResolver,
12985ed9d680409c83fbfd7b617d7f257305d3c34b62Jeff Sharkey                Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * pattern until the deadline has passed.
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the chosen deadline.
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13062397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales    public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
13072397427cb1a0bad8a42e6a342dcf29b31e40a234Andres Morales        final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
1308b7d81d9a20000e3db2b4d2612090c6217f489385Adrian Roos        if (userId == USER_FRP) {
1309b7d81d9a20000e3db2b4d2612090c6217f489385Adrian Roos            // For secure password storage (that is required for FRP), the underlying storage also
1310b7d81d9a20000e3db2b4d2612090c6217f489385Adrian Roos            // enforces the deadline. Since we cannot store settings for the FRP user, don't.
1311b7d81d9a20000e3db2b4d2612090c6217f489385Adrian Roos            return deadline;
1312b7d81d9a20000e3db2b4d2612090c6217f489385Adrian Roos        }
1313a3e5582fac1cc259022c06d027e73c767dc1c117Kevin Chyn        mLockoutDeadlines.put(userId, deadline);
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return deadline;
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The elapsed time in millis in the future when the user is allowed to
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   enter a pattern.
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13228150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public long getLockoutAttemptDeadline(int userId) {
1323a3e5582fac1cc259022c06d027e73c767dc1c117Kevin Chyn        final long deadline = mLockoutDeadlines.get(userId, 0L);
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long now = SystemClock.elapsedRealtime();
1325e3e6d56b94b2c196659e15deffed9dc9028fa974Jorim Jaggi        if (deadline < now && deadline != 0) {
1326a4e23375663ac3a2b6115da71e6711282f03492dAndres Morales            // timeout expired
1327a3e5582fac1cc259022c06d027e73c767dc1c117Kevin Chyn            mLockoutDeadlines.put(userId, 0);
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0L;
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return deadline;
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1333f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller    private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
133452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
1335f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
133652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
133752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return defaultValue;
133852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1341f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller    private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
134252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
1343f45bb403884f30ecb383698ef1bcb1c7dc1964b8Jim Miller            getLockSettings().setBoolean(secureSettingKey, enabled, userId);
134452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
134552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // What can we do?
134652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
134752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1350987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard    private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
1351987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard        try {
1352987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard            return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
1353987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard        } catch (RemoteException re) {
1354987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard            return defaultValue;
1355987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard        }
1356987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard    }
1357987672d2621fa5278dbf48cbef46c50d3fafe4c1Geoffrey Borggaard
1358599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani    private void setLong(String secureSettingKey, long value, int userHandle) {
135952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
13600cf13701d69c79ccd4011472e5c58bf9b4a24726Kenny Guy            getLockSettings().setLong(secureSettingKey, value, userHandle);
136152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
136252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // What can we do?
136352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
136452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1367599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani    private String getString(String secureSettingKey, int userHandle) {
136852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
1369599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani            return getLockSettings().getString(secureSettingKey, null, userHandle);
137052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
137152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return null;
137252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
1373863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev    }
1374863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev
1375599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani    private void setString(String secureSettingKey, String value, int userHandle) {
137652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
1377599dd7ce9adf8ca067cefb0b191a5ac20ec35a79Amith Yamasani            getLockSettings().setString(secureSettingKey, value, userHandle);
137852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
137952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // What can we do?
138052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
138152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
1382863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev    }
1383863f22d0451d52cbcccc252ad29858ef1578e709Konstantin Lopyrev
13848150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public void setPowerButtonInstantlyLocks(boolean enabled, int userId) {
13858150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, userId);
138682142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    }
138782142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos
13888150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos    public boolean getPowerButtonInstantlyLocks(int userId) {
13898150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true, userId);
139082142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    }
139182142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos
1392e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    public boolean isPowerButtonInstantlyLocksEverChosen(int userId) {
1393e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney        return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
1394e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney    }
1395e483b56ea8454886a892a6840d3f71ce9fd5becfBryan Mawhinney
139682142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
139782142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        StringBuilder sb = new StringBuilder();
139882142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        for (ComponentName cn : activeTrustAgents) {
139982142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            if (sb.length() > 0) {
140082142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos                sb.append(',');
140182142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            }
140282142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            sb.append(cn.flattenToShortString());
140382142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        }
140482142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
14058150d2a2a12b38598fd55d8ae3c3b5662ec3520fAdrian Roos        getTrustManager().reportEnabledTrustAgentsChanged(userId);
140682142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    }
140782142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos
140882142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    public List<ComponentName> getEnabledTrustAgents(int userId) {
140982142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        String serialized = getString(ENABLED_TRUST_AGENTS, userId);
141082142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        if (TextUtils.isEmpty(serialized)) {
141182142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            return null;
141282142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        }
141382142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        String[] split = serialized.split(",");
141482142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
141582142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        for (String s : split) {
141682142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            if (!TextUtils.isEmpty(s)) {
141782142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos                activeTrustAgents.add(ComponentName.unflattenFromString(s));
141882142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos            }
141982142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        }
142082142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos        return activeTrustAgents;
142182142c21dd333307682d5f4bb09de3ab3ccfa06cAdrian Roos    }
14222c12cfa1d53b586ae8a8d6aca64a4de771dc85b0Adrian Roos
14232c12cfa1d53b586ae8a8d6aca64a4de771dc85b0Adrian Roos    /**
1424b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * Disable trust until credentials have been entered for user {@param userId}.
1425b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     *
1426b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1427b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     *
1428b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
14292c12cfa1d53b586ae8a8d6aca64a4de771dc85b0Adrian Roos     */
14302c12cfa1d53b586ae8a8d6aca64a4de771dc85b0Adrian Roos    public void requireCredentialEntry(int userId) {
143116093fe3f0d824731a53a264a132504deb08421aJorim Jaggi        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
1432b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    }
1433b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1434b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    /**
1435b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * Requests strong authentication for user {@param userId}.
1436b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     *
1437b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
1438b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     *
1439b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
1440b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     *                         the reason for and the strength of the requested authentication.
1441b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
1442b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     */
1443b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
1444b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            int userId) {
1445b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        try {
1446b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            getLockSettings().requireStrongAuth(strongAuthReason, userId);
1447b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        } catch (RemoteException e) {
1448b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            Log.e(TAG, "Error while requesting strong auth: " + e);
1449b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
14502c12cfa1d53b586ae8a8d6aca64a4de771dc85b0Adrian Roos    }
14514b9e324b6f59f49a8ca4bc4cd8b38a5ea005a6b2Adrian Roos
1452f8f56bce428bb2b89d1d572ccd2d604761dbbce8Adrian Roos    private void onAfterChangingPassword(int userHandle) {
1453f8f56bce428bb2b89d1d572ccd2d604761dbbce8Adrian Roos        getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
14544b9e324b6f59f49a8ca4bc4cd8b38a5ea005a6b2Adrian Roos    }
1455dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller
1456dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller    public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
1457dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller        final int value = Settings.Global.getInt(mContentResolver,
1458dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
1459dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller        return value == -1 ? defaultValue : (value != 0);
1460dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller    }
1461dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller
1462dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller    public void setCredentialRequiredToDecrypt(boolean required) {
1463d39113ea00b650f5778ed3d5dea6664c5d06f5b4Robin Lee        if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
1464d39113ea00b650f5778ed3d5dea6664c5d06f5b4Robin Lee            throw new IllegalStateException(
1465d39113ea00b650f5778ed3d5dea6664c5d06f5b4Robin Lee                    "Only the system or primary user may call setCredentialRequiredForDecrypt()");
1466dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller        }
1467688af6c5743d4ef5d08537b02b23fdde24a3c348Paul Lawrence
1468688af6c5743d4ef5d08537b02b23fdde24a3c348Paul Lawrence        if (isDeviceEncryptionEnabled()){
1469688af6c5743d4ef5d08537b02b23fdde24a3c348Paul Lawrence            Settings.Global.putInt(mContext.getContentResolver(),
1470688af6c5743d4ef5d08537b02b23fdde24a3c348Paul Lawrence               Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
1471688af6c5743d4ef5d08537b02b23fdde24a3c348Paul Lawrence        }
1472dd5de719c5a0d39030f94d931c0ab1bed1f147f8Jim Miller    }
14734eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov
14744eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov    private boolean isDoNotAskCredentialsOnBootSet() {
14754929a5d3b434a6915d64e449b234b40b8eff9993Rubin Xu        return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
14764eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov    }
14774eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov
14784eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov    private boolean shouldEncryptWithCredentials(boolean defaultValue) {
14794eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov        return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
14804eb6a36922f5e98fe181c0326cc5721f0e7589caAndrei Kapishnikov    }
1481aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia
1482aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia    private void throwIfCalledOnMainThread() {
1483aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia        if (Looper.getMainLooper().isCurrentThread()) {
1484aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia            throw new IllegalStateException("should not be called from the main thread.");
1485aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia        }
1486aa26294de3ad97859637f65f6e70eb773541a767Xiyuan Xia    }
1487b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1488b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1489b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        try {
1490b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
1491b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        } catch (RemoteException e) {
1492b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            throw new RuntimeException("Could not register StrongAuthTracker");
1493b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1494b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    }
1495b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1496b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
1497b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        try {
1498b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
1499b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        } catch (RemoteException e) {
1500b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            Log.e(TAG, "Could not unregister StrongAuthTracker", e);
1501b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1502b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    }
1503b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1504b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    /**
1505a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang     * @see StrongAuthTracker#getStrongAuthForUser
1506a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang     */
1507a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    public int getStrongAuthForUser(int userId) {
1508a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        try {
1509a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang            return getLockSettings().getStrongAuthForUser(userId);
1510a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        } catch (RemoteException e) {
1511a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang            Log.e(TAG, "Could not get StrongAuth", e);
1512a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang            return StrongAuthTracker.getDefaultFlags(mContext);
1513a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        }
1514a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    }
1515a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang
1516a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    /**
1517a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang     * @see StrongAuthTracker#isTrustAllowedForUser
1518a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang     */
1519a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    public boolean isTrustAllowedForUser(int userId) {
1520a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
1521a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    }
1522a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang
1523a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    /**
1524a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang     * @see StrongAuthTracker#isFingerprintAllowedForUser
1525a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang     */
1526a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    public boolean isFingerprintAllowedForUser(int userId) {
1527a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
1528a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    }
1529a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang
1530ea8c5ef2b8bc00575073ddbce42e7986a59af627Chad Brubaker    public boolean isUserInLockdown(int userId) {
1531ea8c5ef2b8bc00575073ddbce42e7986a59af627Chad Brubaker        return getStrongAuthForUser(userId)
1532ea8c5ef2b8bc00575073ddbce42e7986a59af627Chad Brubaker                == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
1533ea8c5ef2b8bc00575073ddbce42e7986a59af627Chad Brubaker    }
1534ea8c5ef2b8bc00575073ddbce42e7986a59af627Chad Brubaker
1535e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    private ICheckCredentialProgressCallback wrapCallback(
1536e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            final CheckCredentialProgressCallback callback) {
1537e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        if (callback == null) {
1538e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            return null;
1539e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        } else {
15407a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos            if (mHandler == null) {
15417a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos                throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
15427a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos                        + " to use progress callbacks.");
15437a3bf7c46e54cf226f86e3eeedb100a159f08d00Adrian Roos            }
1544e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            return new ICheckCredentialProgressCallback.Stub() {
1545e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi
1546e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi                @Override
1547e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi                public void onCredentialVerified() throws RemoteException {
1548e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi                    mHandler.post(callback::onEarlyMatched);
1549e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi                }
1550e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi            };
1551e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        }
1552e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    }
1553e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi
1554fcd49f993ede363d0b17900565dfe37066362480Rubin Xu    private LockSettingsInternal getLockSettingsInternal() {
1555fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
1556fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        if (service == null) {
1557fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            throw new SecurityException("Only available to system server itself");
1558fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        }
1559fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        return service;
1560fcd49f993ede363d0b17900565dfe37066362480Rubin Xu    }
1561e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    /**
1562f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * Create an escrow token for the current user, which can later be used to unlock FBE
1563f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * or change user password.
1564f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     *
1565f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * After adding, if the user currently has lockscreen password, he will need to perform a
1566f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * confirm credential operation in order to activate the token for future use. If the user
1567f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * has no secure lockscreen, then the token is activated immediately.
1568f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     *
1569fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * <p>This method is only available to code running in the system server process itself.
1570fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
1571f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * @return a unique 64-bit token handle which is needed to refer to this token later.
1572f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     */
1573f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    public long addEscrowToken(byte[] token, int userId) {
1574fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        return getLockSettingsInternal().addEscrowToken(token, userId);
1575f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    }
1576f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1577f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    /**
1578f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * Remove an escrow token.
1579fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
1580fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * <p>This method is only available to code running in the system server process itself.
1581fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
1582f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * @return true if the given handle refers to a valid token previously returned from
1583f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
1584f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     */
1585f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    public boolean removeEscrowToken(long handle, int userId) {
1586fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        return getLockSettingsInternal().removeEscrowToken(handle, userId);
1587f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    }
1588f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1589f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    /**
1590f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * Check if the given escrow token is active or not. Only active token can be used to call
1591f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
1592fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
1593fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * <p>This method is only available to code running in the system server process itself.
1594f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu     */
1595f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    public boolean isEscrowTokenActive(long handle, int userId) {
1596fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
1597f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    }
1598f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
15997cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu    /**
16007cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * Change a user's lock credential with a pre-configured escrow token.
16017cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     *
1602fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * <p>This method is only available to code running in the system server process itself.
1603fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
16047cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @param credential The new credential to be set
16057cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @param type Credential type: password / pattern / none.
16067cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @param requestedQuality the requested password quality by DevicePolicyManager.
16077cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     *        See {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
16087cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @param tokenHandle Handle of the escrow token
16097cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @param token Escrow token
16107cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @param userId The user who's lock credential to be changed
16117cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     * @return {@code true} if the operation is successful.
16127cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu     */
16137cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu    public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
16147cf4509c31f3dc1c32f89c26867a50c4ed0d5618Rubin Xu            long tokenHandle, byte[] token, int userId) {
1615fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        LockSettingsInternal localService = getLockSettingsInternal();
1616fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        if (type != CREDENTIAL_TYPE_NONE) {
1617fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
1618fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                throw new IllegalArgumentException("password must not be null and at least "
1619fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                        + "of length " + MIN_LOCK_PASSWORD_SIZE);
1620fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            }
1621fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            final int quality = computePasswordQuality(type, credential, requestedQuality);
1622fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
1623fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                    token, quality, userId)) {
1624fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                return false;
1625fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            }
1626682d16758010e311910133fb40868133c05b3fe6Rubin Xu            setKeyguardStoredPasswordQuality(quality, userId);
1627f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1628fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            updateEncryptionPasswordIfNeeded(credential, quality, userId);
1629fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            updatePasswordHistory(credential, userId);
1630f01e90789eb27bc538df13374b6e67991c0ea829Rubin Xu            onAfterChangingPassword(userId);
1631fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        } else {
1632fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            if (!TextUtils.isEmpty(credential)) {
1633fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                throw new IllegalArgumentException("password must be emtpy for NONE type");
1634fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            }
1635fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
1636682d16758010e311910133fb40868133c05b3fe6Rubin Xu                    tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
1637fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                return false;
1638fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            }
1639682d16758010e311910133fb40868133c05b3fe6Rubin Xu            setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
1640f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1641fcd49f993ede363d0b17900565dfe37066362480Rubin Xu            if (userId == UserHandle.USER_SYSTEM) {
1642fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                // Set the encryption password to default.
1643fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
1644fcd49f993ede363d0b17900565dfe37066362480Rubin Xu                setCredentialRequiredToDecrypt(false);
1645f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu            }
1646f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu        }
1647fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        onAfterChangingPassword(userId);
1648fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        return true;
1649f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    }
1650f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1651fcd49f993ede363d0b17900565dfe37066362480Rubin Xu    /**
1652fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * Unlock the specified user by an pre-activated escrow token. This should have the same effect
1653fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * on device encryption as the user entering his lockscreen credentials for the first time after
1654fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
1655fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
1656fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * <p>This method is only available to code running in the system server process itself.
1657fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *
1658fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     * @return {@code true} if the supplied token is valid and unlock succeeds,
1659fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     *         {@code false} otherwise.
1660fcd49f993ede363d0b17900565dfe37066362480Rubin Xu     */
1661fcd49f993ede363d0b17900565dfe37066362480Rubin Xu    public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
1662fcd49f993ede363d0b17900565dfe37066362480Rubin Xu        return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
1663f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    }
1664f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1665f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu
1666f095f8366bac52ac1eeb2b3eb1a403294ceeb541Rubin Xu    /**
1667e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     * Callback to be notified about progress when checking credentials.
1668e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi     */
1669e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    public interface CheckCredentialProgressCallback {
1670e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi
1671e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        /**
1672e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi         * Called as soon as possible when we know that the credentials match but the user hasn't
1673e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi         * been fully unlocked.
1674e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi         */
1675e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi        void onEarlyMatched();
1676e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi    }
1677e8fde5d9666eea10307cbc27f4b1a94d3cbb4ec9Jorim Jaggi
1678a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang    /**
1679b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     * Tracks the global strong authentication state.
1680b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos     */
1681b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    public static class StrongAuthTracker {
1682b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1683b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        @IntDef(flag = true,
1684b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                value = { STRONG_AUTH_NOT_REQUIRED,
1685b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                        STRONG_AUTH_REQUIRED_AFTER_BOOT,
1686b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                        STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
16879d6fc9246ba0b726872a6a8dabe6c334292c3a10Adrian Roos                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
1688c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski                        STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
16894f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker                        STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
16904f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker                        STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
1691b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        @Retention(RetentionPolicy.SOURCE)
1692b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public @interface StrongAuthFlags {}
1693b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1694b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1695b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * Strong authentication is not required.
1696b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1697b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
1698b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1699b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1700b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * Strong authentication is required because the user has not authenticated since boot.
1701b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1702b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
1703b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1704b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
170516093fe3f0d824731a53a264a132504deb08421aJorim Jaggi         * Strong authentication is required because a device admin has requested it.
1706b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1707b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
1708b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1709b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
171016093fe3f0d824731a53a264a132504deb08421aJorim Jaggi         * Some authentication is required because the user has temporarily disabled trust.
1711b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
171216093fe3f0d824731a53a264a132504deb08421aJorim Jaggi        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
1713b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1714873010dfeea11e0f9982c66ad9bdc990d055b129Adrian Roos        /**
1715873010dfeea11e0f9982c66ad9bdc990d055b129Adrian Roos         * Strong authentication is required because the user has been locked out after too many
1716873010dfeea11e0f9982c66ad9bdc990d055b129Adrian Roos         * attempts.
1717873010dfeea11e0f9982c66ad9bdc990d055b129Adrian Roos         */
1718873010dfeea11e0f9982c66ad9bdc990d055b129Adrian Roos        public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
1719873010dfeea11e0f9982c66ad9bdc990d055b129Adrian Roos
1720af4ab3e2d3665c72889bf2337c744eca6c7d5e86Adrian Roos        /**
1721c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski         * Strong authentication is required because it hasn't been used for a time required by
1722c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski         * a device admin.
1723c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski         */
1724c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski        public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
1725c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski
1726c52f867875ed7f671bf897f11e359e8104ce8795Michal Karpinski        /**
17274f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker         * Strong authentication is required because the user has triggered lockdown.
17284f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker         */
17294f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker        public static final int STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN = 0x20;
17304f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker
17314f28f0de37b00216dbe0f66513735a0ab7dd570dChad Brubaker        /**
17329d6fc9246ba0b726872a6a8dabe6c334292c3a10Adrian Roos         * Strong auth flags that do not prevent fingerprint from being accepted as auth.
17339d6fc9246ba0b726872a6a8dabe6c334292c3a10Adrian Roos         *
17349d6fc9246ba0b726872a6a8dabe6c334292c3a10Adrian Roos         * If any other flags are set, fingerprint is disabled.
1735af4ab3e2d3665c72889bf2337c744eca6c7d5e86Adrian Roos         */
1736af4ab3e2d3665c72889bf2337c744eca6c7d5e86Adrian Roos        private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
17379d6fc9246ba0b726872a6a8dabe6c334292c3a10Adrian Roos                | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
1738b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1739af4ab3e2d3665c72889bf2337c744eca6c7d5e86Adrian Roos        private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
1740b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        private final H mHandler;
1741a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer        private final int mDefaultStrongAuthFlags;
1742b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1743a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer        public StrongAuthTracker(Context context) {
1744a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer            this(context, Looper.myLooper());
1745b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1746b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1747b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1748b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
1749b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         *               will be scheduled.
1750a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer         * @param context the current {@link Context}
1751b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1752a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer        public StrongAuthTracker(Context context, Looper looper) {
1753b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            mHandler = new H(looper);
1754a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer            mDefaultStrongAuthFlags = getDefaultFlags(context);
1755a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer        }
1756a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer
1757a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer        public static @StrongAuthFlags int getDefaultFlags(Context context) {
1758a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer            boolean strongAuthRequired = context.getResources().getBoolean(
1759a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer                    com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
1760a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer            return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
1761b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1762b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1763b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1764b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
1765b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
1766b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * authentication is required.
1767b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         *
1768b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * @param userId the user for whom the state is queried.
1769b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1770b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public @StrongAuthFlags int getStrongAuthForUser(int userId) {
1771a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer            return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
1772b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1773b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1774b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1775b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * @return true if unlocking with trust alone is allowed for {@param userId} by the current
1776b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * strong authentication requirements.
1777b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1778b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public boolean isTrustAllowedForUser(int userId) {
1779b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
1780b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1781b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1782b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1783b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
1784b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * current strong authentication requirements.
1785b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1786b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public boolean isFingerprintAllowedForUser(int userId) {
1787af4ab3e2d3665c72889bf2337c744eca6c7d5e86Adrian Roos            return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
1788b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1789b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1790b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        /**
1791b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         * Called when the strong authentication requirements for {@param userId} changed.
1792b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos         */
1793b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        public void onStrongAuthRequiredChanged(int userId) {
1794b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1795b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1796a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1797b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                int userId) {
1798b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            int oldValue = getStrongAuthForUser(userId);
1799b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            if (strongAuthFlags != oldValue) {
1800a7aa4d6f0b91e050c083c19459b0c8b265c92617Rakesh Iyer                if (strongAuthFlags == mDefaultStrongAuthFlags) {
1801b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                    mStrongAuthRequiredForUser.delete(userId);
1802b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                } else {
1803b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                    mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
1804b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                }
1805b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                onStrongAuthRequiredChanged(userId);
1806b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            }
1807b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        }
1808b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1809b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1810a0940d33dcbac0245ad5467d9c302f8eaee615dcVictor Chang        protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
1811b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            @Override
1812b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
1813b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                    int userId) {
1814b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
1815b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                        strongAuthFlags, userId).sendToTarget();
1816b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            }
1817b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        };
1818b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1819b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos        private class H extends Handler {
1820b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
1821b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1822b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            public H(Looper looper) {
1823b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                super(looper);
1824b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            }
1825b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos
1826b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            @Override
1827b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            public void handleMessage(Message msg) {
1828b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                switch (msg.what) {
1829b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                    case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
1830b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                        handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
1831b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                        break;
1832b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos                }
1833b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos            }
18343bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu        }
18353bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    }
18363bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu
18373bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    public void enableSyntheticPassword() {
18383bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu        setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1L, UserHandle.USER_SYSTEM);
18393bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    }
18403bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu
18417a0cc0a7fbfaae2843dd333ab8e62731bc04e2b2Paul Crowley    public void disableSyntheticPassword() {
18427a0cc0a7fbfaae2843dd333ab8e62731bc04e2b2Paul Crowley        setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0L, UserHandle.USER_SYSTEM);
18437a0cc0a7fbfaae2843dd333ab8e62731bc04e2b2Paul Crowley    }
18447a0cc0a7fbfaae2843dd333ab8e62731bc04e2b2Paul Crowley
18453bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu    public boolean isSyntheticPasswordEnabled() {
18463bf722a8d54ca7192dfe07ee7b73eac7d25ccac5Rubin Xu        return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
1847b5e4722891e7bbf2fffcd995af02838667a3ababAdrian Roos    }
18487374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos
18492adc263ce97ae6c8291653490868879841d31a63Adrian Roos    public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
18502adc263ce97ae6c8291653490868879841d31a63Adrian Roos        return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
18517374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos    }
18527374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos
18532adc263ce97ae6c8291653490868879841d31a63Adrian Roos    public static boolean frpCredentialEnabled(Context context) {
18542adc263ce97ae6c8291653490868879841d31a63Adrian Roos        return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
18552adc263ce97ae6c8291653490868879841d31a63Adrian Roos                com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
18567374d3a4bca6bfbf7da1ef5dbf0db9f35f0c8315Adrian Roos    }
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1858