Skip to content

Commit 43813b6

Browse files
committed
Password expiration settings for TestDPC
Change-Id: I4f7935239b2c1e4a501c7176b9f37accc66a81e7
1 parent fcd3707 commit 43813b6

File tree

5 files changed

+93
-0
lines changed

5 files changed

+93
-0
lines changed

app/src/main/java/com/afwsamples/testdpc/DeviceAdminReceiver.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import android.widget.Toast;
3939

4040
import com.afwsamples.testdpc.common.LaunchIntentUtil;
41+
import com.afwsamples.testdpc.common.Util;
4142
import com.afwsamples.testdpc.cosu.EnableCosuActivity;
4243
import com.afwsamples.testdpc.syncauth.FinishSyncAuthDeviceOwnerActivity;
4344
import com.afwsamples.testdpc.syncauth.FinishSyncAuthProfileOwnerActivity;
@@ -236,6 +237,23 @@ public static ComponentName getComponentName(Context context) {
236237
return new ComponentName(context.getApplicationContext(), DeviceAdminReceiver.class);
237238
}
238239

240+
@Override
241+
public void onPasswordExpiring(Context context, Intent intent) {
242+
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(
243+
Context.DEVICE_POLICY_SERVICE);
244+
245+
final long timeNow = System.currentTimeMillis();
246+
final long timeAdminExpires =
247+
devicePolicyManager.getPasswordExpiration(getComponentName(context));
248+
final boolean expiredBySelf = (timeNow >= timeAdminExpires && timeAdminExpires != 0);
249+
250+
Util.showNotification(context, R.string.password_expired_title,
251+
context.getString(expiredBySelf
252+
? R.string.password_expired_by_self
253+
: R.string.password_expired_by_others),
254+
Util.PASSWORD_EXPIRATION_NOTIFICATION_ID);
255+
}
256+
239257
@Override
240258
public void onPasswordFailed(Context context, Intent intent) {
241259
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(

app/src/main/java/com/afwsamples/testdpc/common/Util.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.app.Notification;
2020
import android.app.NotificationManager;
2121
import android.content.Context;
22+
import android.text.format.DateUtils;
2223

2324
import com.afwsamples.testdpc.R;
2425

@@ -27,6 +28,8 @@
2728
*/
2829
public class Util {
2930

31+
public static final int PASSWORD_EXPIRATION_NOTIFICATION_ID = 2;
32+
3033
public static void showNotification(Context context, int titleId, String msg,
3134
int notificationId) {
3235
NotificationManager mNotificationManager =
@@ -39,4 +42,23 @@ public static void showNotification(Context context, int titleId, String msg,
3942
.build();
4043
mNotificationManager.notify(notificationId, notification);
4144
}
45+
46+
/**
47+
* Format a friendly datetime for the current locale according to device policy documentation.
48+
* If the timestamp doesn't represent a real date, it will be interpreted as {@code null}.
49+
*
50+
* @return A {@link CharSequence} such as "12:35 PM today" or "June 15, 2033", or {@code null}
51+
* in the case that {@param timestampMs} equals zero.
52+
*/
53+
public static CharSequence formatTimestamp(long timestampMs) {
54+
if (timestampMs == 0) {
55+
// DevicePolicyManager documentation describes this timestamp as having no effect,
56+
// so show nothing for this case as the policy has not been set.
57+
return null;
58+
}
59+
60+
return DateUtils.formatSameDayTime(timestampMs, System.currentTimeMillis(),
61+
DateUtils.FORMAT_SHOW_WEEKDAY, DateUtils.FORMAT_SHOW_TIME);
62+
}
63+
4264
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030

3131
import com.afwsamples.testdpc.DeviceAdminReceiver;
3232
import com.afwsamples.testdpc.R;
33+
import com.afwsamples.testdpc.common.Util;
3334

3435
import java.util.ArrayList;
3536
import java.util.List;
3637
import java.util.TreeMap;
38+
import java.util.concurrent.TimeUnit;
3739

3840
/**
3941
* This fragment provides functionalities to set password constraint policies as a profile
@@ -67,6 +69,9 @@ private ComponentName getAdmin() {
6769
}
6870

6971
abstract static class Keys {
72+
final static String EXPIRATION_TIME = "password_expiration_time";
73+
final static String EXPIRATION_BY_ALL = "password_expiration_aggregate";
74+
7075
final static String QUALITY = "minimum_password_quality";
7176

7277
final static String MIN_LENGTH = "password_min_length";
@@ -131,6 +136,9 @@ public void onCreate(Bundle savedInstanceState) {
131136
quality.setEntries(entries.toArray(new CharSequence[0]));
132137
quality.setEntryValues(values.toArray(new CharSequence[0]));
133138

139+
// Expiration times.
140+
setup(Keys.EXPIRATION_TIME, null);
141+
134142
// Minimum quality requirement.
135143
setup(Keys.QUALITY, PASSWORD_QUALITIES.floorKey(getDpm().getPasswordQuality(getAdmin())));
136144

@@ -144,6 +152,14 @@ public void onCreate(Bundle savedInstanceState) {
144152
setup(Keys.MIN_NONLETTER, getDpm().getPasswordMinimumNonLetter(getAdmin()));
145153
}
146154

155+
@Override
156+
public void onResume() {
157+
super.onResume();
158+
159+
// Settings that may have been changed by other users need updating.
160+
updateExpirationTimes();
161+
}
162+
147163
@Override
148164
public boolean onPreferenceChange(Preference preference, Object newValue) {
149165
final int value;
@@ -162,6 +178,11 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
162178
CharSequence summary = newValue.toString();
163179

164180
switch (preference.getKey()) {
181+
case Keys.EXPIRATION_TIME: {
182+
getDpm().setPasswordExpirationTimeout(getAdmin(), TimeUnit.SECONDS.toMillis(value));
183+
updateExpirationTimes();
184+
return true;
185+
}
165186
case Keys.QUALITY: {
166187
final ListPreference list = (ListPreference) preference;
167188
// Store newValue now so getEntry() can return the new setting
@@ -225,6 +246,17 @@ private void setup(String key, Object adminSetting) {
225246
field.setSummary(summary);
226247
}
227248

249+
/**
250+
* Refresh summaries for settings related to the next password expiration.
251+
*/
252+
private void updateExpirationTimes() {
253+
final Preference byAdmin = findPreference(Keys.EXPIRATION_TIME);
254+
final Preference byAll = findPreference(Keys.EXPIRATION_BY_ALL);
255+
256+
byAdmin.setSummary(Util.formatTimestamp(getDpm().getPasswordExpiration(getAdmin())));
257+
byAll.setSummary(Util.formatTimestamp(getDpm().getPasswordExpiration(null)));
258+
}
259+
228260
/**
229261
* Notify the admin receiver that something about the password has changed - in this context,
230262
* a minimum password requirement policy.

app/src/main/res/values/strings.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,14 @@
480480
<string name="password_not_compliant_title">Password is not compliant</string>
481481
<string name="password_not_compliant_content">Touch to set a new lock screen password.</string>
482482

483+
<string name="password_expiration">Password expiration</string>
484+
<string name="password_expiration_seconds">Password expiration (seconds)</string>
485+
<string name="password_expiration_aggregate">Expiration by all/other admins</string>
486+
487+
<string name="password_expired_title">Password has expired</string>
488+
<string name="password_expired_by_self">According to a policy set by TestDPC.</string>
489+
<string name="password_expired_by_others">According to a policy set by another admin.</string>
490+
483491
<plurals name="password_failed_attempts_title">
484492
<item quantity="one">Password entered incorrectly %d time</item>
485493
<item quantity="other">Password entered incorrectly %d times</item>

app/src/main/res/xml/password_constraint_preferences.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@
1717

1818
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
1919

20+
<PreferenceCategory android:title="@string/password_expiration">
21+
<EditTextPreference
22+
android:title="@string/password_expiration_seconds"
23+
android:key="password_expiration_time"
24+
android:inputType="number"/>
25+
26+
<!-- Not a real preference- shows the aggregate password expiration time for all admins. -->
27+
<Preference
28+
android:title="@string/password_expiration_aggregate"
29+
android:key="password_expiration_aggregate"
30+
android:selectable="false"/>
31+
</PreferenceCategory>
32+
2033
<PreferenceCategory android:title="@string/password_constraints">
2134
<ListPreference
2235
android:title="@string/minimum_password_quality"

0 commit comments

Comments
 (0)