org.jboss.aerogear.cordova.push.PushPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.aerogear.cordova.push.PushPlugin.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * Copyright Red Hat, Inc., and individual contributors
 *
 * 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 org.jboss.aerogear.cordova.push;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;

import org.apache.cordova.*;
import org.jboss.aerogear.android.Callback;
import org.jboss.aerogear.android.unifiedpush.PushConfig;
import org.jboss.aerogear.android.unifiedpush.PushRegistrar;
import org.jboss.aerogear.android.unifiedpush.Registrations;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author edewit@redhat.com
 */
public class PushPlugin extends CordovaPlugin {
    public static final String TAG = "PushPlugin";

    private static final String UNIFIED_PUSH_URL = "pushServerURL";
    private static final String GCM_SENDER_ID = "senderID";
    private static final String VARIANT_ID = "variantID";
    private static final String SECRET = "variantSecret";
    private static final String DEVICE_TOKEN = "deviceToken";
    private static final String CATEGORIES = "categories";
    private static final String ALIAS = "alias";

    public static final String REGISTER = "register";
    public static final String UNREGISTER = "unregister";

    private static final String REGISTRAR = "registrar";
    private static final String SETTINGS = "settings";

    private static CallbackContext context;
    private static Bundle cachedMessage = null;
    private static boolean foreground = false;

    private SharedPreferences preferences;

    /**
     * Gets the application context from cordova's main activity.
     * @return the application context
     */
    private Context getApplicationContext() {
        return this.cordova.getActivity().getApplicationContext();
    }

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
        preferences = cordova.getActivity().getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
    }

    @Override
    public boolean execute(String action, JSONArray data, final CallbackContext callbackContext) {
        Log.v(TAG, "execute: action=" + action);
        foreground = true;

        if (REGISTER.equals(action)) {
            Log.v(TAG, "execute: data=" + data.toString());

            try {
                context = callbackContext;

                JSONObject pushConfig = parseConfig(data);
                saveConfig(pushConfig);
                cordova.getThreadPool().execute(new Runnable() {
                    @Override
                    public void run() {
                        register(callbackContext);
                    }
                });
            } catch (JSONException e) {
                callbackContext.error(e.getMessage());
                return false;
            }

            if (cachedMessage != null) {
                Log.v(TAG, "sending cached extras");
                sendMessage(cachedMessage);
                cachedMessage = null;
            }

            return true;
        } else if (UNREGISTER.equals(action)) {

            unRegister(callbackContext);
            return true;
        } else {
            callbackContext.error("Invalid action : " + action);
        }

        return false;
    }

    private JSONObject parseConfig(JSONArray data) throws JSONException {
        JSONObject pushConfig = data.getJSONObject(0);
        if (!pushConfig.isNull("android")) {
            final JSONObject android = pushConfig.getJSONObject("android");
            for (Iterator iterator = android.keys(); iterator.hasNext();) {
                String key = (String) iterator.next();
                pushConfig.put(key, android.get(key));
            }

            pushConfig.remove("android");
        }
        return pushConfig;
    }

    private void saveConfig(JSONObject config) throws JSONException {
        final SharedPreferences.Editor editor = preferences.edit();
        for (Iterator i = config.keys(); i.hasNext();) {
            final String key = String.valueOf(i.next());
            editor.putString(key, config.getString(key));
        }

        editor.commit();
    }

    private void register(final CallbackContext callbackContext) {
        try {
            Registrations registrations = new Registrations();
            final PushConfig pushConfig = getPushConfig();
            PushRegistrar registrar = registrations.push(REGISTRAR, pushConfig);
            registrar.register(getApplicationContext(), new Callback<Void>() {
                @Override
                public void onSuccess(Void data) {
                    preferences.edit().putString(DEVICE_TOKEN, pushConfig.getDeviceToken()).commit();
                    PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    webView.sendJavascript(
                            "cordova.require('org.jboss.aerogear.cordova.push.AeroGear.UnifiedPush').successCallback()");
                }

                @Override
                public void onFailure(Exception e) {
                    callbackContext.error(e.getMessage());
                }
            });
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
        }
    }

    private void unRegister(CallbackContext callbackContext) {
        PushRegistrar registrar = getPushRegistrar();
        registrar.unregister(getApplicationContext(), new VoidCallback(callbackContext));
    }

    private PushRegistrar getPushRegistrar() {
        Registrations registrations = new Registrations();
        return registrations.push(REGISTRAR, getPushConfig());
    }

    private PushConfig getPushConfig() {
        try {
            final URI pushServerURI = new URI(preferences.getString(UNIFIED_PUSH_URL, null));
            PushConfig config = new PushConfig(pushServerURI, preferences.getString(GCM_SENDER_ID, null));
            config.setVariantID(preferences.getString(VARIANT_ID, null));
            config.setSecret(preferences.getString(SECRET, null));
            config.setAlias(preferences.getString(ALIAS, null));
            config.setDeviceToken(preferences.getString(DEVICE_TOKEN, null));
            final String categories = preferences.getString(CATEGORIES, null);
            config.setCategories(convert(categories));
            return config;
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private List<String> convert(String categories) throws JSONException {
        List<String> categoryList = null;
        if (categories != null) {
            categoryList = new ArrayList<String>();
            final JSONArray jsonArray = new JSONArray(categories);
            for (int i = 0; i < jsonArray.length(); i++) {
                categoryList.add(jsonArray.getString(i));
            }
        }
        return categoryList;
    }

    /**
     * Sends the message to the client application.
     * If the client application isn't currently active, it is cached for later processing.
     * @param message the message to be send to the client
     */
    public static void sendMessage(Bundle message) {
        if (message != null) {
            message.putBoolean("foreground", foreground);
            if (context != null) {
                PluginResult result = new PluginResult(PluginResult.Status.OK, convertBundleToJson(message));
                result.setKeepCallback(true);
                context.sendPluginResult(result);
            } else {
                Log.v(TAG, "sendMessage: caching message to send at a later time.");
                cachedMessage = message;
            }
        }
    }

    @Override
    public void onPause(boolean multitasking) {
        super.onPause(multitasking);
        foreground = false;
    }

    @Override
    public void onResume(boolean multitasking) {
        super.onResume(multitasking);
        foreground = true;
    }

    /**
     * Serializes a bundle to JSON.
     * @param message to be serialized
     */
    private static JSONObject convertBundleToJson(Bundle message) {
        try {
            JSONObject json;
            json = new JSONObject();

            JSONObject jsondata = new JSONObject();
            for (String key : message.keySet()) {
                Object value = message.get(key);

                // System data from Android
                if (key.equals("from") || key.equals("collapse_key")) {
                    json.put(key, value);
                } else if (key.equals("foreground")) {
                    json.put(key, message.getBoolean("foreground"));
                } else if (key.equals("coldstart")) {
                    json.put(key, message.getBoolean("coldstart"));
                } else {
                    // Maintain backwards compatibility
                    if (key.equals("message") || key.equals("msgcnt") || key.equals("sound")
                            || key.equals("alert")) {
                        json.put(key, value);
                    }

                    if (value instanceof String) {
                        // Try to figure out if the value is another JSON object

                        String strValue = (String) value;
                        if (strValue.startsWith("{")) {
                            try {
                                JSONObject json2 = new JSONObject(strValue);
                                jsondata.put(key, json2);
                            } catch (Exception e) {
                                jsondata.put(key, value);
                            }
                            // Try to figure out if the value is another JSON array
                        } else if (strValue.startsWith("[")) {
                            try {
                                JSONArray json2 = new JSONArray(strValue);
                                jsondata.put(key, json2);
                            } catch (Exception e) {
                                jsondata.put(key, value);
                            }
                        } else {
                            jsondata.put(key, value);
                        }
                    }
                }
            } // while
            json.put("payload", jsondata);

            Log.v(TAG, "extrasToJSON: " + json.toString());

            return json;
        } catch (JSONException e) {
            Log.e(TAG, "extrasToJSON: JSON exception");
        }
        return null;
    }

    public static boolean isInForeground() {
        return foreground;
    }

    public static void setForeground(boolean foreground) {
        PushPlugin.foreground = foreground;
    }

    public static boolean isActive() {
        return context != null;
    }

    public void onDestroy() {
        context = null;
        super.onDestroy();
    }

    private class VoidCallback implements Callback<Void> {
        private final CallbackContext callbackContext;

        public VoidCallback(CallbackContext callbackContext) {
            this.callbackContext = callbackContext;
        }

        @Override
        public void onSuccess(Void data) {
            callbackContext.success("OK");
        }

        @Override
        public void onFailure(Exception e) {
            callbackContext.error(e.getMessage());
        }
    }
}