Skip to content

Commit e24f478

Browse files
committed
Convert password settings to a PreferenceFragment [DO NOT MERGE]
Easier to write code for than raw Fragments. Change-Id: I0b37fbb342f82ffb3b978cb38c8d549b8da78868
1 parent cd876c9 commit e24f478

File tree

5 files changed

+195
-278
lines changed

5 files changed

+195
-278
lines changed

app/src/main/java/com/afwsamples/testdpc/policy/keyguard/PasswordConstraintsFragment.java

Lines changed: 134 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,27 @@
2222
import android.content.Context;
2323
import android.content.Intent;
2424
import android.os.Bundle;
25-
import android.text.Editable;
26-
import android.text.TextUtils;
27-
import android.text.TextWatcher;
28-
import android.view.LayoutInflater;
29-
import android.view.View;
30-
import android.view.ViewGroup;
31-
import android.widget.Button;
32-
import android.widget.EditText;
33-
import android.widget.RadioButton;
34-
import android.widget.RadioGroup;
25+
import android.preference.EditTextPreference;
26+
import android.preference.ListPreference;
27+
import android.preference.Preference;
28+
import android.preference.PreferenceFragment;
3529
import android.widget.Toast;
3630

3731
import com.afwsamples.testdpc.DeviceAdminReceiver;
3832
import com.afwsamples.testdpc.R;
3933

40-
import java.util.LinkedHashMap;
41-
import java.util.Map;
34+
import java.util.ArrayList;
35+
import java.util.List;
36+
import java.util.TreeMap;
4237

4338
/**
4439
* This fragment provides functionalities to set password constraint policies as a profile
45-
* or device owner.
40+
* or device owner. In the former case, it is also possible to set password constraints on
41+
* the parent profile.
4642
*
4743
* <p>These include:
4844
* <ul>
45+
* <li>{@link DevicePolicyManager#setPasswordQuality(ComponentName, int)}</li>
4946
* <li>{@link DevicePolicyManager#setPasswordMinimumLength(ComponentName, String)}</li>
5047
* <li>{@link DevicePolicyManager#setPasswordMinimumLetters(ComponentName, String)}</li>
5148
* <li>{@link DevicePolicyManager#setPasswordMinimumNumeric(ComponentName, String)}</li>
@@ -55,10 +52,33 @@
5552
* <li>{@link DevicePolicyManager#setPasswordMinimumNonLetter(ComponentName, String)}</li>
5653
* </ul>
5754
*/
58-
public final class PasswordConstraintsFragment extends Fragment implements
59-
RadioGroup.OnCheckedChangeListener, TextWatcher {
55+
public final class PasswordConstraintsFragment extends PreferenceFragment implements
56+
Preference.OnPreferenceChangeListener {
6057

61-
private static final Map<Integer, Integer> PASSWORD_QUALITIES = new LinkedHashMap<>(7);
58+
private DevicePolicyManager mDevicePolicyManager;
59+
private ComponentName mAdminComponent;
60+
61+
private DevicePolicyManager getDpm() {
62+
return mDevicePolicyManager;
63+
}
64+
65+
private ComponentName getAdmin() {
66+
return mAdminComponent;
67+
}
68+
69+
abstract static class Keys {
70+
final static String QUALITY = "minimum_password_quality";
71+
72+
final static String MIN_LENGTH = "password_min_length";
73+
final static String MIN_LETTERS = "password_min_letters";
74+
final static String MIN_NUMERIC = "password_min_numeric";
75+
final static String MIN_LOWERCASE = "password_min_lowercase";
76+
final static String MIN_UPPERCASE = "password_min_uppercase";
77+
final static String MIN_SYMBOLS = "password_min_symbols";
78+
final static String MIN_NONLETTER = "password_min_nonletter";
79+
}
80+
81+
private static final TreeMap<Integer, Integer> PASSWORD_QUALITIES = new TreeMap<>();
6282
static {
6383
// IDs of settings for {@link DevicePolicyManager#setPasswordQuality(ComponentName, int)}.
6484
final int[] policyIds = new int[] {
@@ -88,128 +108,121 @@ public final class PasswordConstraintsFragment extends Fragment implements
88108
}
89109
};
90110

91-
// Radio list of all complexity settings, as defined above.
92-
private RadioGroup mQualityGroup;
93-
94-
// Individual minimum password attribute requirements.
95-
private EditText mMinLength;
96-
private EditText mMinLetters;
97-
private EditText mMinNumeric;
98-
private EditText mMinLowerCase;
99-
private EditText mMinUpperCase;
100-
private EditText mMinSymbols;
101-
private EditText mMinNonLetter;
102-
103-
private DevicePolicyManager mDpm;
104-
private ComponentName mAdminComponent;
105-
106111
@Override
107112
public void onCreate(Bundle savedInstanceState) {
108113
super.onCreate(savedInstanceState);
109114
getActivity().getActionBar().setTitle(R.string.password_constraints);
110115

111-
mDpm = (DevicePolicyManager) getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
116+
mDevicePolicyManager = (DevicePolicyManager)
117+
getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
112118
mAdminComponent = DeviceAdminReceiver.getComponentName(getActivity());
113-
}
114-
115-
@Override
116-
public View onCreateView(LayoutInflater layoutInflater, ViewGroup container,
117-
Bundle savedInstanceState) {
118-
final View root = layoutInflater.inflate(R.layout.password_quality, null);
119-
120-
// Create numeric text fields
121-
mMinLength = findAndPrepareField(root, R.id.password_min_length);
122-
mMinLetters = findAndPrepareField(root, R.id.password_min_letters);
123-
mMinNumeric = findAndPrepareField(root, R.id.password_min_numeric);
124-
mMinLowerCase = findAndPrepareField(root, R.id.password_min_lowercase);
125-
mMinUpperCase = findAndPrepareField(root, R.id.password_min_uppercase);
126-
mMinSymbols = findAndPrepareField(root, R.id.password_min_symbols);
127-
mMinNonLetter = findAndPrepareField(root, R.id.password_min_nonletter);
128-
129-
// Create radio group for password quality
130-
mQualityGroup = (RadioGroup) root.findViewById(R.id.password_quality);
131-
for (Map.Entry<Integer, Integer> entry : PASSWORD_QUALITIES.entrySet()) {
132-
final RadioButton choice = new RadioButton(getContext());
133-
choice.setId(entry.getKey());
134-
choice.setText(entry.getValue());
135-
mQualityGroup.addView(choice);
136-
}
137-
mQualityGroup.setOnCheckedChangeListener(this);
138-
139-
return root;
140-
}
141119

142-
@Override
143-
public void onResume() {
144-
super.onResume();
145-
146-
// Set the password quality radio group to show the requirement, if there is one.
147-
mQualityGroup.check(mDpm.getPasswordQuality(mAdminComponent));
148-
149-
// Update all of our minimum requirement fields via getPasswordMinimum(.*)
150-
mMinLength.setText(Integer.toString(mDpm.getPasswordMinimumLength(mAdminComponent)));
151-
mMinLetters.setText(Integer.toString(mDpm.getPasswordMinimumLetters(mAdminComponent)));
152-
mMinNumeric.setText(Integer.toString(mDpm.getPasswordMinimumNumeric(mAdminComponent)));
153-
mMinLowerCase.setText(Integer.toString(mDpm.getPasswordMinimumLowerCase(mAdminComponent)));
154-
mMinUpperCase.setText(Integer.toString(mDpm.getPasswordMinimumUpperCase(mAdminComponent)));
155-
mMinSymbols.setText(Integer.toString(mDpm.getPasswordMinimumSymbols(mAdminComponent)));
156-
mMinNonLetter.setText(Integer.toString(mDpm.getPasswordMinimumNonLetter(mAdminComponent)));
157-
158-
sendPasswordChangedBroadcast();
159-
}
120+
addPreferencesFromResource(R.xml.password_constraint_preferences);
160121

161-
@Override
162-
public void onCheckedChanged(RadioGroup view, int checkedId) {
163-
if (view == mQualityGroup) {
164-
mDpm.setPasswordQuality(mAdminComponent, checkedId);
122+
// Populate password quality settings - messy because the only API for this requires two
123+
// separate String[]s.
124+
List<CharSequence> entries = new ArrayList<>();
125+
List<CharSequence> values = new ArrayList<>();
126+
for (TreeMap.Entry<Integer, Integer> entry : PASSWORD_QUALITIES.entrySet()) {
127+
values.add(Integer.toString(entry.getKey()));
128+
entries.add(getString(entry.getValue()));
165129
}
166-
sendPasswordChangedBroadcast();
130+
ListPreference quality = (ListPreference) findPreference(Keys.QUALITY);
131+
quality.setEntries(entries.toArray(new CharSequence[0]));
132+
quality.setEntryValues(values.toArray(new CharSequence[0]));
133+
134+
// Minimum quality requirement.
135+
setup(Keys.QUALITY, PASSWORD_QUALITIES.floorKey(getDpm().getPasswordQuality(getAdmin())));
136+
137+
// Minimum length requirements.
138+
setup(Keys.MIN_LENGTH, getDpm().getPasswordMinimumLength(getAdmin()));
139+
setup(Keys.MIN_LETTERS, getDpm().getPasswordMinimumLetters(getAdmin()));
140+
setup(Keys.MIN_NUMERIC, getDpm().getPasswordMinimumNumeric(getAdmin()));
141+
setup(Keys.MIN_LOWERCASE, getDpm().getPasswordMinimumLowerCase(getAdmin()));
142+
setup(Keys.MIN_UPPERCASE, getDpm().getPasswordMinimumUpperCase(getAdmin()));
143+
setup(Keys.MIN_SYMBOLS, getDpm().getPasswordMinimumSymbols(getAdmin()));
144+
setup(Keys.MIN_NONLETTER, getDpm().getPasswordMinimumNonLetter(getAdmin()));
167145
}
168146

169147
@Override
170-
public void afterTextChanged(Editable editable) {
171-
if (TextUtils.isEmpty(editable.toString())) {
172-
return;
173-
}
174-
148+
public boolean onPreferenceChange(Preference preference, Object newValue) {
175149
final int value;
176-
try {
177-
value = Integer.parseInt(editable.toString());
178-
} catch (NumberFormatException e) {
179-
Toast.makeText(getActivity(), R.string.not_valid_input, Toast.LENGTH_SHORT).show();
180-
return;
150+
if (newValue instanceof String && ((String) newValue).length() != 0) {
151+
try {
152+
value = Integer.parseInt((String) newValue);
153+
} catch (NumberFormatException e) {
154+
Toast.makeText(getActivity(), R.string.not_valid_input, Toast.LENGTH_SHORT).show();
155+
return false;
156+
}
157+
} else {
158+
value = 0;
181159
}
182160

183-
if (editable == mMinLength.getEditableText()) {
184-
mDpm.setPasswordMinimumLength(mAdminComponent, value);
185-
} else if (editable == mMinLetters.getEditableText()) {
186-
mDpm.setPasswordMinimumLetters(mAdminComponent, value);
187-
} else if (editable == mMinNumeric.getEditableText()) {
188-
mDpm.setPasswordMinimumNumeric(mAdminComponent, value);
189-
} else if (editable == mMinLowerCase.getEditableText()) {
190-
mDpm.setPasswordMinimumLowerCase(mAdminComponent, value);
191-
} else if (editable == mMinUpperCase.getEditableText()) {
192-
mDpm.setPasswordMinimumUpperCase(mAdminComponent, value);
193-
} else if (editable == mMinSymbols.getEditableText()) {
194-
mDpm.setPasswordMinimumSymbols(mAdminComponent, value);
195-
} else if (editable == mMinNonLetter.getEditableText()) {
196-
mDpm.setPasswordMinimumNonLetter(mAdminComponent, value);
161+
// By default, show the new value as a summary.
162+
CharSequence summary = newValue.toString();
163+
164+
switch (preference.getKey()) {
165+
case Keys.QUALITY: {
166+
final ListPreference list = (ListPreference) preference;
167+
// Store newValue now so getEntry() can return the new setting
168+
list.setValue((String) newValue);
169+
summary = list.getEntry();
170+
getDpm().setPasswordQuality(getAdmin(), value);
171+
break;
172+
}
173+
case Keys.MIN_LENGTH:
174+
getDpm().setPasswordMinimumLength(getAdmin(), value);
175+
break;
176+
case Keys.MIN_LETTERS:
177+
getDpm().setPasswordMinimumLetters(getAdmin(), value);
178+
break;
179+
case Keys.MIN_NUMERIC:
180+
getDpm().setPasswordMinimumNumeric(getAdmin(), value);
181+
break;
182+
case Keys.MIN_LOWERCASE:
183+
getDpm().setPasswordMinimumLowerCase(getAdmin(), value);
184+
break;
185+
case Keys.MIN_UPPERCASE:
186+
getDpm().setPasswordMinimumUpperCase(getAdmin(), value);
187+
break;
188+
case Keys.MIN_SYMBOLS:
189+
getDpm().setPasswordMinimumSymbols(getAdmin(), value);
190+
break;
191+
case Keys.MIN_NONLETTER:
192+
getDpm().setPasswordMinimumNonLetter(getAdmin(), value);
193+
break;
194+
default:
195+
return false;
197196
}
198-
sendPasswordChangedBroadcast();
199-
}
200197

201-
@Override
202-
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
198+
preference.setSummary(summary);
199+
sendPasswordRequirementsChanged();
200+
return true;
203201
}
204202

205-
@Override
206-
public void onTextChanged(CharSequence s, int start, int count, int after) {
207-
}
203+
/**
204+
* Set an initial value. Updates the summary to match.
205+
*/
206+
private void setup(String key, Object adminSetting) {
207+
Preference field = findPreference(key);
208+
field.setOnPreferenceChangeListener(this);
208209

209-
private EditText findAndPrepareField(View root, final int id) {
210-
EditText field = (EditText) root.findViewById(id);
211-
field.addTextChangedListener(this);
212-
return field;
210+
if (adminSetting == null) {
211+
return;
212+
}
213+
214+
final String stringSetting = adminSetting.toString();
215+
CharSequence summary = stringSetting;
216+
217+
if (field instanceof EditTextPreference) {
218+
EditTextPreference p = (EditTextPreference) field;
219+
p.setText(stringSetting);
220+
} else if (field instanceof ListPreference) {
221+
ListPreference p = (ListPreference) field;
222+
p.setValue(stringSetting);
223+
summary = p.getEntry();
224+
}
225+
field.setSummary(summary);
213226
}
214227

215228
/**
@@ -221,10 +234,10 @@ private EditText findAndPrepareField(View root, final int id) {
221234
*
222235
* <p>May trigger a show/hide of the notification warning to change the password through
223236
* Settings.
224-
**/
225-
private void sendPasswordChangedBroadcast() {
237+
*/
238+
private void sendPasswordRequirementsChanged() {
226239
Intent changedIntent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_REQUIREMENTS_CHANGED);
227-
changedIntent.setComponent(mAdminComponent);
240+
changedIntent.setComponent(getAdmin());
228241
getContext().sendBroadcast(changedIntent);
229242
}
230243
}

0 commit comments

Comments
 (0)