LockPatternUtils.java revision aa2859ae61098509495b7938e32a6d59d37561be
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.widget;
18
19import com.android.internal.R;
20import com.android.internal.telephony.ITelephony;
21import com.google.android.collect.Lists;
22
23import android.app.ActivityManagerNative;
24import android.app.admin.DevicePolicyManager;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.pm.PackageManager;
29import android.os.Binder;
30import android.os.Bundle;
31import android.os.IBinder;
32import android.os.RemoteException;
33import android.os.ServiceManager;
34import android.os.SystemClock;
35import android.os.UserHandle;
36import android.os.storage.IMountService;
37import android.provider.Settings;
38import android.security.KeyStore;
39import android.telephony.TelephonyManager;
40import android.text.TextUtils;
41import android.util.Log;
42import android.view.View;
43import android.widget.Button;
44
45import org.apache.harmony.kernel.vm.StringUtils;
46
47import java.security.MessageDigest;
48import java.security.NoSuchAlgorithmException;
49import java.security.SecureRandom;
50import java.util.ArrayList;
51import java.util.List;
52
53/**
54 * Utilities for the lock pattern and its settings.
55 */
56public class LockPatternUtils {
57
58    private static final String OPTION_ENABLE_FACELOCK = "enable_facelock";
59
60    private static final String TAG = "LockPatternUtils";
61
62    /**
63     * The maximum number of incorrect attempts before the user is prevented
64     * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
65     */
66    public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
67
68    /**
69     * The number of incorrect attempts before which we fall back on an alternative
70     * method of verifying the user, and resetting their lock pattern.
71     */
72    public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
73
74    /**
75     * How long the user is prevented from trying again after entering the
76     * wrong pattern too many times.
77     */
78    public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
79
80    /**
81     * The interval of the countdown for showing progress of the lockout.
82     */
83    public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
84
85
86    /**
87     * This dictates when we start telling the user that continued failed attempts will wipe
88     * their device.
89     */
90    public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
91
92    /**
93     * The minimum number of dots in a valid pattern.
94     */
95    public static final int MIN_LOCK_PATTERN_SIZE = 4;
96
97    /**
98     * The minimum number of dots the user must include in a wrong pattern
99     * attempt for it to be counted against the counts that affect
100     * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
101     */
102    public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
103
104    /**
105     * Tells the keyguard to show the user switcher when the keyguard is created.
106     */
107    public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
108
109    /**
110     * Tells the keyguard to show the security challenge when the keyguard is created.
111     */
112    public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
113
114    /**
115     * Options used to lock the device upon user switch.
116     */
117    public static final Bundle USER_SWITCH_LOCK_OPTIONS = new Bundle();
118
119    static {
120        USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_USER_SWITCHER, true);
121        USER_SWITCH_LOCK_OPTIONS.putBoolean(KEYGUARD_SHOW_SECURITY_CHALLENGE, true);
122    }
123
124    /**
125     * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
126     * be used
127     */
128    public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
129
130    protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
131    protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
132    protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
133    public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
134    public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
135    protected final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
136    protected final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
137    protected final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
138    public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
139            = "lockscreen.biometric_weak_fallback";
140    public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
141            = "lockscreen.biometricweakeverchosen";
142    public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
143            = "lockscreen.power_button_instantly_locks";
144
145    protected final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
146
147    private final Context mContext;
148    private final ContentResolver mContentResolver;
149    private DevicePolicyManager mDevicePolicyManager;
150    private ILockSettings mLockSettingsService;
151
152    // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
153    private static volatile int sCurrentUserId = UserHandle.USER_NULL;
154
155    public DevicePolicyManager getDevicePolicyManager() {
156        if (mDevicePolicyManager == null) {
157            mDevicePolicyManager =
158                (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
159            if (mDevicePolicyManager == null) {
160                Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
161                        new IllegalStateException("Stack trace:"));
162            }
163        }
164        return mDevicePolicyManager;
165    }
166
167    /**
168     * @param contentResolver Used to look up and save settings.
169     */
170    public LockPatternUtils(Context context) {
171        mContext = context;
172        mContentResolver = context.getContentResolver();
173    }
174
175    private ILockSettings getLockSettings() {
176        if (mLockSettingsService == null) {
177            mLockSettingsService = ILockSettings.Stub.asInterface(
178                (IBinder) ServiceManager.getService("lock_settings"));
179        }
180        return mLockSettingsService;
181    }
182
183    public int getRequestedMinimumPasswordLength() {
184        return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
185    }
186
187    /**
188     * Gets the device policy password mode. If the mode is non-specific, returns
189     * MODE_PATTERN which allows the user to choose anything.
190     */
191    public int getRequestedPasswordQuality() {
192        return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
193    }
194
195    public int getRequestedPasswordHistoryLength() {
196        return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
197    }
198
199    public int getRequestedPasswordMinimumLetters() {
200        return getDevicePolicyManager().getPasswordMinimumLetters(null,
201                getCurrentOrCallingUserId());
202    }
203
204    public int getRequestedPasswordMinimumUpperCase() {
205        return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
206                getCurrentOrCallingUserId());
207    }
208
209    public int getRequestedPasswordMinimumLowerCase() {
210        return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
211                getCurrentOrCallingUserId());
212    }
213
214    public int getRequestedPasswordMinimumNumeric() {
215        return getDevicePolicyManager().getPasswordMinimumNumeric(null,
216                getCurrentOrCallingUserId());
217    }
218
219    public int getRequestedPasswordMinimumSymbols() {
220        return getDevicePolicyManager().getPasswordMinimumSymbols(null,
221                getCurrentOrCallingUserId());
222    }
223
224    public int getRequestedPasswordMinimumNonLetter() {
225        return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
226                getCurrentOrCallingUserId());
227    }
228
229    /**
230     * Returns the actual password mode, as set by keyguard after updating the password.
231     *
232     * @return
233     */
234    public void reportFailedPasswordAttempt() {
235        getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
236    }
237
238    public void reportSuccessfulPasswordAttempt() {
239        getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
240    }
241
242    public void setCurrentUser(int userId) {
243        sCurrentUserId = userId;
244    }
245
246    public int getCurrentUser() {
247        if (sCurrentUserId != UserHandle.USER_NULL) {
248            // Someone is regularly updating using setCurrentUser() use that value.
249            return sCurrentUserId;
250        }
251        try {
252            return ActivityManagerNative.getDefault().getCurrentUser().id;
253        } catch (RemoteException re) {
254            return UserHandle.USER_OWNER;
255        }
256    }
257
258    public void removeUser(int userId) {
259        try {
260            getLockSettings().removeUser(userId);
261        } catch (RemoteException re) {
262            Log.e(TAG, "Couldn't remove lock settings for user " + userId);
263        }
264    }
265
266    private int getCurrentOrCallingUserId() {
267        int callingUid = Binder.getCallingUid();
268        if (callingUid == android.os.Process.SYSTEM_UID) {
269            // TODO: This is a little inefficient. See if all users of this are able to
270            // handle USER_CURRENT and pass that instead.
271            return getCurrentUser();
272        } else {
273            return UserHandle.getUserId(callingUid);
274        }
275    }
276
277    /**
278     * Check to see if a pattern matches the saved pattern.  If no pattern exists,
279     * always returns true.
280     * @param pattern The pattern to check.
281     * @return Whether the pattern matches the stored one.
282     */
283    public boolean checkPattern(List<LockPatternView.Cell> pattern) {
284        final int userId = getCurrentOrCallingUserId();
285        try {
286            final boolean matched = getLockSettings().checkPattern(patternToHash(pattern), userId);
287            if (matched && (userId == UserHandle.USER_OWNER)) {
288                KeyStore.getInstance().password(patternToString(pattern));
289            }
290            return matched;
291        } catch (RemoteException re) {
292            return true;
293        }
294    }
295
296    /**
297     * Check to see if a password matches the saved password.  If no password exists,
298     * always returns true.
299     * @param password The password to check.
300     * @return Whether the password matches the stored one.
301     */
302    public boolean checkPassword(String password) {
303        final int userId = getCurrentOrCallingUserId();
304        try {
305            final boolean matched = getLockSettings().checkPassword(passwordToHash(password),
306                    userId);
307            if (matched && (userId == UserHandle.USER_OWNER)) {
308                KeyStore.getInstance().password(password);
309            }
310            return matched;
311        } catch (RemoteException re) {
312            return true;
313        }
314    }
315
316    /**
317     * Check to see if a password matches any of the passwords stored in the
318     * password history.
319     *
320     * @param password The password to check.
321     * @return Whether the password matches any in the history.
322     */
323    public boolean checkPasswordHistory(String password) {
324        String passwordHashString = new String(passwordToHash(password));
325        String passwordHistory = getString(PASSWORD_HISTORY_KEY);
326        if (passwordHistory == null) {
327            return false;
328        }
329        // Password History may be too long...
330        int passwordHashLength = passwordHashString.length();
331        int passwordHistoryLength = getRequestedPasswordHistoryLength();
332        if(passwordHistoryLength == 0) {
333            return false;
334        }
335        int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength
336                + passwordHistoryLength - 1;
337        if (passwordHistory.length() > neededPasswordHistoryLength) {
338            passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength);
339        }
340        return passwordHistory.contains(passwordHashString);
341    }
342
343    /**
344     * Check to see if the user has stored a lock pattern.
345     * @return Whether a saved pattern exists.
346     */
347    public boolean savedPatternExists() {
348        try {
349            return getLockSettings().havePattern(getCurrentOrCallingUserId());
350        } catch (RemoteException re) {
351            return false;
352        }
353    }
354
355    /**
356     * Check to see if the user has stored a lock pattern.
357     * @return Whether a saved pattern exists.
358     */
359    public boolean savedPasswordExists() {
360        try {
361            return getLockSettings().havePassword(getCurrentOrCallingUserId());
362        } catch (RemoteException re) {
363            return false;
364        }
365    }
366
367    /**
368     * Return true if the user has ever chosen a pattern.  This is true even if the pattern is
369     * currently cleared.
370     *
371     * @return True if the user has ever chosen a pattern.
372     */
373    public boolean isPatternEverChosen() {
374        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
375    }
376
377    /**
378     * Return true if the user has ever chosen biometric weak.  This is true even if biometric
379     * weak is not current set.
380     *
381     * @return True if the user has ever chosen biometric weak.
382     */
383    public boolean isBiometricWeakEverChosen() {
384        return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
385    }
386
387    /**
388     * Used by device policy manager to validate the current password
389     * information it has.
390     */
391    public int getActivePasswordQuality() {
392        int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
393        // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
394        // return biometric_weak if that is being used instead of the backup
395        int quality =
396                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
397        switch (quality) {
398            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
399                if (isLockPatternEnabled()) {
400                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
401                }
402                break;
403            case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
404                if (isBiometricWeakInstalled()) {
405                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
406                }
407                break;
408            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
409                if (isLockPasswordEnabled()) {
410                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
411                }
412                break;
413            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
414                if (isLockPasswordEnabled()) {
415                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
416                }
417                break;
418            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
419                if (isLockPasswordEnabled()) {
420                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
421                }
422                break;
423            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
424                if (isLockPasswordEnabled()) {
425                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
426                }
427                break;
428        }
429
430        return activePasswordQuality;
431    }
432
433    /**
434     * Clear any lock pattern or password.
435     */
436    public void clearLock(boolean isFallback) {
437        if(!isFallback) deleteGallery();
438        saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
439        setLockPatternEnabled(false);
440        saveLockPattern(null);
441        setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
442        setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
443    }
444
445    /**
446     * Disable showing lock screen at all when the DevicePolicyManager allows it.
447     * This is only meaningful if pattern, pin or password are not set.
448     *
449     * @param disable Disables lock screen when true
450     */
451    public void setLockScreenDisabled(boolean disable) {
452        setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
453    }
454
455    /**
456     * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
457     * show LockScreen or go straight to the home screen.
458     *
459     * @return true if lock screen is can be disabled
460     */
461    public boolean isLockScreenDisabled() {
462        return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
463    }
464
465    /**
466     * Calls back SetupFaceLock to delete the temporary gallery file
467     */
468    public void deleteTempGallery() {
469        Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
470        intent.putExtra("deleteTempGallery", true);
471        mContext.sendBroadcast(intent);
472    }
473
474    /**
475     * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
476    */
477    void deleteGallery() {
478        if(usingBiometricWeak()) {
479            Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
480            intent.putExtra("deleteGallery", true);
481            mContext.sendBroadcast(intent);
482        }
483    }
484
485    /**
486     * Save a lock pattern.
487     * @param pattern The new pattern to save.
488     */
489    public void saveLockPattern(List<LockPatternView.Cell> pattern) {
490        this.saveLockPattern(pattern, false);
491    }
492
493    /**
494     * Save a lock pattern.
495     * @param pattern The new pattern to save.
496     * @param isFallback Specifies if this is a fallback to biometric weak
497     */
498    public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
499        // Compute the hash
500        final byte[] hash = LockPatternUtils.patternToHash(pattern);
501        try {
502            getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId());
503            DevicePolicyManager dpm = getDevicePolicyManager();
504            KeyStore keyStore = KeyStore.getInstance();
505            if (pattern != null) {
506                keyStore.password(patternToString(pattern));
507                setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
508                if (!isFallback) {
509                    deleteGallery();
510                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
511                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
512                            pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
513                } else {
514                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
515                    setLong(PASSWORD_TYPE_ALTERNATE_KEY,
516                            DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
517                    finishBiometricWeak();
518                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
519                            0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
520                }
521            } else {
522                if (keyStore.isEmpty()) {
523                    keyStore.reset();
524                }
525                dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
526                        0, 0, 0, 0, 0, getCurrentOrCallingUserId());
527            }
528        } catch (RemoteException re) {
529            Log.e(TAG, "Couldn't save lock pattern " + re);
530        }
531    }
532
533    /**
534     * Compute the password quality from the given password string.
535     */
536    static public int computePasswordQuality(String password) {
537        boolean hasDigit = false;
538        boolean hasNonDigit = false;
539        final int len = password.length();
540        for (int i = 0; i < len; i++) {
541            if (Character.isDigit(password.charAt(i))) {
542                hasDigit = true;
543            } else {
544                hasNonDigit = true;
545            }
546        }
547
548        if (hasNonDigit && hasDigit) {
549            return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
550        }
551        if (hasNonDigit) {
552            return DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
553        }
554        if (hasDigit) {
555            return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
556        }
557        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
558    }
559
560    /** Update the encryption password if it is enabled **/
561    private void updateEncryptionPassword(String password) {
562        DevicePolicyManager dpm = getDevicePolicyManager();
563        if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
564                != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
565            return;
566        }
567
568        IBinder service = ServiceManager.getService("mount");
569        if (service == null) {
570            Log.e(TAG, "Could not find the mount service to update the encryption password");
571            return;
572        }
573
574        IMountService mountService = IMountService.Stub.asInterface(service);
575        try {
576            mountService.changeEncryptionPassword(password);
577        } catch (RemoteException e) {
578            Log.e(TAG, "Error changing encryption password", e);
579        }
580    }
581
582    /**
583     * Save a lock password.  Does not ensure that the password is as good
584     * as the requested mode, but will adjust the mode to be as good as the
585     * pattern.
586     * @param password The password to save
587     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
588     */
589    public void saveLockPassword(String password, int quality) {
590        this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
591    }
592
593    /**
594     * Save a lock password.  Does not ensure that the password is as good
595     * as the requested mode, but will adjust the mode to be as good as the
596     * pattern.
597     * @param password The password to save
598     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
599     * @param isFallback Specifies if this is a fallback to biometric weak
600     */
601    public void saveLockPassword(String password, int quality, boolean isFallback) {
602        saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
603    }
604
605    /**
606     * Save a lock password.  Does not ensure that the password is as good
607     * as the requested mode, but will adjust the mode to be as good as the
608     * pattern.
609     * @param password The password to save
610     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
611     * @param isFallback Specifies if this is a fallback to biometric weak
612     * @param userHandle The userId of the user to change the password for
613     */
614    public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
615        // Compute the hash
616        final byte[] hash = passwordToHash(password);
617        try {
618            getLockSettings().setLockPassword(hash, userHandle);
619            DevicePolicyManager dpm = getDevicePolicyManager();
620            KeyStore keyStore = KeyStore.getInstance();
621            if (password != null) {
622                if (userHandle == UserHandle.USER_OWNER) {
623                    // Update the encryption password.
624                    updateEncryptionPassword(password);
625
626                    // Update the keystore password
627                    keyStore.password(password);
628                }
629
630                int computedQuality = computePasswordQuality(password);
631                if (!isFallback) {
632                    deleteGallery();
633                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
634                    if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
635                        int letters = 0;
636                        int uppercase = 0;
637                        int lowercase = 0;
638                        int numbers = 0;
639                        int symbols = 0;
640                        int nonletter = 0;
641                        for (int i = 0; i < password.length(); i++) {
642                            char c = password.charAt(i);
643                            if (c >= 'A' && c <= 'Z') {
644                                letters++;
645                                uppercase++;
646                            } else if (c >= 'a' && c <= 'z') {
647                                letters++;
648                                lowercase++;
649                            } else if (c >= '0' && c <= '9') {
650                                numbers++;
651                                nonletter++;
652                            } else {
653                                symbols++;
654                                nonletter++;
655                            }
656                        }
657                        dpm.setActivePasswordState(Math.max(quality, computedQuality),
658                                password.length(), letters, uppercase, lowercase,
659                                numbers, symbols, nonletter, userHandle);
660                    } else {
661                        // The password is not anything.
662                        dpm.setActivePasswordState(
663                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
664                                0, 0, 0, 0, 0, 0, 0, userHandle);
665                    }
666                } else {
667                    // Case where it's a fallback for biometric weak
668                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
669                            userHandle);
670                    setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
671                            userHandle);
672                    finishBiometricWeak();
673                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
674                            0, 0, 0, 0, 0, 0, 0, userHandle);
675                }
676                // Add the password to the password history. We assume all
677                // password
678                // hashes have the same length for simplicity of implementation.
679                String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
680                if (passwordHistory == null) {
681                    passwordHistory = new String();
682                }
683                int passwordHistoryLength = getRequestedPasswordHistoryLength();
684                if (passwordHistoryLength == 0) {
685                    passwordHistory = "";
686                } else {
687                    passwordHistory = new String(hash) + "," + passwordHistory;
688                    // Cut it to contain passwordHistoryLength hashes
689                    // and passwordHistoryLength -1 commas.
690                    passwordHistory = passwordHistory.substring(0, Math.min(hash.length
691                            * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
692                            .length()));
693                }
694                setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
695            } else {
696                // Conditionally reset the keystore if empty. If
697                // non-empty, we are just switching key guard type
698                if (keyStore.isEmpty()) {
699                    keyStore.reset();
700                }
701                dpm.setActivePasswordState(
702                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
703                        userHandle);
704            }
705        } catch (RemoteException re) {
706            // Cant do much
707            Log.e(TAG, "Unable to save lock password " + re);
708        }
709    }
710
711    /**
712     * Retrieves the quality mode we're in.
713     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
714     *
715     * @return stored password quality
716     */
717    public int getKeyguardStoredPasswordQuality() {
718        int quality =
719                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
720        // If the user has chosen to use weak biometric sensor, then return the backup locking
721        // method and treat biometric as a special case.
722        if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
723            quality =
724                (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
725                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
726        }
727        return quality;
728    }
729
730    /**
731     * @return true if the lockscreen method is set to biometric weak
732     */
733    public boolean usingBiometricWeak() {
734        int quality =
735                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
736        return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
737    }
738
739    /**
740     * Deserialize a pattern.
741     * @param string The pattern serialized with {@link #patternToString}
742     * @return The pattern.
743     */
744    public static List<LockPatternView.Cell> stringToPattern(String string) {
745        List<LockPatternView.Cell> result = Lists.newArrayList();
746
747        final byte[] bytes = string.getBytes();
748        for (int i = 0; i < bytes.length; i++) {
749            byte b = bytes[i];
750            result.add(LockPatternView.Cell.of(b / 3, b % 3));
751        }
752        return result;
753    }
754
755    /**
756     * Serialize a pattern.
757     * @param pattern The pattern.
758     * @return The pattern in string form.
759     */
760    public static String patternToString(List<LockPatternView.Cell> pattern) {
761        if (pattern == null) {
762            return "";
763        }
764        final int patternSize = pattern.size();
765
766        byte[] res = new byte[patternSize];
767        for (int i = 0; i < patternSize; i++) {
768            LockPatternView.Cell cell = pattern.get(i);
769            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
770        }
771        return new String(res);
772    }
773
774    /*
775     * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
776     * at least a second level of protection. First level is that the file
777     * is in a location only readable by the system process.
778     * @param pattern the gesture pattern.
779     * @return the hash of the pattern in a byte array.
780     */
781    private static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
782        if (pattern == null) {
783            return null;
784        }
785
786        final int patternSize = pattern.size();
787        byte[] res = new byte[patternSize];
788        for (int i = 0; i < patternSize; i++) {
789            LockPatternView.Cell cell = pattern.get(i);
790            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
791        }
792        try {
793            MessageDigest md = MessageDigest.getInstance("SHA-1");
794            byte[] hash = md.digest(res);
795            return hash;
796        } catch (NoSuchAlgorithmException nsa) {
797            return res;
798        }
799    }
800
801    private String getSalt() {
802        long salt = getLong(LOCK_PASSWORD_SALT_KEY, 0);
803        if (salt == 0) {
804            try {
805                salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
806                setLong(LOCK_PASSWORD_SALT_KEY, salt);
807                Log.v(TAG, "Initialized lock password salt");
808            } catch (NoSuchAlgorithmException e) {
809                // Throw an exception rather than storing a password we'll never be able to recover
810                throw new IllegalStateException("Couldn't get SecureRandom number", e);
811            }
812        }
813        return Long.toHexString(salt);
814    }
815
816    /*
817     * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
818     * Not the most secure, but it is at least a second level of protection. First level is that
819     * the file is in a location only readable by the system process.
820     * @param password the gesture pattern.
821     * @return the hash of the pattern in a byte array.
822     */
823    public byte[] passwordToHash(String password) {
824        if (password == null) {
825            return null;
826        }
827        String algo = null;
828        byte[] hashed = null;
829        try {
830            byte[] saltedPassword = (password + getSalt()).getBytes();
831            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
832            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
833            hashed = (toHex(sha1) + toHex(md5)).getBytes();
834        } catch (NoSuchAlgorithmException e) {
835            Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
836        }
837        return hashed;
838    }
839
840    private static String toHex(byte[] ary) {
841        final String hex = "0123456789ABCDEF";
842        String ret = "";
843        for (int i = 0; i < ary.length; i++) {
844            ret += hex.charAt((ary[i] >> 4) & 0xf);
845            ret += hex.charAt(ary[i] & 0xf);
846        }
847        return ret;
848    }
849
850    /**
851     * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
852     */
853    public boolean isLockPasswordEnabled() {
854        long mode = getLong(PASSWORD_TYPE_KEY, 0);
855        long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
856        final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
857                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
858                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
859                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
860        final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
861                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
862                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
863                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
864
865        return savedPasswordExists() && (passwordEnabled ||
866                (usingBiometricWeak() && backupEnabled));
867    }
868
869    /**
870     * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
871     */
872    public boolean isLockPatternEnabled() {
873        final boolean backupEnabled =
874                getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
875                == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
876
877        return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
878                && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
879                        == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
880                        (usingBiometricWeak() && backupEnabled));
881    }
882
883    /**
884     * @return Whether biometric weak lock is installed and that the front facing camera exists
885     */
886    public boolean isBiometricWeakInstalled() {
887        // Check that it's installed
888        PackageManager pm = mContext.getPackageManager();
889        try {
890            pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
891        } catch (PackageManager.NameNotFoundException e) {
892            return false;
893        }
894
895        // Check that the camera is enabled
896        if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
897            return false;
898        }
899        if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
900            return false;
901        }
902
903
904        return true;
905    }
906
907    /**
908     * Set whether biometric weak liveliness is enabled.
909     */
910    public void setBiometricWeakLivelinessEnabled(boolean enabled) {
911        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
912        long newFlag;
913        if (enabled) {
914            newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
915        } else {
916            newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
917        }
918        setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
919    }
920
921    /**
922     * @return Whether the biometric weak liveliness is enabled.
923     */
924    public boolean isBiometricWeakLivelinessEnabled() {
925        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
926        return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
927    }
928
929    /**
930     * Set whether the lock pattern is enabled.
931     */
932    public void setLockPatternEnabled(boolean enabled) {
933        setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
934    }
935
936    /**
937     * @return Whether the visible pattern is enabled.
938     */
939    public boolean isVisiblePatternEnabled() {
940        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
941    }
942
943    /**
944     * Set whether the visible pattern is enabled.
945     */
946    public void setVisiblePatternEnabled(boolean enabled) {
947        setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
948    }
949
950    /**
951     * @return Whether tactile feedback for the pattern is enabled.
952     */
953    public boolean isTactileFeedbackEnabled() {
954        return Settings.System.getIntForUser(mContentResolver,
955                Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
956    }
957
958    /**
959     * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
960     * pattern until the deadline has passed.
961     * @return the chosen deadline.
962     */
963    public long setLockoutAttemptDeadline() {
964        final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
965        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
966        return deadline;
967    }
968
969    /**
970     * @return The elapsed time in millis in the future when the user is allowed to
971     *   attempt to enter his/her lock pattern, or 0 if the user is welcome to
972     *   enter a pattern.
973     */
974    public long getLockoutAttemptDeadline() {
975        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
976        final long now = SystemClock.elapsedRealtime();
977        if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
978            return 0L;
979        }
980        return deadline;
981    }
982
983    /**
984     * @return Whether the user is permanently locked out until they verify their
985     *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
986     *   attempts.
987     */
988    public boolean isPermanentlyLocked() {
989        return getBoolean(LOCKOUT_PERMANENT_KEY, false);
990    }
991
992    /**
993     * Set the state of whether the device is permanently locked, meaning the user
994     * must authenticate via other means.
995     *
996     * @param locked Whether the user is permanently locked out until they verify their
997     *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
998     *   attempts.
999     */
1000    public void setPermanentlyLocked(boolean locked) {
1001        setBoolean(LOCKOUT_PERMANENT_KEY, locked);
1002    }
1003
1004    public boolean isEmergencyCallCapable() {
1005        return mContext.getResources().getBoolean(
1006                com.android.internal.R.bool.config_voice_capable);
1007    }
1008
1009    public boolean isPukUnlockScreenEnable() {
1010        return mContext.getResources().getBoolean(
1011                com.android.internal.R.bool.config_enable_puk_unlock_screen);
1012    }
1013
1014    public boolean isEmergencyCallEnabledWhileSimLocked() {
1015        return mContext.getResources().getBoolean(
1016                com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
1017    }
1018
1019    /**
1020     * @return A formatted string of the next alarm (for showing on the lock screen),
1021     *   or null if there is no next alarm.
1022     */
1023    public String getNextAlarm() {
1024        String nextAlarm = Settings.System.getStringForUser(mContentResolver,
1025                Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT);
1026        if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
1027            return null;
1028        }
1029        return nextAlarm;
1030    }
1031
1032    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
1033        try {
1034            return getLockSettings().getBoolean(secureSettingKey, defaultValue,
1035                    getCurrentOrCallingUserId());
1036        } catch (RemoteException re) {
1037            return defaultValue;
1038        }
1039    }
1040
1041    private void setBoolean(String secureSettingKey, boolean enabled) {
1042        try {
1043            getLockSettings().setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
1044        } catch (RemoteException re) {
1045            // What can we do?
1046            Log.e(TAG, "Couldn't write boolean " + secureSettingKey + re);
1047        }
1048    }
1049
1050    public int[] getAppWidgets() {
1051        String appWidgetIdString = Settings.Secure.getStringForUser(
1052                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
1053                UserHandle.USER_CURRENT);
1054        String delims = ",";
1055        if (appWidgetIdString != null) {
1056            String[] appWidgetStringIds = appWidgetIdString.split(delims);
1057            int[] appWidgetIds = new int[appWidgetStringIds.length];
1058            for (int i = 0; i < appWidgetStringIds.length; i++) {
1059                String appWidget = appWidgetStringIds[i];
1060                try {
1061                    appWidgetIds[i] = Integer.decode(appWidget);
1062                } catch (NumberFormatException e) {
1063                    return null;
1064                }
1065            }
1066            return appWidgetIds;
1067        }
1068        return new int[0];
1069    }
1070
1071    private static String combineStrings(int[] list, String separator) {
1072        int listLength = list.length;
1073
1074        switch (listLength) {
1075            case 0: {
1076                return "";
1077            }
1078            case 1: {
1079                return Integer.toString(list[0]);
1080            }
1081        }
1082
1083        int strLength = 0;
1084        int separatorLength = separator.length();
1085
1086        String[] stringList = new String[list.length];
1087        for (int i = 0; i < listLength; i++) {
1088            stringList[i] = Integer.toString(list[i]);
1089            strLength += stringList[i].length();
1090            if (i < listLength - 1) {
1091                strLength += separatorLength;
1092            }
1093        }
1094
1095        StringBuilder sb = new StringBuilder(strLength);
1096
1097        for (int i = 0; i < listLength; i++) {
1098            sb.append(list[i]);
1099            if (i < listLength - 1) {
1100                sb.append(separator);
1101            }
1102        }
1103
1104        return sb.toString();
1105    }
1106
1107    private void writeAppWidgets(int[] appWidgetIds) {
1108        Settings.Secure.putString(mContentResolver,
1109        Settings.Secure.putStringForUser(mContentResolver,
1110                        Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
1111                        combineStrings(appWidgetIds, ","),
1112                        UserHandle.USER_CURRENT);
1113    }
1114
1115    public void addAppWidget(int widgetId, int index) {
1116        int[] widgets = getAppWidgets();
1117        int[] newWidgets = new int[widgets.length + 1];
1118        for (int i = 0, j = 0; i < newWidgets.length; i++) {
1119            if (index == i) {
1120                newWidgets[i] = widgetId;
1121                i++;
1122            }
1123            if (i < newWidgets.length) {
1124                newWidgets[i] = widgets[j];
1125                j++;
1126            }
1127        }
1128        writeAppWidgets(newWidgets);
1129    }
1130
1131    public boolean removeAppWidget(int widgetId, int index) {
1132        int[] widgets = getAppWidgets();
1133        int[] newWidgets = new int[widgets.length - 1];
1134        for (int i = 0, j = 0; i < widgets.length; i++) {
1135            if (index == i) {
1136                if (widgets[i] != widgetId) {
1137                    return false;
1138                }
1139                // continue...
1140            } else {
1141                newWidgets[j] = widgets[i];
1142                j++;
1143            }
1144        }
1145        writeAppWidgets(newWidgets);
1146        return true;
1147    }
1148
1149    private long getLong(String secureSettingKey, long defaultValue) {
1150        try {
1151            return getLockSettings().getLong(secureSettingKey, defaultValue,
1152                    getCurrentOrCallingUserId());
1153        } catch (RemoteException re) {
1154            return defaultValue;
1155        }
1156    }
1157
1158    private void setLong(String secureSettingKey, long value) {
1159        setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1160    }
1161
1162    private void setLong(String secureSettingKey, long value, int userHandle) {
1163        try {
1164            getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId());
1165        } catch (RemoteException re) {
1166            // What can we do?
1167            Log.e(TAG, "Couldn't write long " + secureSettingKey + re);
1168        }
1169    }
1170
1171    private String getString(String secureSettingKey) {
1172        return getString(secureSettingKey, getCurrentOrCallingUserId());
1173    }
1174
1175    private String getString(String secureSettingKey, int userHandle) {
1176        try {
1177            return getLockSettings().getString(secureSettingKey, null, userHandle);
1178        } catch (RemoteException re) {
1179            return null;
1180        }
1181    }
1182
1183    private void setString(String secureSettingKey, String value, int userHandle) {
1184        try {
1185            getLockSettings().setString(secureSettingKey, value, userHandle);
1186        } catch (RemoteException re) {
1187            // What can we do?
1188            Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
1189        }
1190    }
1191
1192    public boolean isSecure() {
1193        long mode = getKeyguardStoredPasswordQuality();
1194        final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
1195        final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
1196                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
1197                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
1198                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
1199        final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
1200                || isPassword && savedPasswordExists();
1201        return secure;
1202    }
1203
1204    /**
1205     * Sets the emergency button visibility based on isEmergencyCallCapable().
1206     *
1207     * If the emergency button is visible, sets the text on the emergency button
1208     * to indicate what action will be taken.
1209     *
1210     * If there's currently a call in progress, the button will take them to the call
1211     * @param button the button to update
1212     * @param the phone state:
1213     *  {@link TelephonyManager#CALL_STATE_IDLE}
1214     *  {@link TelephonyManager#CALL_STATE_RINGING}
1215     *  {@link TelephonyManager#CALL_STATE_OFFHOOK}
1216     * @param shown indicates whether the given screen wants the emergency button to show at all
1217     * @param button
1218     * @param phoneState
1219     * @param shown shown if true; hidden if false
1220     * @param upperCase if true, converts button label string to upper case
1221     */
1222    public void updateEmergencyCallButtonState(Button button, int  phoneState, boolean shown,
1223            boolean upperCase, boolean showIcon) {
1224        if (isEmergencyCallCapable() && shown) {
1225            button.setVisibility(View.VISIBLE);
1226        } else {
1227            button.setVisibility(View.GONE);
1228            return;
1229        }
1230
1231        int textId;
1232        if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
1233            // show "return to call" text and show phone icon
1234            textId = R.string.lockscreen_return_to_call;
1235            int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
1236            button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
1237        } else {
1238            textId = R.string.lockscreen_emergency_call;
1239            int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
1240            button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
1241        }
1242        if (upperCase) {
1243            CharSequence original = mContext.getResources().getText(textId);
1244            String upper = original != null ? original.toString().toUpperCase() : null;
1245            button.setText(upper);
1246        } else {
1247            button.setText(textId);
1248        }
1249    }
1250
1251    /**
1252     * @deprecated
1253     * @param button
1254     * @param phoneState
1255     * @param shown
1256     */
1257    public void updateEmergencyCallButtonState(Button button, int  phoneState, boolean shown) {
1258        updateEmergencyCallButtonState(button, phoneState, shown, false, true);
1259    }
1260
1261    /**
1262     * Resumes a call in progress. Typically launched from the EmergencyCall button
1263     * on various lockscreens.
1264     *
1265     * @return true if we were able to tell InCallScreen to show.
1266     */
1267    public boolean resumeCall() {
1268        ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
1269        try {
1270            if (phone != null && phone.showCallScreen()) {
1271                return true;
1272            }
1273        } catch (RemoteException e) {
1274            // What can we do?
1275        }
1276        return false;
1277    }
1278
1279    private void finishBiometricWeak() {
1280        setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
1281
1282        // Launch intent to show final screen, this also
1283        // moves the temporary gallery to the actual gallery
1284        Intent intent = new Intent();
1285        intent.setClassName("com.android.facelock",
1286                "com.android.facelock.SetupEndScreen");
1287        mContext.startActivity(intent);
1288    }
1289
1290    public void setPowerButtonInstantlyLocks(boolean enabled) {
1291        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
1292    }
1293
1294    public boolean getPowerButtonInstantlyLocks() {
1295        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
1296    }
1297
1298}
1299