Java tutorial
/* * * Copyright 2016 Michael A Updike * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.weebly.opus1269.copyeverywhere.cloud; import android.content.Context; import android.util.Log; import com.google.android.gms.auth.api.Auth; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; import com.google.android.gms.auth.api.signin.GoogleSignInResult; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.google.android.gms.iid.InstanceID; import com.weebly.opus1269.copyeverywhere.R; import com.weebly.opus1269.copyeverywhere.helpers.App; import com.weebly.opus1269.copyeverywhere.helpers.AppUtils; import com.weebly.opus1269.copyeverywhere.model.Device; import com.weebly.opus1269.copyeverywhere.model.Devices; import com.weebly.opus1269.copyeverywhere.ui.settings.Prefs; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.Collections; import java.util.concurrent.TimeUnit; /** * Manage GCM Device Group from the client side * see: https://developers.google.com/cloud-messaging/android/client-device-group * */ public class DeviceGroups { private static final String TAG = "DeviceGroups"; private static final int TIMEOUT = 20; private DeviceGroups() { } /** * Add to Device Group - blocks, call off main thread * * @param idToken authorization token * @return message on error, otherwise empty string */ public static String add(String idToken) { String errorMessage = ""; final String keyName = Prefs.getPersonEmail(); try { final String regId = getGcmToken(); // Headers final HttpRequest request = new HttpRequest(); request.setHeader(HttpRequest.HEADER_PROJECT_ID, GcmConstants.PROJECT_ID); request.setHeader(HttpRequest.HEADER_CONTENT_TYPE, HttpRequest.CONTENT_TYPE_JSON); request.setHeader(HttpRequest.HEADER_ACCEPT, HttpRequest.CONTENT_TYPE_JSON); // Request final JSONObject data = new JSONObject(); data.put(GcmConstants.OPERATION, "add"); data.put(GcmConstants.NOTIFICATION_KEY_NAME, keyName); data.put(GcmConstants.REGISTRATION_IDS, new JSONArray(Collections.singletonList(regId))); data.put(GcmConstants.ID_TOKEN, idToken); request.doPost(GcmConstants.URL, data.toString()); final int responseCode = request.getResponseCode(); final JSONObject response = new JSONObject(request.getResponseBody()); if (responseCode == 200) { // success final String notificationKey = response.getString(GcmConstants.NOTIFICATION_KEY); AppUtils.log(TAG, GcmConstants.LOG_NOTIFICATION_KEY + notificationKey); storeValues(true, regId, notificationKey, keyName); } else { errorMessage = response.toString(4); Log.e(TAG, errorMessage); storeValues(false, "", "", keyName); } } catch (IOException | JSONException e) { errorMessage = e.getMessage() + "\n" + e; Log.e(TAG, "Error adding Device Group token: " + errorMessage); storeValues(false, "", "", keyName); } return errorMessage; } /** * Remove from Device Group - blocks, call off main thread * * @param regId GCM token * @param idToken authorization token * @return message on error, otherwise empty string */ public static String remove(String regId, String idToken) { String errorMessage = ""; final String keyName = Prefs.getPersonEmail(); String token = idToken; try { if (token == null) { token = getIdToken(); } // Headers final HttpRequest request = new HttpRequest(); request.setHeader(HttpRequest.HEADER_PROJECT_ID, GcmConstants.PROJECT_ID); request.setHeader(HttpRequest.HEADER_CONTENT_TYPE, HttpRequest.CONTENT_TYPE_JSON); request.setHeader(HttpRequest.HEADER_ACCEPT, HttpRequest.CONTENT_TYPE_JSON); // Request final JSONObject data = new JSONObject(); //noinspection DuplicateStringLiteralInspection data.put(GcmConstants.OPERATION, "remove"); data.put(GcmConstants.NOTIFICATION_KEY_NAME, keyName); data.put(GcmConstants.REGISTRATION_IDS, new JSONArray(Collections.singletonList(regId))); data.put(GcmConstants.ID_TOKEN, token); request.doPost(GcmConstants.URL, data.toString()); final int responseCode = request.getResponseCode(); final JSONObject response = new JSONObject(request.getResponseBody()); if (responseCode == 200) { // remove ourselves from device list final Device device = Device.getMyDevice(); Devices.remove(device); AppUtils.log(TAG, request.getResponseBody()); } else { errorMessage = response.toString(4); Log.e(TAG, errorMessage); } } catch (IOException | JSONException e) { errorMessage = e.getMessage() + "\n" + e; Log.e(TAG, "Error removing Device Group token: " + errorMessage); } Prefs.setGcmId(""); Prefs.setGcmRegistered(false); return errorMessage; } /** * Refresh the GCM token - blocks, call off main thread * * @return message on error, otherwise empty string */ public static String refresh() { final String oldRegId = Prefs.getGcmId(); final String idToken = getIdToken(); final String errorMessage = add(idToken); remove(oldRegId, idToken); return errorMessage; } private static String getGcmToken() throws IOException { final Context context = App.getContext(); // Initially this goes to the network for the token, subsequent calls are local. // R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json. // See https://developers.google.com/cloud-messaging/android/start for details on this file. final InstanceID instanceID = InstanceID.getInstance(context); final String token = instanceID.getToken(context.getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); AppUtils.log(TAG, "Gcm Token: " + token); return token; } private static String getIdToken() { String idToken = ""; // Get the IDToken that can be used securely on the backend for a short time // ID and basic profile are included in DEFAULT_SIGN_IN. final GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(GcmConstants.WEB_CLIENT_ID).build(); // Build a GoogleApiClient with access to the Google Sign-In API and the // options specified by gso. final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(App.getContext()) .addApi(Auth.GOOGLE_SIGN_IN_API, gso).build(); try { final ConnectionResult result = googleApiClient.blockingConnect(TIMEOUT, TimeUnit.SECONDS); if (result.isSuccess()) { final GoogleSignInResult googleSignInResult = Auth.GoogleSignInApi.silentSignIn(googleApiClient) .await(TIMEOUT, TimeUnit.SECONDS); if (googleSignInResult.isSuccess()) { final GoogleSignInAccount acct = googleSignInResult.getSignInAccount(); if (acct != null) { idToken = acct.getIdToken(); } } } } finally { googleApiClient.disconnect(); } return idToken; } private static void storeValues(boolean registered, String gcmId, String key, String keyName) { if (!registered) { // remove ourselves from device list Devices.remove(Device.getMyDevice()); } Prefs.setGcmRegistered(registered); Prefs.setGcmId(gcmId); Prefs.setNotificationKey(key); Prefs.setNotificationKeyName(keyName); if (registered) { // add ourselves to device list final Device device = Device.getMyDevice(); Devices.add(device); // let other devices know about us UpstreamMessages.sendDeviceAdded(device); } } }