package ca.grocerygo.android.services.location; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.database.Cursor; import android.location.Location; import android.media.AudioManager; import android.media.RingtoneManager; import android.os.Bundle; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; import android.util.SparseArray; import ca.grocerygo.android.MapFragmentActivity; import ca.grocerygo.android.R; import ca.grocerygo.android.database.CartTable; import ca.grocerygo.android.database.StoreTable; import ca.grocerygo.android.settings.SettingsManager; import ca.grocerygo.android.utils.GroceryGoUtils; import ca.grocerygo.android.utils.GroceryStoreDistanceMap; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; public class LocationReceiver extends BroadcastReceiver { // a near location is 1500m public static final int LOCATION_NEAR = 1500; public static final int NOTIFICATION_LOCATION_ID = 0; @Override public void onReceive(Context context, Intent intent) { Location loc = (Location) intent.getExtras().get(LocationMonitor.EXTRA_LOCATION); if (loc == null) return; constructNotification(context, loc); rebuildStoreDistances(context, loc); } private void rebuildStoreDistances(Context context, Location loc) { // Build a new store location map using the new location and reload the view SparseArray<Float> newDistanceMap = GroceryGoUtils.buildDistanceMap(context); GroceryStoreDistanceMap.setmStoreDistanceMap(newDistanceMap); GroceryGoUtils.reloadGroceryLocation(context); } private void constructNotification(Context context, Location loc) { Bundle extras = new Bundle(); ArrayList<Integer> storeIDs = new ArrayList<Integer>(); // list of unique stores that are closeby Set<String> newEvents = new HashSet<String>(); ArrayList<String> events = new ArrayList<String>(); // list of unique grocery names boolean displayNotification = false; Cursor stores = GroceryGoUtils.getGroceriesFromCartFromStores(context); stores.moveToFirst(); while (!stores.isAfterLast()) { String name = stores.getString(stores.getColumnIndex(CartTable.COLUMN_CART_GROCERY_NAME)); int storeID = stores.getInt(stores.getColumnIndex(StoreTable.COLUMN_STORE_ID)); Location storeLoc = new Location("Store Location"); storeLoc.setLatitude(stores.getDouble(stores.getColumnIndex(StoreTable.COLUMN_STORE_LATITUDE))); storeLoc.setLongitude(stores.getDouble(stores.getColumnIndex(StoreTable.COLUMN_STORE_LONGITUDE))); // calculate the distance in meters between the current user location and the store's location float distance = loc.distanceTo(storeLoc); if (distance <= LOCATION_NEAR) { if (!events.contains(name)) events.add(name); if (!storeIDs.contains(storeID)) storeIDs.add(storeID); newEvents.add(name); displayNotification = true; } stores.moveToNext(); } if (!displayNotification) return; // Check if the exact same set of items has been previously notified SharedPreferences prefs = SettingsManager.getPrefs(context); Set<String> oldEvents = prefs.getStringSet(SettingsManager.SETTINGS_PREVIOUS_NOTIFICATION, new HashSet<String>()); if (oldEvents.equals(newEvents)) return; Editor prefsEditor = prefs.edit(); prefsEditor.putStringSet(SettingsManager.SETTINGS_PREVIOUS_NOTIFICATION, newEvents); prefsEditor.commit(); extras.putIntegerArrayList(MapFragmentActivity.EXTRA_FILTER_STORE, storeIDs); // Now make a notification if there are nearby items in the cart NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.ic_stat_notify_item) .setContentTitle(context.getString(R.string.app_name)) .setContentText(context.getString(R.string.notification_content_text)) .setAutoCancel(true); // Create a big notification NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); // Sets a title for the inbox style big view inboxStyle.setBigContentTitle(context.getString(R.string.notification_contect_big_title)); // Moves events into the big view for (int i=0; i < events.size(); i++) { inboxStyle.addLine(events.get(i)); } // Moves the big view style object into the notification object. mBuilder.setStyle(inboxStyle); // Creates an explicit intent for the top activity that will be opened (the map) Intent resultIntent = new Intent(context, MapFragmentActivity.class); resultIntent.putExtras(extras); // 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(context); // Adds the back stack for the Intent (but not the Intent itself) stackBuilder.addParentStack(MapFragmentActivity.class); // Adds the Intent that starts the Activity to the top of the stack stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent( 0, PendingIntent.FLAG_UPDATE_CURRENT ); mBuilder.setContentIntent(resultPendingIntent); NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); // Now set sounds and vibrations mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (audioManager.getRingerMode() != AudioManager.RINGER_MODE_SILENT) mBuilder.setDefaults(Notification.DEFAULT_VIBRATE); // the ID allows for updating the notification later on mNotificationManager.notify(NOTIFICATION_LOCATION_ID, mBuilder.build()); } }