package com.zulip.android.gcm; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences.Editor; import android.os.AsyncTask; import android.os.SystemClock; import android.util.Log; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.zulip.android.ZulipApp; import com.zulip.android.activities.ZulipActivity; import com.zulip.android.networking.HTTPRequest; import com.zulip.android.util.ZLog; import java.io.IOException; // This class manages registering and unregistering for GCM notifications. // When a notification is received, it is processed by GcmBroadcastReceiver. public class Notifications { // Project Number from the Google Cloud Services console private static final String SENDER_ID = "835904834568"; private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; private static final String TAG = "GCM"; private ZulipApp app; private GoogleCloudMessaging gcm; private String regid; private Activity activity; public Notifications(ZulipActivity activity) { this.activity = activity; this.app = (ZulipApp) activity.getApplication(); } public void register() { if (checkPlayServices()) { gcm = GoogleCloudMessaging.getInstance(app); regid = getRegistrationId(); if (regid.isEmpty()) { registerInBackground(); } else { Log.i(TAG, "Already registered for GCM: " + regid); } } else { Log.i(TAG, "No valid Google Play Services APK found."); } } private boolean checkPlayServices() { int resultCode = GooglePlayServicesUtil .isGooglePlayServicesAvailable(app); if (resultCode != ConnectionResult.SUCCESS) { if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { GooglePlayServicesUtil.getErrorDialog(resultCode, activity, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } else { Log.i(TAG, "This device is not supported."); } return false; } return true; } private String getRegistrationId() { String regID = app.getSettings().getString("gcm_reg_id", ""); long registeredVersion = app.getSettings() .getLong("gcm_reg_last_version", 0); long currentVersion = app.getAppVersion(); if (registeredVersion != currentVersion) { Log.i(TAG, "App version changed."); return ""; } return regID; } private void storeRegistrationId(Context context, String regId) { Editor ed = app.getSettings().edit(); ed.putString("gcm_reg_id", regId); ed.putLong("gcm_reg_last_version", app.getAppVersion()); ed.apply(); } private void registerInBackground() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(app); } int failures = 0; while (true) { try { regid = gcm.register(SENDER_ID); break; } catch (IOException e) { ZLog.logException(e); failures += 1; long backoff = (long) (Math.exp(failures / 2.0) * 1000); Log.e("GCM", "Failure " + failures + ", sleeping for " + backoff); SystemClock.sleep(backoff); } } Log.i("GCM", "Device registered, registration ID=" + regid); HTTPRequest request = new HTTPRequest(app); request.setProperty("token", regid); request.setMethodAndUrl("POST", "v1/users/me/android_gcm_reg_id"); request.execute(); // Persist the regID - no need to register again. storeRegistrationId(app, regid); } catch (IOException ex) { ZLog.logException(ex); } return null; } }.execute(null, null, null); } public AsyncTask<Void, Void, Void> logOut(final Runnable callback) { return new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { // TODO: if this request fails (say, you log out while // offline), the server will keep sending you notifications. // There's not much we can do about that, but we may // want the receiver to test for logged in status and try // this request again if we get a push message when logged // out (or logged in as the wrong user). The complication is // that we no longer have the API key to make an // authenticated request. HTTPRequest request = new HTTPRequest(app); request.setProperty("token", regid); request.setMethodAndUrl("DELETE", "v1/users/me/android_gcm_reg_id"); request.execute(); storeRegistrationId(app, ""); regid = ""; } catch (IOException ex) { ZLog.logException(ex); } return null; } @Override protected void onPostExecute(Void v) { callback.run(); } }.execute(null, null, null); } }