org.jboss.aerogear.cordova.geo.GeofencingPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.aerogear.cordova.geo.GeofencingPlugin.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.geo;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static org.jboss.aerogear.cordova.geo.GeofencingService.TAG;

/**
 * Corodova Plugin to create Geofences.
 *
 * @author edewit@redhat.com
 */
public class GeofencingPlugin extends CordovaPlugin {

    private static JSONObject cachedRegionEvent;
    private static boolean foreground;
    private static String notifyMessage;
    private static List<PluginCommand> pendingActions = new ArrayList<PluginCommand>();

    private Timer timer = new Timer();

    private GeofencingService service;
    private static CallbackContext callbackContext;
    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            GeofencingService.LocalBinder binder = (GeofencingService.LocalBinder) service;
            GeofencingPlugin.this.service = binder.getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    @Override
    public void onNewIntent(Intent intent) {
        fireRegionChangedEvent(intent);
    }

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);

        Intent intent = new Intent(cordova.getActivity(), GeofencingService.class);
        cordova.getActivity().bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onDestroy() {
        cordova.getActivity().unbindService(connection);
    }

    @Override
    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
        try {
            return invokeService(new PluginCommand(action, data, callbackContext));
        } catch (Exception e) {
            StringWriter writer = new StringWriter();
            PrintWriter err = new PrintWriter(writer);
            e.printStackTrace(err);
            Log.e(TAG, writer.toString());
            callbackContext.error(e.getMessage());
        }

        return false;
    }

    private boolean invokeService(final PluginCommand pluginCommand) throws JSONException {
        if (service != null) {
            if ("register".equals(pluginCommand.getAction())) {
                callbackContext = pluginCommand.getCallbackContext();
                PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
                result.setKeepCallback(true);
                callbackContext.sendPluginResult(result);

                if (cachedRegionEvent != null) {
                    sendNotification(cachedRegionEvent);
                }

                return true;
            }
            if ("addRegion".equals(pluginCommand.getAction())) {
                JSONObject params = parseParameters(pluginCommand.getData());
                String id = params.getString("fid");
                Log.d(TAG, "adding region " + id);
                service.addRegion(id, params.getDouble("latitude"), params.getDouble("longitude"),
                        (float) params.getInt("radius"));
                pluginCommand.getCallbackContext().success();
                return true;
            }
            if ("removeRegion".equals(pluginCommand.getAction())) {
                JSONObject params = parseParameters(pluginCommand.getData());
                String id = params.getString("fid");
                service.removeRegion(id);
                return true;
            }
            if ("getWatchedRegionIds".equals(pluginCommand.getAction())) {
                pluginCommand.getCallbackContext().success(new JSONArray(service.getWatchedRegionIds()));
                return true;
            }

            return false;
        } else {
            pendingActions.add(pluginCommand);
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (service != null) {
                        for (PluginCommand args : pendingActions) {
                            try {
                                invokeService(args);
                            } catch (JSONException e) {
                                pluginCommand.callbackContext.error(e.getMessage());
                            }
                        }

                        pendingActions.clear();
                        cancel();
                    }
                }
            }, 2000);

            return true;
        }
    }

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

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

    void fireRegionChangedEvent(final Intent intent) {
        cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                sendNotification(intent.getExtras());
            }
        });
    }

    public static void sendNotification(Bundle bundle) {
        if (bundle != null) {
            final String status = bundle.getString("status");
            final String id = bundle.getString("id");
            sendNotification(createRegionEvent(id, status));
        }
    }

    public static void sendNotification(String id, String status) {
        sendNotification(createRegionEvent(id, status));
    }

    private static void sendNotification(JSONObject regionEvent) {
        if (callbackContext != null) {
            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, regionEvent);
            pluginResult.setKeepCallback(true);
            callbackContext.sendPluginResult(pluginResult);
        } else {
            cachedRegionEvent = regionEvent;
        }
    }

    private static JSONObject createRegionEvent(String id, String status) {
        JSONObject data = new JSONObject();
        try {
            data.put("fid", id);
            data.put("status", status);
        } catch (JSONException e) {
            throw new RuntimeException("could not create json object", e);
        }
        return data;
    }

    private JSONObject parseParameters(JSONArray data) throws JSONException {
        if (data.length() == 1 && !data.isNull(0)) {
            return (JSONObject) data.get(0);
        } else {
            throw new IllegalArgumentException("Invalid arguments specified!");
        }
    }

    public static boolean isInForeground() {
        return foreground;
    }

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

    public static String getNotifyMessage() {
        return notifyMessage;
    }

    private static class PluginCommand {
        private final String action;
        private final JSONArray data;
        private final CallbackContext callbackContext;

        private PluginCommand(String action, JSONArray data, CallbackContext callbackContext) {
            this.action = action;
            this.data = data;
            this.callbackContext = callbackContext;
        }

        public String getAction() {
            return action;
        }

        public JSONArray getData() {
            return data;
        }

        public CallbackContext getCallbackContext() {
            return callbackContext;
        }
    }
}