entry : PASSWORD_QUALITIES.entrySet()) {
values.add(Integer.toString(entry.getKey()));
entries.add(getString(entry.getValue()));
}
ListPreference quality = (ListPreference) findPreference(Keys.QUALITY);
quality.setEntries(entries.toArray(new CharSequence[0]));
quality.setEntryValues(values.toArray(new CharSequence[0]));
// Expiration times.
setup(Keys.EXPIRATION_TIME, null);
setup(Keys.HISTORY_LENGTH, getDpm().getPasswordHistoryLength(getAdmin()));
// Minimum quality requirement.
setup(Keys.QUALITY, PASSWORD_QUALITIES.floorKey(getDpm().getPasswordQuality(getAdmin())));
// Minimum length requirements.
setup(Keys.MIN_LENGTH, getDpm().getPasswordMinimumLength(getAdmin()));
setup(Keys.MIN_LETTERS, getDpm().getPasswordMinimumLetters(getAdmin()));
setup(Keys.MIN_NUMERIC, getDpm().getPasswordMinimumNumeric(getAdmin()));
setup(Keys.MIN_LOWERCASE, getDpm().getPasswordMinimumLowerCase(getAdmin()));
setup(Keys.MIN_UPPERCASE, getDpm().getPasswordMinimumUpperCase(getAdmin()));
setup(Keys.MIN_SYMBOLS, getDpm().getPasswordMinimumSymbols(getAdmin()));
setup(Keys.MIN_NONLETTER, getDpm().getPasswordMinimumNonLetter(getAdmin()));
setPreferencesConstraint();
}
@Override
public void onResume() {
super.onResume();
// Settings that may have been changed by other users need updating.
updateExpirationTimes();
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final int value;
if (newValue instanceof String && ((String) newValue).length() != 0) {
try {
value = Integer.parseInt((String) newValue);
} catch (NumberFormatException e) {
Toast.makeText(getActivity(), R.string.not_valid_input, Toast.LENGTH_SHORT).show();
return false;
}
} else {
value = 0;
}
// By default, show the new value as a summary.
CharSequence summary = newValue.toString();
switch (preference.getKey()) {
case Keys.EXPIRATION_TIME: {
getDpm().setPasswordExpirationTimeout(getAdmin(), TimeUnit.SECONDS.toMillis(value));
updateExpirationTimes();
return true;
}
case Keys.HISTORY_LENGTH:
getDpm().setPasswordHistoryLength(getAdmin(), value);
break;
case Keys.QUALITY: {
final ListPreference list = (ListPreference) preference;
// Store newValue now so getEntry() can return the new setting
list.setValue((String) newValue);
summary = list.getEntry();
getDpm().setPasswordQuality(getAdmin(), value);
refreshPreferences();
break;
}
case Keys.MIN_LENGTH:
getDpm().setPasswordMinimumLength(getAdmin(), value);
break;
case Keys.MIN_LETTERS:
getDpm().setPasswordMinimumLetters(getAdmin(), value);
break;
case Keys.MIN_NUMERIC:
getDpm().setPasswordMinimumNumeric(getAdmin(), value);
break;
case Keys.MIN_LOWERCASE:
getDpm().setPasswordMinimumLowerCase(getAdmin(), value);
break;
case Keys.MIN_UPPERCASE:
getDpm().setPasswordMinimumUpperCase(getAdmin(), value);
break;
case Keys.MIN_SYMBOLS:
getDpm().setPasswordMinimumSymbols(getAdmin(), value);
break;
case Keys.MIN_NONLETTER:
getDpm().setPasswordMinimumNonLetter(getAdmin(), value);
break;
default:
return false;
}
preference.setSummary(summary);
sendPasswordRequirementsChanged();
return true;
}
/**
* Enable and disable password constraint preferences based on the current password quality.
*/
private void setPreferencesConstraint() {
// Minimum length can be set for most qualities
mMinLength.setCustomConstraint(
() -> getDpm().getPasswordQuality(getAdmin()) >= PASSWORD_QUALITY_NUMERIC
? NO_CUSTOM_CONSTRIANT
: R.string.not_for_password_quality);
// Other minimums are only active for the highest quality
CustomConstraint constraint =
() -> getDpm().getPasswordQuality(getAdmin()) == PASSWORD_QUALITY_COMPLEX
? NO_CUSTOM_CONSTRIANT
: R.string.not_for_password_quality;
mMinLetters.setCustomConstraint(constraint);
mMinNumeric.setCustomConstraint(constraint);
mMinLower.setCustomConstraint(constraint);
mMinUpper.setCustomConstraint(constraint);
mMinSymbols.setCustomConstraint(constraint);
mMinNonLetter.setCustomConstraint(constraint);
}
private void refreshPreferences() {
mMinLength.refreshEnabledState();
mMinLetters.refreshEnabledState();
mMinNumeric.refreshEnabledState();
mMinLower.refreshEnabledState();
mMinUpper.refreshEnabledState();
mMinSymbols.refreshEnabledState();
mMinNonLetter.refreshEnabledState();
}
/**
* Set an initial value. Updates the summary to match.
*/
private void setup(String key, Object adminSetting) {
Preference field = findPreference(key);
field.setOnPreferenceChangeListener(this);
if (adminSetting == null) {
return;
}
final String stringSetting = adminSetting.toString();
CharSequence summary = stringSetting;
if (field instanceof EditTextPreference) {
EditTextPreference p = (EditTextPreference) field;
p.setText(stringSetting);
} else if (field instanceof ListPreference) {
ListPreference p = (ListPreference) field;
p.setValue(stringSetting);
summary = p.getEntry();
}
field.setSummary(summary);
}
/**
* Refresh summaries for settings related to the next password expiration.
*/
private void updateExpirationTimes() {
final Preference byAdmin = findPreference(Keys.EXPIRATION_TIME);
final Preference byAll = findPreference(Keys.EXPIRATION_BY_ALL);
byAdmin.setSummary(Util.formatTimestamp(getDpm().getPasswordExpiration(getAdmin())));
byAll.setSummary(Util.formatTimestamp(getDpm().getPasswordExpiration(null)));
}
/**
* Notify the admin receiver that something about the password has changed - in this context,
* a minimum password requirement policy.
*
* This has to be sent manually because the system server only sends broadcasts for changes to
* the actual password, not any of the constraints related it it.
*
* May trigger a show/hide of the notification warning to change the password through
* Settings.
*/
private void sendPasswordRequirementsChanged() {
Intent changedIntent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_REQUIREMENTS_CHANGED);
changedIntent.setComponent(getAdmin());
getActivity().sendBroadcast(changedIntent);
}
}