/**
  * Save a lock pattern.
  *
  * @param pattern The new pattern to save.
  * @param isFallback Specifies if this is a fallback to biometric weak
  */
 public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
   // Compute the hash
   final byte[] hash = LockPatternUtils.patternToHash(pattern);
   try {
     // Write the hash to file
     RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "rw");
     // Truncate the file if pattern is null, to clear the lock
     if (pattern == null) {
       raf.setLength(0);
     } else {
       raf.write(hash, 0, hash.length);
     }
     raf.close();
     DevicePolicyManager dpm = getDevicePolicyManager();
     KeyStore keyStore = KeyStore.getInstance();
     if (pattern != null) {
       keyStore.password(patternToString(pattern));
       setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
       if (!isFallback) {
         deleteGallery();
         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
         dpm.setActivePasswordState(
             DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern.size(), 0, 0, 0, 0, 0, 0);
       } else {
         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
         setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
         finishBiometricWeak();
         dpm.setActivePasswordState(
             DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, 0, 0, 0, 0, 0, 0, 0);
       }
     } else {
       if (keyStore.isEmpty()) {
         keyStore.reset();
       }
       dpm.setActivePasswordState(
           DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
     }
   } catch (FileNotFoundException fnfe) {
     // Cant do much, unless we want to fail over to using the settings
     // provider
     Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
   } catch (IOException ioe) {
     // Cant do much
     Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
   }
 }
  /**
   * Save a lock password. Does not ensure that the password is as good as the requested mode, but
   * will adjust the mode to be as good as the pattern.
   *
   * @param password The password to save
   * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
   * @param isFallback Specifies if this is a fallback to biometric weak
   */
  public void saveLockPassword(String password, int quality, boolean isFallback) {
    // Compute the hash
    final byte[] hash = passwordToHash(password);
    try {
      // Write the hash to file
      RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "rw");
      // Truncate the file if pattern is null, to clear the lock
      if (password == null) {
        raf.setLength(0);
      } else {
        raf.write(hash, 0, hash.length);
      }
      raf.close();
      DevicePolicyManager dpm = getDevicePolicyManager();
      KeyStore keyStore = KeyStore.getInstance();
      if (password != null) {
        // Update the encryption password.
        updateEncryptionPassword(password);

        // Update the keystore password
        keyStore.password(password);

        int computedQuality = computePasswordQuality(password);
        if (!isFallback) {
          deleteGallery();
          setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
          if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
            int letters = 0;
            int uppercase = 0;
            int lowercase = 0;
            int numbers = 0;
            int symbols = 0;
            int nonletter = 0;
            for (int i = 0; i < password.length(); i++) {
              char c = password.charAt(i);
              if (c >= 'A' && c <= 'Z') {
                letters++;
                uppercase++;
              } else if (c >= 'a' && c <= 'z') {
                letters++;
                lowercase++;
              } else if (c >= '0' && c <= '9') {
                numbers++;
                nonletter++;
              } else {
                symbols++;
                nonletter++;
              }
            }
            dpm.setActivePasswordState(
                Math.max(quality, computedQuality),
                password.length(),
                letters,
                uppercase,
                lowercase,
                numbers,
                symbols,
                nonletter);
          } else {
            // The password is not anything.
            dpm.setActivePasswordState(
                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
          }
        } else {
          // Case where it's a fallback for biometric weak
          setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
          setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
          finishBiometricWeak();
          dpm.setActivePasswordState(
              DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, 0, 0, 0, 0, 0, 0, 0);
        }
        // Add the password to the password history. We assume all
        // password
        // hashes have the same length for simplicity of implementation.
        String passwordHistory = getString(PASSWORD_HISTORY_KEY);
        if (passwordHistory == null) {
          passwordHistory = new String();
        }
        int passwordHistoryLength = getRequestedPasswordHistoryLength();
        if (passwordHistoryLength == 0) {
          passwordHistory = "";
        } else {
          passwordHistory = new String(hash) + "," + passwordHistory;
          // Cut it to contain passwordHistoryLength hashes
          // and passwordHistoryLength -1 commas.
          passwordHistory =
              passwordHistory.substring(
                  0,
                  Math.min(
                      hash.length * passwordHistoryLength + passwordHistoryLength - 1,
                      passwordHistory.length()));
        }
        setString(PASSWORD_HISTORY_KEY, passwordHistory);
      } else {
        // Conditionally reset the keystore if empty. If
        // non-empty, we are just switching key guard type
        if (keyStore.isEmpty()) {
          keyStore.reset();
        }
        dpm.setActivePasswordState(
            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
      }
    } catch (FileNotFoundException fnfe) {
      // Cant do much, unless we want to fail over to using the settings provider
      Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename);
    } catch (IOException ioe) {
      // Cant do much
      Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename);
    }
  }