com.platform.middlewares.plugins.GeoLocationPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.platform.middlewares.plugins.GeoLocationPlugin.java

Source

package com.platform.middlewares.plugins;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;

import com.breadwallet.presenter.activities.MainActivity;
import com.breadwallet.tools.manager.SharedPreferencesManager;
import com.breadwallet.tools.util.BRConstants;
import com.platform.BRHTTPHelper;
import com.platform.GeoLocationManager;
import com.platform.interfaces.Plugin;

import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.websocket.api.Session;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * BreadWallet
 * <p/>
 * Created by Mihail Gutan on <mihail@breadwallet.com> 11/2/16.
 * Copyright (c) 2016 breadwallet LLC
 * <p/>
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * <p/>
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * <p/>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
public class GeoLocationPlugin implements Plugin {
    public static final String TAG = GeoLocationPlugin.class.getName();

    private static Continuation continuation;
    private static Request globalBaseRequest;

    public static void handleGeoPermission(final boolean granted) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (continuation == null) {
                    Log.e(TAG, "handleGeoPermission: WARNING continuation is null");
                    return;
                }

                try {
                    if (granted) {
                        globalBaseRequest.setHandled(true);
                        ((HttpServletResponse) continuation.getServletResponse()).setStatus(204);

                    } else {
                        try {
                            Log.e(TAG, "handleGeoPermission: granted is false");
                            globalBaseRequest.setHandled(true);
                            ((HttpServletResponse) continuation.getServletResponse()).sendError(400);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                } finally {
                    continuation.complete();
                    continuation = null;
                    globalBaseRequest = null;
                }
            }
        }).start();

    }

    @Override
    public boolean handle(String target, Request baseRequest, HttpServletRequest request,
            HttpServletResponse response) {
        if (target.startsWith("/_permissions/geo")) {
            Log.i(TAG, "handling: " + target + " " + baseRequest.getMethod());
            MainActivity app = MainActivity.app;
            if (app == null) {
                Log.e(TAG, "handle: context is null: " + target + " " + baseRequest.getMethod());
                return BRHTTPHelper.handleError(500, "context is null", baseRequest, response);
            }
            switch (request.getMethod()) {
            // GET /_permissions/geo
            //
            // Call this method to retrieve the current permission status for geolocation.
            // The returned JSON dictionary contains the following keys:
            //
            // "status" = "denied" | "restricted | "undetermined" | "inuse" | "always"
            // "user_queried" = true | false
            // "location_enabled" = true | false
            //
            // The status correspond to those found in the apple CLLocation documentation: http://apple.co/1O0lHFv
            //
            // "user_queried" indicates whether or not the user has already been asked for geolocation
            // "location_enabled" indicates whether or not the user has geo location enabled on their phone
            case "GET":
                JSONObject jsonResult = new JSONObject();
                String status;
                boolean enabled;
                boolean permRequested = SharedPreferencesManager.getGeoPermissionsRequested(app);
                int permissionCheck = ContextCompat.checkSelfPermission(app,
                        Manifest.permission.ACCESS_FINE_LOCATION);
                if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                    status = "always";
                    enabled = true;
                } else {
                    Log.e(TAG, "handle: sending permission denied: " + target + " " + baseRequest.getMethod());
                    status = permRequested ? "denied" : "undetermined";
                    enabled = false;
                }
                try {
                    jsonResult.put("status", status);
                    jsonResult.put("user_queried", permRequested);
                    jsonResult.put("location_enabled", enabled);
                    return BRHTTPHelper.handleSuccess(200, jsonResult.toString().getBytes(), baseRequest, response,
                            null);
                } catch (JSONException e) {
                    e.printStackTrace();
                    Log.e(TAG,
                            "handle: failed to send permission status: " + target + " " + baseRequest.getMethod());
                    return BRHTTPHelper.handleError(500, null, baseRequest, response);
                }
                // POST /_permissions/geo
                //
                // Call this method to request the geo permission from the user.
                // The request body should be a JSON dictionary containing a single key, "style"
                // the value of which should be either "inuse" or "always" - these correspond to the
                // two ways the user can authorize geo access to the app. "inuse" will request
                // geo availability to the app when the app is foregrounded, and "always" will request
                // full time geo availability to the app
            case "POST":
                if (ContextCompat.checkSelfPermission(app,
                        Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    Log.e(TAG, "handle: requesting permissions: " + target + " " + baseRequest.getMethod());
                    ActivityCompat.requestPermissions(app,
                            new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, BRConstants.GEO_REQUEST_ID);
                }
                SharedPreferencesManager.putGeoPermissionsRequested(app, true);
                continuation = ContinuationSupport.getContinuation(request);
                continuation.suspend(response);
                globalBaseRequest = baseRequest;
                return true;

            }
        } else if (target.startsWith("/_geo") && !target.startsWith("/_geosocket")) {
            Log.i(TAG, "handling: " + target + " " + baseRequest.getMethod());
            // GET /_geo
            //
            // Calling this method will query CoreLocation for a location object. The returned value may not be returned
            // very quick (sometimes getting a geo lock takes some time) so be sure to display to the user some status
            // while waiting for a response.
            //
            // Response Object:
            //
            // "coordinates" = { "latitude": double, "longitude": double }
            // "altitude" = double
            // "description" = "a string representation of this object"
            // "timestamp" = "ISO-8601 timestamp of when this location was generated"
            // "horizontal_accuracy" = double
            MainActivity app = MainActivity.app;
            if (app == null) {
                Log.e(TAG, "handle: context is null: " + target + " " + baseRequest.getMethod());
                return BRHTTPHelper.handleError(500, "context is null", baseRequest, response);
            }

            if (request.getMethod().equalsIgnoreCase("GET")) {
                JSONObject obj = getAuthorizationError(app);
                if (obj != null) {
                    Log.e(TAG, "handle: error getting location: " + obj.toString() + ", " + target + " "
                            + baseRequest.getMethod());
                    return BRHTTPHelper.handleError(500, obj.toString(), baseRequest, response);
                }

                continuation = ContinuationSupport.getContinuation(request);
                continuation.suspend(response);
                GeoLocationManager.getInstance().getOneTimeGeoLocation(continuation, baseRequest);
                return true;
            }
        } else if (target.startsWith("/_geosocket")) {
            Log.i(TAG, "handling: " + target + " " + baseRequest.getMethod());
            // GET /_geosocket
            //
            // This opens up a websocket to the location manager. It will return a new location every so often (but with no
            // predetermined interval) with the same exact structure that is sent via the GET /_geo call.
            //
            // It will start the location manager when there is at least one client connected and stop the location manager
            // when the last client disconnects.

            return true;
        }

        return false;
    }

    private JSONObject getAuthorizationError(Context app) {
        String error = null;

        LocationManager lm = (LocationManager) app.getSystemService(Context.LOCATION_SERVICE);
        boolean gps_enabled = false;
        boolean network_enabled = false;

        try {
            gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch (Exception ignored) {
        }

        try {
            network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch (Exception ignored) {
        }
        if (!gps_enabled && !network_enabled) {
            error = "Location services are disabled";
        }
        int permissionCheck = ContextCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION);
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            error = "Location services are not authorized";
        }

        if (error != null) {
            JSONObject obj = new JSONObject();
            try {
                obj.put("error", error);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return obj;
        } else {
            return null;
        }

    }

}