package edu.mit.mitmobile2.alerts; import java.util.HashMap; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONStringer; 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.util.Log; import edu.mit.mitmobile2.Global; import edu.mit.mitmobile2.MobileWebApi; import edu.mit.mitmobile2.MobileWebApi.ErrorResponseListener; import edu.mit.mitmobile2.MobileWebApi.IgnoreErrorListener; import edu.mit.mitmobile2.MobileWebApi.JSONArrayResponseListener; import edu.mit.mitmobile2.MobileWebApi.JSONObjectResponseListener; import edu.mit.mitmobile2.MobileWebApi.ServerResponseException; import edu.mit.mitmobile2.about.Config; import edu.mit.mitmobile2.emergency.EmergencyInfoNoticeListener; public class C2DMReceiver extends BroadcastReceiver { public static abstract class NoticeListener { abstract public void onReceivedNotice(Context context, JSONObject object, int noticeCount); protected void notifyUser(Context context, String statusBarText, String alarmTitle, String alarmText, int iconResID, Class<?> classname) { Intent startIntent = new Intent(context, classname); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, startIntent, 0); notifyUser(context, statusBarText, alarmTitle, alarmText, iconResID, pendingIntent); } protected void notifyUser(Context context, String statusBarText, String alarmTitle, String alarmText, int iconResID, PendingIntent pendingIntent ) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); long curTime = System.currentTimeMillis(); Notification notify = new Notification(iconResID, statusBarText, curTime); notify.setLatestEventInfo(context, alarmTitle, alarmText, pendingIntent); notify.flags = Notification.FLAG_AUTO_CANCEL; notify.defaults = Notification.DEFAULT_ALL; // Launch if selected... notificationManager.notify((int) curTime, notify); // use current time as id for unique notifications } } // This only get set after the // server has confirmed receipt of the registration id private static String sRegistrationID; private static String mPendingRegistrationID; public static void registerForNotifications(Context context) { if (sRegistrationID == null) { Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER"); registrationIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0)); // boilerplate registrationIntent.putExtra("sender", Config.C2DM_SENDER); context.startService(registrationIntent); } } @Override public void onReceive(Context context, Intent intent) { Log.d("action", intent.getAction()); if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) { String registration = intent.getStringExtra("registration_id"); if (registration != null) { if (mPendingRegistrationID == null || !registration.equals(mPendingRegistrationID)) { mPendingRegistrationID = registration; registerDevice(context, mPendingRegistrationID); } } else { Log.d("C2DMReceiver", "failed to get a registration ID, probably an invalid C2DM sender configuration"); } } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) { try { final SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE); long deviceID = preferences.getLong(DEVICE_ID_KEY, -1); JSONObject payloadObject = new JSONObject(intent.getExtras().getString("payload")); String tag = payloadObject.getString("tag"); int recipientDeviceID = payloadObject.getInt("deviceID"); if (recipientDeviceID != deviceID) { // notice not intended for this recipient // user probably uninstalled and reinstalled the app return; } NoticeListener noticeListener = null; if (tag.startsWith("emergencyinfo:")) { noticeListener = new EmergencyInfoNoticeListener(); } if (noticeListener != null) { noticeListener.onReceivedNotice(context, payloadObject, incrementNoticeCount(context)); } else { Log.d("C2DMReceiver", "Could not find a target for notification with tag=" + tag); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.d("C2DMReceiver", "Failed at parsing incoming notification"); } catch (Exception e){ e.printStackTrace(); Log.d("C2DMReceiver", "Failed at parsing incoming notification"); } } } private final static String PREFERENCES = "DeviceRegistration"; private final static String DEVICE_ID_KEY = "device_id"; private final static String DEVICE_PASS_KEY = "pass_key"; private final static String DEVICE_REGISTRATION_KEY = "device_registration"; private final static String NOTICE_COUNT_KEY = "notice_count"; public static void clearDeviceRegistration(Context context) { final SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE); Editor editor = preferences.edit(); editor.putLong(DEVICE_ID_KEY, -1); editor.commit(); sRegistrationID = null; } private void registerDevice(final Context context, final String registrationID) { final SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE); MobileWebApi api = new MobileWebApi(false, false, null, context, null); long deviceID = preferences.getLong(DEVICE_ID_KEY, -1); String appID = Config.release_project_name; if (deviceID == -1) { // need register the device HashMap<String, String> params = new HashMap<String, String>(); params.put("module", "push"); params.put("command", "register"); params.put("device_type", "android"); params.put("app_id", appID); params.put("device_token", registrationID); api.requestJSONObject(params, new JSONObjectResponseListener( new RegistrationErrorListener(), null) { @Override public void onResponse(JSONObject object) throws ServerResponseException, JSONException { Editor editor = preferences.edit(); editor.putLong(DEVICE_ID_KEY, object.getLong(DEVICE_ID_KEY)); editor.putLong(DEVICE_PASS_KEY, object.getLong(DEVICE_PASS_KEY)); editor.putString(DEVICE_REGISTRATION_KEY, registrationID); editor.commit(); sRegistrationID = registrationID; mPendingRegistrationID = null; Global.onDeviceRegisterCompleted(); } }); } else { // may need to change our token String oldRegistrationID = preferences.getString(DEVICE_REGISTRATION_KEY, ""); if (!oldRegistrationID.equals(registrationID)) { HashMap<String, String> params = new HashMap<String, String>(); params.put("module", "push"); params.put("command", "newDeviceToken"); params.put("device_type", "android"); params.put("app_id", appID); params.put("device_token", registrationID); params.put("device_id", Long.toString(deviceID)); params.put("pass_key", Long.toString(preferences.getLong(DEVICE_PASS_KEY, 0))); api.requestJSONObject(params, new JSONObjectResponseListener( new RegistrationErrorListener(), null) { @Override public void onResponse(JSONObject object) throws ServerResponseException, JSONException { // nothing to do mPendingRegistrationID = null; if (object.getBoolean("success")) { Editor editor = preferences.edit(); editor.putString(DEVICE_REGISTRATION_KEY, registrationID); editor.commit(); sRegistrationID = registrationID; Global.onDeviceRegisterCompleted(); } else { Log.d("C2DMReceiver", "Device token failed to registered"); } } }); } } } class RegistrationErrorListener implements ErrorResponseListener { @Override public void onError() { mPendingRegistrationID = null; } }; public static void markNotificationAsRead(Context context, String tag) { JSONStringer encoder = new JSONStringer(); try { encoder.array(); encoder.value(tag); encoder.endArray(); } catch (JSONException e) { e.printStackTrace(); Log.e("C2DMReceiver", "Failed to encode tag=" + tag); } Device device = getDevice(context); HashMap<String, String> params = new HashMap<String, String>(); params.put("module", "push"); params.put("command", "markNotificationsAsRead"); params.put("tags", encoder.toString()); params.put("device_type", "android"); params.put("app_id", Config.release_project_name); params.put("device_id", Long.toString(device.mDeviceId)); params.put("pass_key", Long.toString(device.mPassKey)); MobileWebApi api = new MobileWebApi(false, false, null, context, null); api.requestJSONArray(params, new JSONArrayResponseListener( new IgnoreErrorListener(), null) { @Override public void onResponse(JSONArray array) throws ServerResponseException, JSONException { } }); } static public class Device { private long mDeviceId; private long mPassKey; Device(long deviceId, long passKey) { mDeviceId = deviceId; mPassKey = passKey; } public long getDeviceId() { return mDeviceId; } public long getPassKey() { return mPassKey; } } public static Device getDevice(Context context) { final SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE); return new Device( preferences.getLong(DEVICE_ID_KEY, -1), preferences.getLong(DEVICE_PASS_KEY, 0) ); } private int incrementNoticeCount(Context context) { final SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE); int count = preferences.getInt(NOTICE_COUNT_KEY, 0); Editor editor = preferences.edit(); editor.putInt(NOTICE_COUNT_KEY, count+1); editor.commit(); return count+1; } }