diff --git a/app/src/main/java/com/example/android/sunshine/app/MainActivity.java b/app/src/main/java/com/example/android/sunshine/app/MainActivity.java index 4960cfa..07068f5 100644 --- a/app/src/main/java/com/example/android/sunshine/app/MainActivity.java +++ b/app/src/main/java/com/example/android/sunshine/app/MainActivity.java @@ -15,8 +15,14 @@ */ package com.example.android.sunshine.app; +import android.app.AlertDialog; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; @@ -26,15 +32,28 @@ import android.view.MenuItem; import com.example.android.sunshine.app.sync.SunshineSyncAdapter; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; +import com.google.android.gms.gcm.GoogleCloudMessaging; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; public class MainActivity extends ActionBarActivity implements ForecastFragment.Callback { private final String LOG_TAG = MainActivity.class.getSimpleName(); private static final String DETAILFRAGMENT_TAG = "DFTAG"; private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; + public static final String PROPERTY_REG_ID = "registration_id"; + private static final String PROPERTY_APP_VERSION = "appVersion"; + + /** + * Substitute you own sender ID here. This is the project number you got + * from the API Console. + */ + String SENDER_ID = "Your-Sender-ID"; private boolean mTwoPane; private String mLocation; + private GoogleCloudMessaging mGcm; @Override protected void onCreate(Bundle savedInstanceState) { @@ -66,12 +85,26 @@ public class MainActivity extends ActionBarActivity implements ForecastFragment. SunshineSyncAdapter.initializeSyncAdapter(this); - if (!checkPlayServices()) { - // this is where we could either prompt a user that they should install - // the latest version of Google Play Services, or add an error snackbar - // that some features won't be available. - } + // If Google Play Services is not available, some features, such as GCM-powered weather + // alerts, will not be available. + if (checkPlayServices()) { + mGcm = GoogleCloudMessaging.getInstance(this); + String regId = getRegistrationId(this); + if (SENDER_ID.equals("Your-Sender-ID")) { + new AlertDialog.Builder(this) + .setTitle("Needs Sender ID") + .setMessage("GCM will not function in Sunshine until you replace your Sender ID with a Sender ID from the Google Developers Console.") + .setPositiveButton(android.R.string.ok, null) + .create().show(); + } else if (regId.isEmpty()) { + registerInBackground(this); + } + } else { + Log.i(LOG_TAG, "No valid Google Play Services APK. Weather alerts will be disabled."); + // Store regID as null + storeRegistrationId(this, null); + } } @Override @@ -162,4 +195,113 @@ public class MainActivity extends ActionBarActivity implements ForecastFragment. } return true; } + + /** + * Gets the current registration ID for application on GCM service. + *

+ * If result is empty, the app needs to register. + * + * @return registration ID, or empty string if there is no existing + * registration ID. + */ + private String getRegistrationId(Context context) { + final SharedPreferences prefs = getGCMPreferences(context); + String registrationId = prefs.getString(PROPERTY_REG_ID, ""); + if (registrationId.isEmpty()) { + Log.i(LOG_TAG, "GCM Registration not found."); + return ""; + } + + // Check if app was updated; if so, it must clear the registration ID + // since the existing registration ID is not guaranteed to work with + // the new app version. + int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE); + int currentVersion = getAppVersion(context); + if (registeredVersion != currentVersion) { + Log.i(LOG_TAG, "App version changed."); + return ""; + } + return registrationId; + } + + /** + * @return Application's {@code SharedPreferences}. + */ + private SharedPreferences getGCMPreferences(Context context) { + // Sunshine persists the registration ID in shared preferences, but + // how you store the registration ID in your app is up to you. Just make sure + // that it is private! + return getSharedPreferences(MainActivity.class.getSimpleName(), Context.MODE_PRIVATE); + } + + /** + * @return Application's version code from the {@code PackageManager}. + */ + private static int getAppVersion(Context context) { + try { + PackageInfo packageInfo = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0); + return packageInfo.versionCode; + } catch (PackageManager.NameNotFoundException e) { + // Should never happen. WHAT DID YOU DO?!?! + throw new RuntimeException("Could not get package name: " + e); + } + } + + /** + * Registers the application with GCM servers asynchronously. + *

+ * Stores the registration ID and app versionCode in the application's + * shared preferences. + */ + private void registerInBackground(final Context context) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + String msg = ""; + try { + if (mGcm == null) { + mGcm = GoogleCloudMessaging.getInstance(context); + } + String regId = mGcm.register(SENDER_ID); + msg = "Device registered, registration ID=" + regId; + + // You should send the registration ID to your server over HTTP, + // so it can use GCM/HTTP or CCS to send messages to your app. + // The request to your server should be authenticated if your app + // is using accounts. + //sendRegistrationIdToBackend(); + // For this demo: we don't need to send it because the device + // will send upstream messages to a server that echo back the + // message using the 'from' address in the message. + + // Persist the registration ID - no need to register again. + storeRegistrationId(context, regId); + } catch (IOException ex) { + msg = "Error :" + ex.getMessage(); + // TODO(joannasmith): If there is an error, don't just keep trying to register. + // Require the user to click a button again, or perform + // exponential back-off. + } + return null; + } + }.execute(null, null, null); + } + + /** + * Stores the registration ID and app versionCode in the application's + * {@code SharedPreferences}. + * + * @param context application's context. + * @param regId registration ID + */ + private void storeRegistrationId(Context context, String regId) { + final SharedPreferences prefs = getGCMPreferences(context); + int appVersion = getAppVersion(context); + Log.i(LOG_TAG, "Saving regId on app version " + appVersion); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(PROPERTY_REG_ID, regId); + editor.putInt(PROPERTY_APP_VERSION, appVersion); + editor.commit(); + } }