package de.tum.in.tumcampusapp.services; import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.google.android.gms.iid.InstanceID; import com.google.android.gms.iid.InstanceIDListenerService; import java.io.IOException; import java.util.Date; import de.tum.in.tumcampusapp.api.TUMCabeClient; import de.tum.in.tumcampusapp.auxiliary.Const; import de.tum.in.tumcampusapp.auxiliary.Utils; import de.tum.in.tumcampusapp.exceptions.NoPrivateKey; import de.tum.in.tumcampusapp.models.tumcabe.DeviceUploadGcmToken; import de.tum.in.tumcampusapp.models.tumcabe.TUMCabeStatus; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; public class GcmIdentificationService extends InstanceIDListenerService { private static final String SENDER_ID = "944892355389"; private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; private final Context mContext; public GcmIdentificationService() { mContext = null; } public GcmIdentificationService(Context c) { mContext = c; } /** * Registers this phone with InstanceID and returns a valid token to be transmitted to the server * * @return String token that can be used to transmit messages to this client */ public String register() throws IOException { String iid = InstanceID.getInstance(mContext).getId(); String token = InstanceID.getInstance(mContext).getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE); Utils.setInternalSetting(mContext, Const.GCM_INSTANCE_ID, iid); Utils.setInternalSetting(mContext, Const.GCM_TOKEN_ID, token); return token; } public void unregister() throws IOException { InstanceID.getInstance(mContext).deleteInstanceID(); Utils.setInternalSetting(mContext, Const.GCM_INSTANCE_ID, ""); Utils.setInternalSetting(mContext, Const.GCM_TOKEN_ID, ""); } /** * Actual service routine which can use this as a context */ @Override public void onTokenRefresh() { InstanceID iid = InstanceID.getInstance(this); try { String token = iid.getToken(GcmIdentificationService.SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE); Utils.setInternalSetting(this, Const.GCM_TOKEN_ID, token); } catch (IOException e) { Utils.log(e, "Failed to refresh token"); } // send this tokenItem.token to your server } public String getCurrentToken() { return Utils.getInternalSettingString(this.mContext, Const.GCM_TOKEN_ID, ""); } public void checkSetup() { String token = this.getCurrentToken(); //If we failed, we need to re register if (token.isEmpty()) { this.registerInBackground(); } else { // If the regId is not empty, we still need to check whether it was successfully sent to the TCA server, because this can fail due to user not confirming their private key if (!Utils.getInternalSettingBool(mContext, Const.GCM_REG_ID_SENT_TO_SERVER, false)) { this.sendTokenToBackend(token); } //Update the reg id in steady intervals this.checkRegisterIdUpdate(token); } } /** * Check the device to make sure it has the Google Play Services APK. If * it doesn't, display a dialog that allows users to download the APK from * the Google Play Store or enable it in the device's system settings. */ public static boolean checkPlayServices(final Activity a) { final int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(a); if (resultCode != ConnectionResult.SUCCESS) { if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)) { a.runOnUiThread(new Runnable() { @Override public void run() { GoogleApiAvailability.getInstance().getErrorDialog(a, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } }); } else { Utils.log("This device is not supported by Google Play services."); } return false; } return true; } /** * Registers the application with GCM servers asynchronously. * <p> * Stores the registration ID and app versionCode in the application's * shared preferences. */ private void registerInBackground() { new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { try { //Register a new id String token = GcmIdentificationService.this.register(); //Reset the lock in case we are updating and maybe failed Utils.setInternalSetting(mContext, Const.GCM_REG_ID_SENT_TO_SERVER, false); Utils.setInternalSetting(mContext, Const.GCM_REG_ID_LAST_TRANSMISSION, new Date().getTime()); // Let the server know of our new registration id GcmIdentificationService.this.sendTokenToBackend(token); return "GCM registration successful"; } catch (IOException ex) { //Return the error message return "Error :" + ex.getMessage(); } } @Override protected void onPostExecute(String msg) { Utils.log(msg); } }.execute(); } /** * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP * or CCS to send messages to your app. Not needed for this demo since the * device sends upstream messages to a server that echoes back the message * using the 'from' address in the message. */ private void sendTokenToBackend(String token) { //@todo //Check if all parameters are present if (token == null || token.isEmpty()) { Utils.logv("Parameter missing for sending reg id"); return; } //Try to create the message DeviceUploadGcmToken dgcm; try { dgcm = new DeviceUploadGcmToken(mContext, token); } catch (NoPrivateKey noPrivateKey) { return; } TUMCabeClient.getInstance(mContext).deviceUploadGcmToken(dgcm, new Callback<TUMCabeStatus>() { @Override public void onResponse(Call<TUMCabeStatus> call, Response<TUMCabeStatus> response) { TUMCabeStatus s = response.body(); if (response.isSuccessful() && s != null) { Utils.logv("Success uploading GCM registration id: " + response.body().getStatus()); // Store in shared preferences the information that the GCM registration id was sent to the TCA server successfully Utils.setInternalSetting(mContext, Const.GCM_REG_ID_SENT_TO_SERVER, true); } else { Utils.logv("Uploading GCM registration failed..."); } } @Override public void onFailure(Call<TUMCabeStatus> call, Throwable t) { Utils.log(t, "Failure uploading GCM registration id"); Utils.setInternalSetting(mContext, Const.GCM_REG_ID_SENT_TO_SERVER, false); } }); } /** * Helper function to check if we need to update the regid * * @param regId registration ID */ private void checkRegisterIdUpdate(String regId) { //Regularly (once a day) update the server with the reg id long lastTransmission = Utils.getInternalSettingLong(mContext, Const.GCM_REG_ID_LAST_TRANSMISSION, 0); Date now = new Date(); if (now.getTime() - 24 * 3600000 > lastTransmission) { this.sendTokenToBackend(regId); } } }