16
16
17
17
package com .afwsamples .testdpc ;
18
18
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
+
19
23
import android .accounts .Account ;
20
24
import android .accounts .AccountManager ;
21
25
import android .annotation .TargetApi ;
22
- import android .app .admin .DevicePolicyManager ;
23
26
import android .app .Notification ;
24
27
import android .app .NotificationManager ;
25
28
import android .app .PendingIntent ;
29
+ import android .app .admin .DevicePolicyManager ;
26
30
import android .content .ComponentName ;
27
31
import android .content .Context ;
28
32
import android .content .Intent ;
40
44
import android .util .Log ;
41
45
import android .widget .Toast ;
42
46
43
- import com .afwsamples .testdpc .common .Util ;
44
47
import com .afwsamples .testdpc .common .LaunchIntentUtil ;
45
48
import com .afwsamples .testdpc .common .Util ;
46
49
import com .afwsamples .testdpc .cosu .EnableCosuActivity ;
47
50
51
+ import java .io .BufferedReader ;
52
+ import java .io .BufferedWriter ;
48
53
import java .io .File ;
49
54
import java .io .FileInputStream ;
50
55
import java .io .FileOutputStream ;
51
56
import java .io .IOException ;
52
57
import java .io .InputStream ;
58
+ import java .io .InputStreamReader ;
53
59
import java .io .OutputStream ;
60
+ import java .io .OutputStreamWriter ;
61
+ import java .text .DateFormat ;
62
+ import java .text .SimpleDateFormat ;
54
63
import java .util .ArrayList ;
64
+ import java .util .Collections ;
65
+ import java .util .Date ;
55
66
import java .util .List ;
56
67
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
-
61
68
/**
62
69
* Handles events related to the managed profile.
63
70
*/
@@ -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
@@ -297,8 +309,14 @@ private boolean isRuntimePermission(PackageManager packageManager, String permis
297
309
@ TargetApi (Build .VERSION_CODES .M )
298
310
@ Override
299
311
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
+ }
302
320
}
303
321
304
322
@ TargetApi (Build .VERSION_CODES .M )
@@ -360,6 +378,17 @@ public void onPasswordFailed(Context context, Intent intent) {
360
378
361
379
String title = context .getResources ().getQuantityString (
362
380
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
+
363
392
String content = maxAttempts == 0
364
393
? context .getString (R .string .password_failed_no_limit_set )
365
394
: context .getResources ().getQuantityString (
@@ -373,11 +402,78 @@ public void onPasswordFailed(Context context, Intent intent) {
373
402
.setContentIntent (PendingIntent .getActivity (context , /* requestCode */ -1 ,
374
403
new Intent (DevicePolicyManager .ACTION_SET_NEW_PASSWORD ), /* flags */ 0 ));
375
404
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
+
376
414
NotificationManager nm = (NotificationManager )
377
415
context .getSystemService (Context .NOTIFICATION_SERVICE );
378
416
nm .notify (PASSWORD_FAILED_NOTIFICATION_ID , warn .getNotification ());
379
417
}
380
418
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
+
381
477
@ Override
382
478
public void onPasswordChanged (Context context , Intent intent ) {
383
479
updatePasswordQualityNotification (context );
0 commit comments