com.weebly.opus1269.copyeverywhere.cloud.DeviceGroups.java Source code

Java tutorial

Introduction

Here is the source code for com.weebly.opus1269.copyeverywhere.cloud.DeviceGroups.java

Source

/*
 *
 * 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);
        }
    }
}