1616
1717package com .afwsamples .testdpc ;
1818
19+ import static android .app .admin .DevicePolicyManager .EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE ;
20+ import static android .app .admin .DevicePolicyManager .PERMISSION_GRANT_STATE_GRANTED ;
21+ import static com .afwsamples .testdpc .policy .PolicyManagementFragment .OVERRIDE_KEY_SELECTION_KEY ;
22+
1923import android .accounts .Account ;
2024import android .accounts .AccountManager ;
2125import android .annotation .TargetApi ;
22- import android .app .admin .DevicePolicyManager ;
2326import android .app .Notification ;
2427import android .app .NotificationManager ;
2528import android .app .PendingIntent ;
29+ import android .app .admin .DevicePolicyManager ;
2630import android .content .ComponentName ;
2731import android .content .Context ;
2832import android .content .Intent ;
4044import android .util .Log ;
4145import android .widget .Toast ;
4246
43- import com .afwsamples .testdpc .common .Util ;
4447import com .afwsamples .testdpc .common .LaunchIntentUtil ;
4548import com .afwsamples .testdpc .common .Util ;
4649import com .afwsamples .testdpc .cosu .EnableCosuActivity ;
4750
51+ import java .io .BufferedReader ;
52+ import java .io .BufferedWriter ;
4853import java .io .File ;
4954import java .io .FileInputStream ;
5055import java .io .FileOutputStream ;
5156import java .io .IOException ;
5257import java .io .InputStream ;
58+ import java .io .InputStreamReader ;
5359import java .io .OutputStream ;
60+ import java .io .OutputStreamWriter ;
61+ import java .text .DateFormat ;
62+ import java .text .SimpleDateFormat ;
5463import java .util .ArrayList ;
64+ import java .util .Collections ;
65+ import java .util .Date ;
5566import java .util .List ;
5667
57- import static android .app .admin .DevicePolicyManager .EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE ;
58- import static android .app .admin .DevicePolicyManager .PERMISSION_GRANT_STATE_GRANTED ;
59- import static com .afwsamples .testdpc .policy .PolicyManagementFragment .OVERRIDE_KEY_SELECTION_KEY ;
60-
6168/**
6269 * Handles events related to the managed profile.
6370 */
@@ -67,6 +74,11 @@ public class DeviceAdminReceiver extends android.app.admin.DeviceAdminReceiver {
6774 public static final String ACTION_PASSWORD_REQUIREMENTS_CHANGED =
6875 "com.afwsamples.testdpc.policy.PASSWORD_REQUIREMENTS_CHANGED" ;
6976
77+ private static final String LOGS_DIR = "logs" ;
78+
79+ private static final String FAILED_PASSWORD_LOG_FILE =
80+ "failed_pw_attempts_timestamps.log" ;
81+
7082 private static final int CHANGE_PASSWORD_NOTIFICATION_ID = 101 ;
7183 private static final int PASSWORD_FAILED_NOTIFICATION_ID = 102 ;
7284
@@ -297,8 +309,14 @@ private boolean isRuntimePermission(PackageManager packageManager, String permis
297309 @ TargetApi (Build .VERSION_CODES .M )
298310 @ Override
299311 public void onSystemUpdatePending (Context context , Intent intent , long receivedTime ) {
300- Toast .makeText (context , "System update received at: " + receivedTime ,
301- Toast .LENGTH_LONG ).show ();
312+ if (receivedTime != -1 ) {
313+ DateFormat sdf = new SimpleDateFormat ("hh:mm:ss dd/MM/yyyy" );
314+ String timeString = sdf .format (new Date (receivedTime ));
315+ Toast .makeText (context , "System update received at: " + timeString ,
316+ Toast .LENGTH_LONG ).show ();
317+ } else {
318+ // No system update is currently available on this device.
319+ }
302320 }
303321
304322 @ TargetApi (Build .VERSION_CODES .M )
@@ -360,6 +378,17 @@ public void onPasswordFailed(Context context, Intent intent) {
360378
361379 String title = context .getResources ().getQuantityString (
362380 R .plurals .password_failed_attempts_title , attempts , attempts );
381+
382+ ArrayList <Date > previousFailedAttempts = getFailedPasswordAttempts (context );
383+ Date date = new Date ();
384+ previousFailedAttempts .add (date );
385+ Collections .sort (previousFailedAttempts , Collections .<Date >reverseOrder ());
386+ try {
387+ saveFailedPasswordAttempts (context , previousFailedAttempts );
388+ } catch (IOException e ) {
389+ Log .e (TAG , "Unable to save failed password attempts" , e );
390+ }
391+
363392 String content = maxAttempts == 0
364393 ? context .getString (R .string .password_failed_no_limit_set )
365394 : context .getResources ().getQuantityString (
@@ -373,11 +402,78 @@ public void onPasswordFailed(Context context, Intent intent) {
373402 .setContentIntent (PendingIntent .getActivity (context , /* requestCode */ -1 ,
374403 new Intent (DevicePolicyManager .ACTION_SET_NEW_PASSWORD ), /* flags */ 0 ));
375404
405+ Notification .InboxStyle inboxStyle = new Notification .InboxStyle ();
406+ inboxStyle .setBigContentTitle (title );
407+
408+ final DateFormat dateFormat = SimpleDateFormat .getDateTimeInstance ();
409+ for (Date d : previousFailedAttempts ) {
410+ inboxStyle .addLine (dateFormat .format (d ));
411+ }
412+ warn .setStyle (inboxStyle );
413+
376414 NotificationManager nm = (NotificationManager )
377415 context .getSystemService (Context .NOTIFICATION_SERVICE );
378416 nm .notify (PASSWORD_FAILED_NOTIFICATION_ID , warn .getNotification ());
379417 }
380418
419+ private static File logFile (Context context ) {
420+ File parent = context .getDir (LOGS_DIR , Context .MODE_PRIVATE );
421+ return new File (parent , FAILED_PASSWORD_LOG_FILE );
422+ }
423+
424+ private static ArrayList <Date > getFailedPasswordAttempts (Context context ) {
425+ File logFile = logFile (context );
426+ ArrayList <Date > result = new ArrayList <Date >();
427+
428+ if (!logFile .exists ()) {
429+ return result ;
430+ }
431+
432+ FileInputStream fis = null ;
433+ try {
434+ fis = new FileInputStream (logFile );
435+ BufferedReader br = new BufferedReader (new InputStreamReader (fis ));
436+
437+ String line = null ;
438+ while ((line = br .readLine ()) != null && line .length () > 0 ) {
439+ result .add (new Date (Long .parseLong (line )));
440+ }
441+
442+ br .close ();
443+ } catch (IOException e ) {
444+ Log .e (TAG , "Unable to read failed password attempts" , e );
445+ } finally {
446+ if (fis != null ) {
447+ try {
448+ fis .close ();
449+ } catch (IOException e ) {
450+ Log .e (TAG , "Unable to close failed password attempts log file" , e );
451+ }
452+ }
453+ }
454+
455+ return result ;
456+ }
457+
458+ private static void saveFailedPasswordAttempts (Context context , ArrayList <Date > attempts )
459+ throws IOException {
460+ File logFile = logFile (context );
461+
462+ if (!logFile .exists ()) {
463+ logFile .createNewFile ();
464+ }
465+
466+ FileOutputStream fos = new FileOutputStream (logFile );
467+ BufferedWriter bw = new BufferedWriter (new OutputStreamWriter (fos ));
468+
469+ for (Date date : attempts ) {
470+ bw .write (Long .toString (date .getTime ()));
471+ bw .newLine ();
472+ }
473+
474+ bw .close ();
475+ }
476+
381477 @ Override
382478 public void onPasswordChanged (Context context , Intent intent ) {
383479 updatePasswordQualityNotification (context );
0 commit comments