org.deviceconnect.android.deviceplugin.host.profile.HostGeolocationProfile.java Source code

Java tutorial

Introduction

Here is the source code for org.deviceconnect.android.deviceplugin.host.profile.HostGeolocationProfile.java

Source

/*
 HostGeolocationProfile.java
 Copyright (c) 2017 NTT DOCOMO,INC.
 Released under the MIT license
 http://opensource.org/licenses/mit-license.php
 */
package org.deviceconnect.android.deviceplugin.host.profile;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;

import org.deviceconnect.android.activity.PermissionUtility;
import org.deviceconnect.android.deviceplugin.host.activity.GeolocationAlertDialogActivity;
import org.deviceconnect.android.event.Event;
import org.deviceconnect.android.event.EventError;
import org.deviceconnect.android.event.EventManager;
import org.deviceconnect.android.message.MessageUtils;
import org.deviceconnect.android.profile.DConnectProfile;
import org.deviceconnect.android.profile.GeolocationProfile;
import org.deviceconnect.android.profile.api.DConnectApi;
import org.deviceconnect.android.profile.api.DeleteApi;
import org.deviceconnect.android.profile.api.GetApi;
import org.deviceconnect.android.profile.api.PutApi;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.utils.RFC3339DateUtils;

import java.util.List;

import static android.Manifest.permission.ACCESS_COARSE_LOCATION;

/**
 * Geolocation Profile.
 * @author NTT DOCOMO, INC.
 */
public class HostGeolocationProfile extends GeolocationProfile implements LocationListener {
    /** LocationManager. */
    private LocationManager mLocationManager;

    /** ServiceID. */
    private String mServiceId;

    /** ???????. */
    private long mLocationLastTime;

    /** ??????. */
    private Bundle mLocationCache;

    /**
     * Constructor.
     */
    public HostGeolocationProfile() {
        DConnectApi mGetOnGeolocationApi = new GetApi() {

            @Override
            public String getAttribute() {
                return ATTRIBUTE_CURRENT_POSITION;
            }

            @Override
            public boolean onRequest(final Intent request, final Intent response) {
                PermissionUtility.requestPermissions(getContext(), new Handler(Looper.getMainLooper()),
                        new String[] { Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION },
                        new PermissionUtility.PermissionRequestCallback() {
                            @Override
                            public void onSuccess() {
                                long maximumAge = (long) getMaximumAge(request);
                                if (System.currentTimeMillis() - mLocationLastTime < maximumAge) {
                                    DConnectProfile.setResult(response, DConnectMessage.RESULT_OK);
                                    response.putExtra(GeolocationProfile.PARAM_POSITION, mLocationCache);
                                    sendResponse(response);
                                } else {
                                    getLocationManager(response);
                                    getGPS(getHighAccuracy(request), response);
                                }
                            }

                            @Override
                            public void onFail(@NonNull String deniedPermission) {
                                MessageUtils.setIllegalDeviceStateError(response,
                                        "ACCESS_FINE_LOCATION permission not granted.");
                                sendResponse(response);
                            }
                        });

                return false;
            }
        };
        addApi(mGetOnGeolocationApi);

        DConnectApi mPutOnGeolocationApi = new PutApi() {

            @Override
            public String getAttribute() {
                return ATTRIBUTE_ON_WATCH_POSITION;
            }

            @Override
            public boolean onRequest(final Intent request, final Intent response) {
                PermissionUtility.requestPermissions(getContext(), new Handler(Looper.getMainLooper()),
                        new String[] { Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION },
                        new PermissionUtility.PermissionRequestCallback() {
                            @Override
                            public void onSuccess() {
                                getLocationManager(response);
                                String serviceId = getServiceID(request);
                                // ?
                                EventError error = EventManager.INSTANCE.addEvent(request);
                                if (error == EventError.NONE) {
                                    startGPS(getHighAccuracy(request), (int) getInterval(request));
                                    mServiceId = serviceId;
                                    DConnectProfile.setResult(response, DConnectMessage.RESULT_OK);
                                    response.putExtra(DConnectMessage.EXTRA_VALUE,
                                            "Register OnWatchPosition event");
                                } else {
                                    MessageUtils.setUnknownError(response, "Can not register event.");
                                }
                                sendResponse(response);
                            }

                            @Override
                            public void onFail(@NonNull String deniedPermission) {
                                MessageUtils.setIllegalDeviceStateError(response,
                                        "ACCESS_FINE_LOCATION permission not granted.");
                                sendResponse(response);
                            }
                        });

                return false;
            }
        };
        addApi(mPutOnGeolocationApi);

        DConnectApi mDeleteOnGeolocationApi = new DeleteApi() {

            @Override
            public String getAttribute() {
                return ATTRIBUTE_ON_WATCH_POSITION;
            }

            @Override
            public boolean onRequest(final Intent request, final Intent response) {
                PermissionUtility.requestPermissions(getContext(), new Handler(Looper.getMainLooper()),
                        new String[] { Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION },
                        new PermissionUtility.PermissionRequestCallback() {
                            @Override
                            public void onSuccess() {
                                getLocationManager(response);
                                // ?
                                EventError error = EventManager.INSTANCE.removeEvent(request);
                                if (error == EventError.NONE) {
                                    stopGPS();
                                    DConnectProfile.setResult(response, DConnectMessage.RESULT_OK);
                                    response.putExtra(DConnectMessage.EXTRA_VALUE,
                                            "Unregister OnWatchPosition event");
                                } else {
                                    MessageUtils.setUnknownError(response, "Can not unregister event.");
                                }
                                sendResponse(response);
                            }

                            @Override
                            public void onFail(@NonNull String deniedPermission) {
                                MessageUtils.setIllegalDeviceStateError(response,
                                        "ACCESS_FINE_LOCATION permission not granted.");
                                sendResponse(response);
                            }
                        });

                return false;
            }
        };
        addApi(mDeleteOnGeolocationApi);
    }

    /**
     * ????.
     * @return ??
     */
    private LocationManager getLocationManager(final Intent response) {
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
        }
        // GPS??.
        if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
                && !mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Intent intent = new Intent(getContext(), GeolocationAlertDialogActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            Bundle bundle = new Bundle();
            bundle.putParcelable("response", response);
            intent.putExtra("Intent", bundle);
            getContext().startActivity(intent);
        }
        return mLocationManager;
    }

    /**
     * ?????.
     * @param accuracy .
     * @param response ?.
     */
    private void getGPS(final boolean accuracy, final Intent response) {
        if (ActivityCompat.checkSelfPermission(getContext(),
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(getContext(),
                        ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            MessageUtils.setIllegalDeviceStateError(response, "ACCESS_FINE_LOCATION permission not granted.");
            sendResponse(response);
            return;
        }

        Criteria criteria = new Criteria();
        if (accuracy) {
            criteria.setAccuracy(Criteria.ACCURACY_FINE);
        } else {
            criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        }

        mLocationManager.requestSingleUpdate(mLocationManager.getBestProvider(criteria, true),
                new LocationListener() {
                    @Override
                    public void onLocationChanged(Location location) {
                        Bundle position = createPositionObject(location);

                        DConnectProfile.setResult(response, DConnectMessage.RESULT_OK);
                        response.putExtra(GeolocationProfile.PARAM_POSITION, position);
                        sendResponse(response);
                    }

                    @Override
                    public void onStatusChanged(String provider, int status, Bundle extras) {
                        // NOP
                    }

                    @Override
                    public void onProviderEnabled(String provider) {
                        // NOP
                    }

                    @Override
                    public void onProviderDisabled(String provider) {
                        // NOP
                    }
                }, Looper.getMainLooper());
    }

    /**
     * ??.
     * @param accuracy .
     * @param interval ?.
     */
    private void startGPS(final boolean accuracy, final int interval) {
        if (ActivityCompat.checkSelfPermission(getContext(),
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(getContext(),
                        ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        Criteria criteria = new Criteria();
        if (accuracy) {
            criteria.setAccuracy(Criteria.ACCURACY_FINE);
        } else {
            criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        }

        mLocationManager.requestLocationUpdates(mLocationManager.getBestProvider(criteria, true), interval, 0, this,
                Looper.getMainLooper());
    }

    /**
     * ???.
     */
    private void stopGPS() {
        if (mLocationManager != null) {
            if (ActivityCompat.checkSelfPermission(getContext(),
                    Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    && ActivityCompat.checkSelfPermission(getContext(),
                            ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            mLocationManager.removeUpdates(this);
        }
    }

    /**
     * ????.
     * @return ???true????false
     */
    private boolean isEmptyEventList() {
        List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, GeolocationProfile.PROFILE_NAME, null,
                GeolocationProfile.ATTRIBUTE_ON_WATCH_POSITION.toLowerCase());
        return events == null || events.size() == 0;
    }

    /**
     * ?.
     * @param location ?
     * @return ?
     */
    private Bundle createPositionObject(final Location location) {
        Bundle coordinates = new Bundle();
        setLatitude(coordinates, location.getLatitude());
        setLongitude(coordinates, location.getLongitude());
        setAltitude(coordinates, location.getAltitude());
        setAccuracy(coordinates, location.getAccuracy());
        setHeading(coordinates, location.getBearing());
        setSpeed(coordinates, location.getSpeed());

        Bundle position = new Bundle();
        setCoordinates(position, coordinates);
        setTimeStamp(position, location.getTime());
        setTimeStampString(position, RFC3339DateUtils.toString(location.getTime()));
        mLocationCache = position;
        mLocationLastTime = location.getTime();

        return position;
    }

    @Override
    public void onLocationChanged(Location location) {
        Bundle position = createPositionObject(location);

        if (isEmptyEventList()) {
            stopGPS();
            return;
        }

        List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, GeolocationProfile.PROFILE_NAME, null,
                GeolocationProfile.ATTRIBUTE_ON_WATCH_POSITION.toLowerCase());

        for (int i = 0; i < events.size(); i++) {
            Event event = events.get(i);
            Intent intent = EventManager.createEventMessage(event);
            intent.putExtra(GeolocationProfile.PARAM_POSITION, position);
            sendEvent(intent, event.getAccessToken());
        }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // NOP
    }

    @Override
    public void onProviderEnabled(String provider) {
        // NOP
    }

    @Override
    public void onProviderDisabled(String provider) {
        // NOP
    }

}