package org.bitseal.services; import org.bitseal.R; import org.bitseal.activities.InboxActivity; import org.bitseal.activities.LockScreenActivity; import android.app.IntentService; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; import android.util.Log; public class NotificationsService extends IntentService { public static final String EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED = "extraNewMessagesNotificationCleared"; public static final String KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED = "keyNewMessagesNotificationCurrentlyDisplayed"; public static final String EXTRA_DISPLAY_NEW_MESSAGES_NOTIFICATION = "displayNewMessagesNotification"; public static final String EXTRA_DISPLAY_UNLOCK_NOTIFICATION = "extraDisplayUnlockNotification"; /** A random value used as a unique ID number of the 'new messages received' notification */ private static final int NEW_MESSAGES_NOTIFICATION_ID = 43282372; /** A random value used as a unique ID number of the 'new messages received' notification */ private static final int UNLOCK_NOTIFICATION_ID = 749385039; /** A key for storing the number of new messages referred to in the current 'new messages received' notification */ private static final String NEW_MESSAGES_NOTIFICATION_KEY = "newMessagesNotificationKey"; private static final String UNLOCK_NOTIFICATION_TITLE = "Unlock Bitseal"; private static final String UNLOCK_NOTIFICATION_TEXT = "Touch to unlock Bitseal"; public static final String TAG = "NOTIFICATIONS_SERVICE"; public NotificationsService() { super("NotificationsService"); } public static int getNewMessagesNotificationId() { return NEW_MESSAGES_NOTIFICATION_ID; } public static int getUnlockNotificationId() { return UNLOCK_NOTIFICATION_ID; } @Override protected void onHandleIntent(Intent intent) { if (intent.hasExtra(EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED)) { // Set the 'new messages notification currently displayed' shared preference to false SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, false); editor.commit(); Log.i(TAG, "Recorded dismissal of new messages notification"); } else if (intent.hasExtra(EXTRA_DISPLAY_NEW_MESSAGES_NOTIFICATION)) { int newMessages = intent.getExtras().getInt(EXTRA_DISPLAY_NEW_MESSAGES_NOTIFICATION); displayNewMessagesNotification(newMessages); } else if (intent.hasExtra(EXTRA_DISPLAY_UNLOCK_NOTIFICATION)) { displayUnlockNotification(); } } /** * Shows an Android notification that new messages have been received * * @param newMessages - An int representing the number of new messages received */ private void displayNewMessagesNotification(int newMessages) { int notificationNewMessages; // The number of new messages that this notification will advertise to the user // Check whether there is already a 'new messages' notification being displayed to the user SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); boolean newMessagesNotificationCurrentlyDisplayed = prefs.getBoolean(NotificationsService.KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, false); // If there is, cancel the current notification and show a new one that takes account of the number of messages referred to in the last notification if (newMessagesNotificationCurrentlyDisplayed) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.cancel(NEW_MESSAGES_NOTIFICATION_ID); int oldNotificationMessages = prefs.getInt(NEW_MESSAGES_NOTIFICATION_KEY, 0); notificationNewMessages = newMessages + oldNotificationMessages; } else { notificationNewMessages = newMessages; } Log.i(TAG, "Showing notification for " + notificationNewMessages + " new message(s) received"); // Create and display the new notification if (notificationNewMessages == 1) { displayNewMessagesNotification("1 new message received", "Touch to open Bitseal inbox"); } else { displayNewMessagesNotification(notificationNewMessages + " new messages received", "Touch to open Bitseal inbox"); } // Store the number of new messages referred to in this notification so that it can be updated later SharedPreferences.Editor editor = prefs.edit(); editor.putInt(NEW_MESSAGES_NOTIFICATION_KEY, notificationNewMessages); editor.commit(); // Set the 'new messages notification currently displayed' shared preference to true editor.putBoolean(NotificationsService.KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, true); editor.commit(); } /** * Displays an Android notification to the user, informing them that new messages * have been received.<br><br> * * Note: This method is adapted from the example here: <br> * https://developer.android.com/guide/topics/ui/notifiers/notifications.html * * @param title - A String containing the title of the notification to display * @param text - A String containing the text of the notification to display */ private void displayNewMessagesNotification(String title, String text) { NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle(title); builder.setContentText(text); builder.setAutoCancel(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setSmallIcon(R.drawable.notification_icon_lollipop); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); // All we show is the number of new messages received } else { builder.setSmallIcon(R.drawable.notification_icon); } // Set a sound for the notification Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); builder.setSound(alarmSound); // Creates an intent to open the Inbox Activity if the user selects the notification Intent openNotificationIntent = new Intent(this, InboxActivity.class); openNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true); // Creates an intent to run the notifications service if the user clears the notification Intent clearNotificationIntent = new Intent(getApplicationContext(), NotificationsService.class); clearNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true); PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, clearNotificationIntent, PendingIntent.FLAG_CANCEL_CURRENT); builder.setDeleteIntent(pendingIntent); // The stack builder object will contain an artificial back stack for the // started Activity. This ensures that navigating backward from the Activity leads out of // your application to the Home screen. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); // Adds the back stack for the Intent (but not the Intent itself) stackBuilder.addParentStack(InboxActivity.class); // Adds the Intent that starts the Activity to the top of the stack stackBuilder.addNextIntent(openNotificationIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(resultPendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // The notification ID number allows you to update the notification later on. notificationManager.notify(NEW_MESSAGES_NOTIFICATION_ID, builder.build()); } /** * Displays an Android notification to the user, informing them that the app * needs to be unlocked (decrypting the database). * * Note: This method is adapted from the example here: <br> * https://developer.android.com/guide/topics/ui/notifiers/notifications.html */ private void displayUnlockNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentTitle(UNLOCK_NOTIFICATION_TITLE); builder.setContentText(UNLOCK_NOTIFICATION_TEXT); builder.setAutoCancel(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setSmallIcon(R.drawable.notification_icon_lollipop); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); } else { builder.setSmallIcon(R.drawable.notification_icon); } // Creates an intent to open the lock screen activity if the user selects the notification Intent openNotificationIntent = new Intent(this, LockScreenActivity.class); openNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true); // Creates an intent to run the notifications service if the user clears the notification Intent clearNotificationIntent = new Intent(getApplicationContext(), NotificationsService.class); clearNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true); PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, clearNotificationIntent, PendingIntent.FLAG_CANCEL_CURRENT); builder.setDeleteIntent(pendingIntent); // The stack builder object will contain an artificial back stack for the // started Activity. This ensures that navigating backward from the Activity leads out of // your application to the Home screen. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); // Adds the back stack for the Intent (but not the Intent itself) stackBuilder.addParentStack(LockScreenActivity.class); // Adds the Intent that starts the Activity to the top of the stack stackBuilder.addNextIntent(openNotificationIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(resultPendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // The notification ID number allows you to update the notification later on. notificationManager.notify(UNLOCK_NOTIFICATION_ID, builder.build()); } }