19
19
import android .accounts .Account ;
20
20
import android .accounts .AccountManager ;
21
21
import android .annotation .TargetApi ;
22
- import android .app .admin .DevicePolicyManager ;
23
22
import android .app .Notification ;
24
23
import android .app .NotificationManager ;
25
24
import android .app .PendingIntent ;
25
+ import android .app .admin .DevicePolicyManager ;
26
26
import android .content .ComponentName ;
27
27
import android .content .Context ;
28
28
import android .content .Intent ;
40
40
import android .util .Log ;
41
41
import android .widget .Toast ;
42
42
43
- import com .afwsamples .testdpc .common .Util ;
44
43
import com .afwsamples .testdpc .common .LaunchIntentUtil ;
45
44
import com .afwsamples .testdpc .common .Util ;
46
45
import com .afwsamples .testdpc .cosu .EnableCosuActivity ;
47
46
47
+ import java .io .BufferedReader ;
48
+ import java .io .BufferedWriter ;
48
49
import java .io .File ;
49
50
import java .io .FileInputStream ;
50
51
import java .io .FileOutputStream ;
51
52
import java .io .IOException ;
52
53
import java .io .InputStream ;
54
+ import java .io .InputStreamReader ;
53
55
import java .io .OutputStream ;
56
+ import java .io .OutputStreamWriter ;
57
+ import java .text .DateFormat ;
58
+ import java .text .SimpleDateFormat ;
54
59
import java .util .ArrayList ;
60
+ import java .util .Collections ;
61
+ import java .util .Date ;
55
62
import java .util .List ;
56
63
57
64
import static android .app .admin .DevicePolicyManager .EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE ;
@@ -67,6 +74,11 @@ public class DeviceAdminReceiver extends android.app.admin.DeviceAdminReceiver {
67
74
public static final String ACTION_PASSWORD_REQUIREMENTS_CHANGED =
68
75
"com.afwsamples.testdpc.policy.PASSWORD_REQUIREMENTS_CHANGED" ;
69
76
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
+
70
82
private static final int CHANGE_PASSWORD_NOTIFICATION_ID = 101 ;
71
83
private static final int PASSWORD_FAILED_NOTIFICATION_ID = 102 ;
72
84
@@ -360,6 +372,17 @@ public void onPasswordFailed(Context context, Intent intent) {
360
372
361
373
String title = context .getResources ().getQuantityString (
362
374
R .plurals .password_failed_attempts_title , attempts , attempts );
375
+
376
+ ArrayList <Date > previousFailedAttempts = getFailedPasswordAttempts (context );
377
+ Date date = new Date ();
378
+ previousFailedAttempts .add (date );
379
+ Collections .sort (previousFailedAttempts , Collections .<Date >reverseOrder ());
380
+ try {
381
+ saveFailedPasswordAttempts (context , previousFailedAttempts );
382
+ } catch (IOException e ) {
383
+ Log .e (TAG , "Unable to save failed password attempts" , e );
384
+ }
385
+
363
386
String content = maxAttempts == 0
364
387
? context .getString (R .string .password_failed_no_limit_set )
365
388
: context .getResources ().getQuantityString (
@@ -373,11 +396,78 @@ public void onPasswordFailed(Context context, Intent intent) {
373
396
.setContentIntent (PendingIntent .getActivity (context , /* requestCode */ -1 ,
374
397
new Intent (DevicePolicyManager .ACTION_SET_NEW_PASSWORD ), /* flags */ 0 ));
375
398
399
+ Notification .InboxStyle inboxStyle = new Notification .InboxStyle ();
400
+ inboxStyle .setBigContentTitle (title );
401
+
402
+ final DateFormat dateFormat = SimpleDateFormat .getDateTimeInstance ();
403
+ for (Date d : previousFailedAttempts ) {
404
+ inboxStyle .addLine (dateFormat .format (d ));
405
+ }
406
+ warn .setStyle (inboxStyle );
407
+
376
408
NotificationManager nm = (NotificationManager )
377
409
context .getSystemService (Context .NOTIFICATION_SERVICE );
378
410
nm .notify (PASSWORD_FAILED_NOTIFICATION_ID , warn .getNotification ());
379
411
}
380
412
413
+ private static File logFile (Context context ) {
414
+ File parent = context .getDir (LOGS_DIR , Context .MODE_PRIVATE );
415
+ return new File (parent , FAILED_PASSWORD_LOG_FILE );
416
+ }
417
+
418
+ private static ArrayList <Date > getFailedPasswordAttempts (Context context ) {
419
+ File logFile = logFile (context );
420
+ ArrayList <Date > result = new ArrayList <Date >();
421
+
422
+ if (!logFile .exists ()) {
423
+ return result ;
424
+ }
425
+
426
+ FileInputStream fis = null ;
427
+ try {
428
+ fis = new FileInputStream (logFile );
429
+ BufferedReader br = new BufferedReader (new InputStreamReader (fis ));
430
+
431
+ String line = null ;
432
+ while ((line = br .readLine ()) != null && line .length () > 0 ) {
433
+ result .add (new Date (Long .parseLong (line )));
434
+ }
435
+
436
+ br .close ();
437
+ } catch (IOException e ) {
438
+ Log .e (TAG , "Unable to read failed password attempts" , e );
439
+ } finally {
440
+ if (fis != null ) {
441
+ try {
442
+ fis .close ();
443
+ } catch (IOException e ) {
444
+ Log .e (TAG , "Unable to close failed password attempts log file" , e );
445
+ }
446
+ }
447
+ }
448
+
449
+ return result ;
450
+ }
451
+
452
+ private static void saveFailedPasswordAttempts (Context context , ArrayList <Date > attempts )
453
+ throws IOException {
454
+ File logFile = logFile (context );
455
+
456
+ if (!logFile .exists ()) {
457
+ logFile .createNewFile ();
458
+ }
459
+
460
+ FileOutputStream fos = new FileOutputStream (logFile );
461
+ BufferedWriter bw = new BufferedWriter (new OutputStreamWriter (fos ));
462
+
463
+ for (Date date : attempts ) {
464
+ bw .write (Long .toString (date .getTime ()));
465
+ bw .newLine ();
466
+ }
467
+
468
+ bw .close ();
469
+ }
470
+
381
471
@ Override
382
472
public void onPasswordChanged (Context context , Intent intent ) {
383
473
updatePasswordQualityNotification (context );
0 commit comments