package com.example.gcm; import android.app.Activity; import android.content.Context; import android.net.Uri; import com.example.ExampleConfig; import com.example.utility.Preferences; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import org.alfonz.utility.Logcat; import org.alfonz.utility.VersionUtility; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Random; public final class GcmUtility { private static final int MAX_ATTEMPTS = 5; private static final int BACKOFF_MILLI_SECONDS = 2000; private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; private static final Random sRandom = new Random(); private GcmUtility() {} public static boolean checkPlayServices(Activity activity) { int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity); if(resultCode != ConnectionResult.SUCCESS) { if(GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { GooglePlayServicesUtil.getErrorDialog(resultCode, activity, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } else { Logcat.e("this device is not supported"); activity.finish(); } return false; } return true; } public static String getRegistrationId(Context context) { Preferences preferences = new Preferences(); // get saved registration id String registrationId = preferences.getGcmRegistrationId(); if(registrationId.isEmpty()) { Logcat.d("registration id not found"); return ""; } // check if app was updated int registeredVersion = preferences.getGcmVersionCode(); int currentVersion = VersionUtility.getVersionCode(context); if(registeredVersion != currentVersion) { Logcat.d("app version has changed"); return ""; } return registrationId; } // register this account/device pair within the server public static void register(final Context context, final String registrationId) { Logcat.d("registering device with registration id = %s", registrationId); // request url String requestUrl = ExampleConfig.GCM_REGISTER_URL; // request params Uri.Builder builder = new Uri.Builder(); builder.appendQueryParameter("regId", registrationId); String params = builder.build().toString().substring(1); // initial sleep time before next try long backoff = BACKOFF_MILLI_SECONDS + sRandom.nextInt(1000); // Once GCM returns a registration id, we need to register it on the server. // As the server might be down, we will retry it a couple times. for(int i = 1; i <= MAX_ATTEMPTS; i++) { Logcat.d("attempt #%d to register", i); try { post(requestUrl, params); // TODO: use post or get Preferences preferences = new Preferences(); preferences.setGcmRegistrationId(registrationId); preferences.setGcmVersionCode(VersionUtility.getVersionCode(context)); Logcat.d("server successfully registered device"); return; } catch(IOException e) { // Here we are simplifying and retrying on any error. // In a real application, it should retry only on unrecoverable errors (like HTTP error code 503). Logcat.e("server failed to register on attempt #%d / exception " + e.getMessage(), i); if(i == MAX_ATTEMPTS) break; try { Logcat.d("sleeping for %d ms before retry", backoff); Thread.sleep(backoff); } catch(InterruptedException interruptedException) { // activity finished before we complete Logcat.d("thread interrupted so abort remaining retries"); Thread.currentThread().interrupt(); return; } // increase backoff exponentially backoff *= 2; } } Logcat.d("could not register device on server after %d attempts", MAX_ATTEMPTS); } // unregister this account/device pair within the server public static void unregister(final Context context, final String registrationId) { Logcat.d("unregistering device with registration id = %s", registrationId); // request url String requestUrl = ExampleConfig.GCM_UNREGISTER_URL; // request params Uri.Builder builder = new Uri.Builder(); builder.appendQueryParameter("regId", registrationId); String params = builder.build().toString().substring(1); try { post(requestUrl, params); // TODO: use post or get Preferences preferences = new Preferences(); preferences.setGcmRegistrationId(""); preferences.setGcmVersionCode(-1); Logcat.d("server successfully unregistered device"); } catch(IOException e) { // At this point the device is unregistered from GCM, but still registered on the server. // We could try to unregister again, but it is not necessary: if the server tries to send a message to the device, // it will get a "NotRegistered" error message and should unregister the device. Logcat.e("could not unregister device on server / exception " + e.getMessage()); } } // send a POST request to the server private static void post(String requestUrl, String params) throws IOException { // create new URL URL url; try { url = new URL(requestUrl); } catch(MalformedURLException e) { throw new IllegalArgumentException("Invalid url " + requestUrl); } // data byte[] requestData = params.getBytes(); Logcat.d("sending '" + params + "' to " + url); // URL connection HttpURLConnection connection = null; try { connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); connection.setFixedLengthStreamingMode(requestData.length); connection.setDoOutput(true); connection.setUseCaches(false); connection.connect(); // post the request OutputStream outputStream = connection.getOutputStream(); outputStream.write(requestData); outputStream.close(); // handle the response int status = connection.getResponseCode(); if(status != 200) { throw new IOException("POST failed with error code " + status); } } finally { if(connection != null) connection.disconnect(); } } // send a GET request to the server private static void get(String baseUrl, String params) throws IOException { // request URL StringBuilder builder = new StringBuilder(); builder.append(baseUrl); if(params != null && !params.equals("")) { builder.append("?"); builder.append(params); } String requestUrl = builder.toString(); // create new URL URL url; try { url = new URL(requestUrl); } catch(MalformedURLException e) { throw new IllegalArgumentException("Invalid url " + requestUrl); } Logcat.d("sending " + requestUrl); // URL connection HttpURLConnection connection = null; try { connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); connection.setUseCaches(false); connection.connect(); // handle the response int status = connection.getResponseCode(); if(status != 200) { throw new IOException("GET failed with error code " + status); } } finally { if(connection != null) connection.disconnect(); } } }