com.example.android.geofence.DGGeofencing.java Source code

Java tutorial

Introduction

Here is the source code for com.example.android.geofence.DGGeofencing.java

Source

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.example.android.geofence;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.text.TextUtils;
import android.text.format.DateUtils;

import com.example.android.geofence.GeofenceUtils.REMOVE_TYPE;
import com.example.android.geofence.GeofenceUtils.REQUEST_TYPE;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.Geofence;

import java.util.ArrayList;
import java.util.List;

import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;

/**
 * UI handler for the Location Services Geofence sample app.
 * Allow input of latitude, longitude, and radius for two geofences.
 * When registering geofences, check input and then send the geofences to Location Services.
 * Also allow removing either one of or both of the geofences.
 * The menu allows you to clear the screen or delete the geofences stored in persistent memory.
 */
public class DGGeofencing extends CordovaPlugin {
    /*
     * Use to set an expiration time for a geofence. After this amount
     * of time Location Services will stop tracking the geofence.
     * Remember to unregister a geofence when you're finished with it.
     * Otherwise, your app will use up battery. To continue monitoring
     * a geofence indefinitely, set the expiration time to
     * Geofence#NEVER_EXPIRE.
     */
    private static final long GEOFENCE_EXPIRATION_IN_HOURS = 1200;
    private static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = GEOFENCE_EXPIRATION_IN_HOURS
            * DateUtils.HOUR_IN_MILLIS;

    // Store the current request
    private REQUEST_TYPE mRequestType;

    // Store the current type of removal
    private REMOVE_TYPE mRemoveType;

    // Store a list of geofences to add
    List<Geofence> mCurrentGeofences;

    // Add geofences handler
    private GeofenceRequester mGeofenceRequester;
    // Remove geofences handler
    private GeofenceRemover mGeofenceRemover;

    /*
     * Internal lightweight geofence objects for geofence 1 and 2
     */
    private SimpleGeofence mUIGeofence1;

    // An intent filter for the broadcast receiver
    private IntentFilter mIntentFilter;

    // Store the list of geofences to remove
    private List<String> mGeofenceIdsToRemove;

    public static CallbackContext cbContext;

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {

        if (action.equalsIgnoreCase("initCallbackForRegionMonitoring")) {
            cbContext = callbackContext;
        } else if (action.equalsIgnoreCase("startMonitoringRegion")) {

            // Create an intent filter for the broadcast receiver
            mIntentFilter = new IntentFilter();

            // Action for broadcast Intents that report successful addition of geofences
            mIntentFilter.addAction(GeofenceUtils.ACTION_GEOFENCES_ADDED);

            // Action for broadcast Intents that report successful removal of geofences
            mIntentFilter.addAction(GeofenceUtils.ACTION_GEOFENCES_REMOVED);

            // Action for broadcast Intents containing various types of geofencing errors
            mIntentFilter.addAction(GeofenceUtils.ACTION_GEOFENCE_ERROR);

            // All Location Services sample apps use this category
            mIntentFilter.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);

            // Instantiate the current List of geofences
            mCurrentGeofences = new ArrayList<Geofence>();

            // Instantiate a Geofence requester
            mGeofenceRequester = new GeofenceRequester(this.cordova.getActivity());

            // Instantiate a Geofence remover
            mGeofenceRemover = new GeofenceRemover(this.cordova.getActivity());

            // Attach to the main UI
            //setContentView(R.layout.activity_main);

            /*
             * Record the request as an ADD. If a connection error occurs,
             * the app can automatically restart the add request if Google Play services
             * can fix the error
             */
            mRequestType = GeofenceUtils.REQUEST_TYPE.ADD;

            /*
             * Check for Google Play services. Do this after
             * setting the request type. If connecting to Google Play services
             * fails, onActivityResult is eventually called, and it needs to
             * know what type of request was in progress.
             */
            if (!servicesConnected()) {
                return false;
            }

            /*
             * Create a version of geofence 1 that is "flattened" into individual fields. This
             * allows it to be stored in SharedPreferences.
             */
            double lat = Double.valueOf(args.getString(1));
            double lng = Double.valueOf(args.getString(2));
            float radius = Float.valueOf(args.getString(3));

            mUIGeofence1 = new SimpleGeofence("1",
                    // Get latitude, longitude, and radius from the UI
                    lat, lng, radius,
                    // Set the expiration time
                    GEOFENCE_EXPIRATION_IN_MILLISECONDS,
                    // Only detect entry transitions
                    Geofence.GEOFENCE_TRANSITION_ENTER);

            /*
             * Add Geofence objects to a List. toGeofence()
             * creates a Location Services Geofence object from a
             * flat object
             */
            mCurrentGeofences.add(mUIGeofence1.toGeofence());

            // Start the request. Fail if there's already a request in progress
            try {
                // Try to add geofences
                mGeofenceRequester.addGeofences(mCurrentGeofences);
            } catch (UnsupportedOperationException e) {
                // Notify user that previous request hasn't finished.
            }
        }
        return true;
    }

    /*
     * Handle results returned to this Activity by other Activities started with
     * startActivityForResult(). In particular, the method onConnectionFailed() in
     * GeofenceRemover and GeofenceRequester may call startResolutionForResult() to
     * start an Activity that handles Google Play services problems. The result of this
     * call returns here, to onActivityResult.
     * calls
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        // Choose what to do based on the request code
        switch (requestCode) {

        // If the request code matches the code sent in onConnectionFailed
        case GeofenceUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST:

            switch (resultCode) {
            // If Google Play services resolved the problem
            case Activity.RESULT_OK:

                // If the request was to add geofences
                if (GeofenceUtils.REQUEST_TYPE.ADD == mRequestType) {

                    // Toggle the request flag and send a new request
                    mGeofenceRequester.setInProgressFlag(false);

                    // Restart the process of adding the current geofences
                    mGeofenceRequester.addGeofences(mCurrentGeofences);

                    // If the request was to remove geofences
                } else if (GeofenceUtils.REQUEST_TYPE.REMOVE == mRequestType) {

                    // Toggle the removal flag and send a new removal request
                    mGeofenceRemover.setInProgressFlag(false);

                    // If the removal was by Intent
                    if (GeofenceUtils.REMOVE_TYPE.INTENT == mRemoveType) {

                        // Restart the removal of all geofences for the PendingIntent
                        mGeofenceRemover.removeGeofencesByIntent(mGeofenceRequester.getRequestPendingIntent());

                        // If the removal was by a List of geofence IDs
                    } else {

                        // Restart the removal of the geofence list
                        mGeofenceRemover.removeGeofencesById(mGeofenceIdsToRemove);
                    }
                }
                break;

            // If any other result was returned by Google Play services
            default:

                // Report that Google Play services was unable to resolve the problem.
            }

            // If any other request code was received
        default:
            // Report that this Activity received an unknown requestCode

            break;
        }
    }

    /**
     * Verify that Google Play services is available before making a request.
     *
     * @return true if Google Play services is available, otherwise false
     */
    private boolean servicesConnected() {

        // Check that Google Play services is available
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this.cordova.getActivity());

        // If Google Play services is available
        if (ConnectionResult.SUCCESS == resultCode) {
            // Continue
            return true;

            // Google Play services was not available for some reason
        } else {
            return false;
        }
    }

    /**
     * Define a Broadcast receiver that receives updates from connection listeners and
     * the geofence transition service.
     */
    public class GeofenceSampleReceiver extends BroadcastReceiver {
        /*
         * Define the required method for broadcast receivers
         * This method is invoked when a broadcast Intent triggers the receiver
         */
        @Override
        public void onReceive(Context context, Intent intent) {

            // Check the action code and determine what to do
            String action = intent.getAction();

            // Intent contains information about errors in adding or removing geofences
            if (TextUtils.equals(action, GeofenceUtils.ACTION_GEOFENCE_ERROR)) {

                handleGeofenceError(context, intent);

                // Intent contains information about successful addition or removal of geofences
            } else if (TextUtils.equals(action, GeofenceUtils.ACTION_GEOFENCES_ADDED)
                    || TextUtils.equals(action, GeofenceUtils.ACTION_GEOFENCES_REMOVED)) {

                handleGeofenceStatus(context, intent);

                // Intent contains information about a geofence transition
            } else if (TextUtils.equals(action, GeofenceUtils.ACTION_GEOFENCE_TRANSITION)) {

                handleGeofenceTransition(context, intent);

                // The Intent contained an invalid action
            } else {
            }
        }

        /**
         * If you want to display a UI message about adding or removing geofences, put it here.
         *
         * @param context A Context for this component
         * @param intent The received broadcast Intent
         */
        private void handleGeofenceStatus(Context context, Intent intent) {
        }

        /**
         * Report geofence transitions to the UI
         *
         * @param context A Context for this component
         * @param intent The Intent containing the transition
         */
        private void handleGeofenceTransition(Context context, Intent intent) {
            /*
             * If you want to change the UI when a transition occurs, put the code
             * here. The current design of the app uses a notification to inform the
             * user that a transition has occurred.
             */
        }

        /**
         * Report addition or removal errors to the UI, using a Toast
         *
         * @param intent A broadcast Intent sent by ReceiveTransitionsIntentService
         */
        private void handleGeofenceError(Context context, Intent intent) {
        }
    }
}