Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0682809a authored by destradaa's avatar destradaa
Browse files

Add support in the platform for Flp Geofencing.

Change-Id: I0fb0e276d3a06322697bb5d46323779aca1f78c5
parent f464511a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -355,6 +355,7 @@ aidl_files := \
	frameworks/base/core/java/android/content/SyncStats.aidl \
	frameworks/base/core/java/android/content/res/Configuration.aidl \
	frameworks/base/core/java/android/database/CursorWindow.aidl \
	frameworks/base/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl \
	frameworks/base/core/java/android/net/Uri.aidl \
	frameworks/base/core/java/android/nfc/NdefMessage.aidl \
	frameworks/base/core/java/android/nfc/NdefRecord.aidl \
+14 −8
Original line number Diff line number Diff line
@@ -15,16 +15,11 @@
 */
package android.hardware.location;

import android.content.Context;
import android.location.Location;
import android.os.RemoteException;
import android.util.Log;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * This class handles geofences managed by various hardware subsystems. It contains
@@ -52,13 +47,20 @@ public final class GeofenceHardware {
    private IGeofenceHardware mService;

    // Hardware systems that do geofence monitoring.
    static final int NUM_MONITORS = 1;
    static final int NUM_MONITORS = 2;

    /**
     * Constant for geofence monitoring done by the GPS hardware.
     */
    public static final int MONITORING_TYPE_GPS_HARDWARE = 0;

    /**
     * Constant for geofence monitoring done by the Fused hardware.
     *
     * @hide
     */
    public static final int MONITORING_TYPE_FUSED_HARDWARE = 1;

    /**
     * Constant to indiciate that the monitoring system is currently
     * available for monitoring geofences.
@@ -124,8 +126,12 @@ public final class GeofenceHardware {
     */
    public static final int GEOFENCE_FAILURE = 5;

    static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
    static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
    /**
     * The constant used to indicate that the operation failed due to insufficient memory.
     *
     * @hide
     */
    public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6;

    private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
            mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
+206 −139
Original line number Diff line number Diff line
@@ -18,23 +18,21 @@ package android.hardware.location;

import android.content.Context;
import android.content.pm.PackageManager;
import android.location.FusedBatchOptions;
import android.location.IFusedGeofenceHardware;
import android.location.IGpsGeofenceHardware;
import android.location.Location;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * This class manages the geofences which are handled by hardware.
@@ -54,6 +52,7 @@ public final class GeofenceHardwareImpl {
            new ArrayList[GeofenceHardware.NUM_MONITORS];
    private final ArrayList<Reaper> mReapers = new ArrayList<Reaper>();

    private IFusedGeofenceHardware mFusedService;
    private IGpsGeofenceHardware mGpsService;

    private int[] mSupportedMonitorTypes = new int[GeofenceHardware.NUM_MONITORS];
@@ -67,7 +66,7 @@ public final class GeofenceHardwareImpl {
    private static final int GEOFENCE_CALLBACK_BINDER_DIED = 6;

    // mCallbacksHandler message types
    private static final int GPS_GEOFENCE_STATUS = 1;
    private static final int GEOFENCE_STATUS = 1;
    private static final int CALLBACK_ADD = 2;
    private static final int CALLBACK_REMOVE = 3;
    private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
@@ -91,16 +90,6 @@ public final class GeofenceHardwareImpl {
    private static final int RESOLUTION_LEVEL_COARSE = 2;
    private static final int RESOLUTION_LEVEL_FINE = 3;

    // GPS Geofence errors. Should match gps.h constants.
    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;



    public synchronized static GeofenceHardwareImpl getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new GeofenceHardwareImpl(context);
@@ -113,6 +102,9 @@ public final class GeofenceHardwareImpl {
        // Init everything to unsupported.
        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
                GeofenceHardware.MONITOR_UNSUPPORTED);
        setMonitorAvailability(
                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
                GeofenceHardware.MONITOR_UNSUPPORTED);

    }

@@ -147,6 +139,22 @@ public final class GeofenceHardwareImpl {
        }
    }

    private void updateFusedHardwareAvailability() {
        boolean fusedSupported;
        try {
            fusedSupported = mFusedService.isSupported();
        } catch(RemoteException e) {
            Log.e(TAG, "RemoteException calling LocationManagerService");
            fusedSupported = false;
        }

        if(fusedSupported) {
            setMonitorAvailability(
                    GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
                    GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE);
        }
    }

    public void setGpsHardwareGeofence(IGpsGeofenceHardware service) {
        if (mGpsService == null) {
            mGpsService = service;
@@ -159,12 +167,39 @@ public final class GeofenceHardwareImpl {
        }
    }

    public void setFusedGeofenceHardware(IFusedGeofenceHardware service) {
        if(mFusedService == null) {
            mFusedService = service;
            updateFusedHardwareAvailability();
        } else if(service == null) {
            mFusedService = null;
            Log.w(TAG, "Fused Geofence Hardware service seems to have crashed");
        } else {
            Log.e(TAG, "Error: FusedService being set again");
        }
    }

    public int[] getMonitoringTypes() {
        boolean gpsSupported;
        boolean fusedSupported;
        synchronized (mSupportedMonitorTypes) {
            if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
                        GeofenceHardware.MONITOR_UNSUPPORTED) {
            gpsSupported = mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE]
                    != GeofenceHardware.MONITOR_UNSUPPORTED;
            fusedSupported = mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE]
                    != GeofenceHardware.MONITOR_UNSUPPORTED;
        }

        if(gpsSupported) {
            if(fusedSupported) {
                return new int[] {
                        GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
                        GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE };
            } else {
                return new int[] { GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE };
            }
        } else if (fusedSupported) {
            return new int[] { GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE };
        } else {
            return new int[0];
        }
    }
@@ -213,6 +248,30 @@ public final class GeofenceHardwareImpl {
                    result = false;
                }
                break;
            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
                if(mFusedService == null) {
                    return false;
                }
                GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence(
                        latitude,
                        longitude,
                        radius);
                request.setUnknownTimer(unknownTimer);
                request.setNotificationResponsiveness(notificationResponsivenes);
                request.setMonitorTransitions(monitorTransitions);
                request.setLastTransition(lastTransition);

                GeofenceHardwareRequestParcelable parcelableRequest =
                        new GeofenceHardwareRequestParcelable(geofenceId, request);
                try {
                    mFusedService.addGeofences(
                            new GeofenceHardwareRequestParcelable[] { parcelableRequest });
                    result = true;
                } catch(RemoteException e) {
                    Log.e(TAG, "AddGeofence: RemoteException calling LocationManagerService");
                    result = false;
                }
                break;
            default:
                result = false;
        }
@@ -251,6 +310,18 @@ public final class GeofenceHardwareImpl {
                    result = false;
                }
                break;
            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
                if(mFusedService == null) {
                    return false;
                }
                try {
                    mFusedService.removeGeofences(new int[] { geofenceId });
                    result = true;
                } catch(RemoteException e) {
                    Log.e(TAG, "RemoveGeofence: RemoteException calling LocationManagerService");
                    result = false;
                }
                break;
            default:
                result = false;
        }
@@ -278,6 +349,18 @@ public final class GeofenceHardwareImpl {
                    result = false;
                }
                break;
            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
                if(mFusedService == null) {
                    return false;
                }
                try {
                    mFusedService.pauseMonitoringGeofence(geofenceId);
                    result = true;
                } catch(RemoteException e) {
                    Log.e(TAG, "PauseGeofence: RemoteException calling LocationManagerService");
                    result = false;
                }
                break;
            default:
                result = false;
        }
@@ -306,6 +389,18 @@ public final class GeofenceHardwareImpl {
                    result = false;
                }
                break;
            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
                if(mFusedService == null) {
                    return false;
                }
                try {
                    mFusedService.resumeMonitoringGeofence(geofenceId, monitorTransition);
                    result = true;
                } catch(RemoteException e) {
                    Log.e(TAG, "ResumeGeofence: RemoteException calling LocationManagerService");
                    result = false;
                }
                break;
            default:
                result = false;
        }
@@ -334,127 +429,106 @@ public final class GeofenceHardwareImpl {
        return true;
    }

    private Location getLocation(int flags, double latitude,
            double longitude, double altitude, float speed, float bearing, float accuracy,
            long timestamp) {
        if (DEBUG) Log.d(TAG, "GetLocation: " + flags + ":" + latitude);
        Location location = new Location(LocationManager.GPS_PROVIDER);
        if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
            location.setLatitude(latitude);
            location.setLongitude(longitude);
            location.setTime(timestamp);
            // It would be nice to push the elapsed real-time timestamp
            // further down the stack, but this is still useful
            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
        }
        if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
            location.setAltitude(altitude);
        } else {
            location.removeAltitude();
        }
        if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
            location.setSpeed(speed);
        } else {
            location.removeSpeed();
        }
        if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
            location.setBearing(bearing);
        } else {
            location.removeBearing();
        }
        if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
            location.setAccuracy(accuracy);
        } else {
            location.removeAccuracy();
    /**
     * Used to report geofence transitions
     */
    public void reportGeofenceTransition(
            int geofenceId,
            Location location,
            int transition,
            long transitionTimestamp,
            int monitoringType,
            int sourcesUsed) {
        if(location == null) {
            Log.e(TAG, String.format("Invalid Geofence Transition: location=%p", location));
            return;
        }
        return location;
        if(DEBUG) {
            Log.d(
                    TAG,
                    "GeofenceTransition| " + location + ", transition:" + transition +
                    ", transitionTimestamp:" + transitionTimestamp + ", monitoringType:" +
                    monitoringType + ", sourcesUsed:" + sourcesUsed);
        }

        GeofenceTransition geofenceTransition = new GeofenceTransition(
                geofenceId,
                transition,
                transitionTimestamp,
                location,
                monitoringType,
                sourcesUsed);
        acquireWakeLock();

        Message message = mGeofenceHandler.obtainMessage(
                GEOFENCE_TRANSITION_CALLBACK,
                geofenceTransition);
        message.sendToTarget();
    }

    /**
     * called from GpsLocationProvider to report geofence transition
     * Used to report Monitor status changes.
     */
    public void reportGpsGeofenceTransition(int geofenceId, int flags, double latitude,
            double longitude, double altitude, float speed, float bearing, float accuracy,
            long timestamp, int transition, long transitionTimestamp) {
        if (DEBUG) Log.d(TAG, "GeofenceTransition: Flags: " + flags + " Lat: " + latitude +
            " Long: " + longitude + " Altitude: " + altitude + " Speed: " + speed + " Bearing: " +
            bearing + " Accuracy: " + accuracy + " Timestamp: " + timestamp + " Transition: " +
            transition + " TransitionTimestamp: " + transitionTimestamp);
        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
                accuracy, timestamp);
        GeofenceTransition t = new GeofenceTransition(geofenceId, transition, timestamp, location);
    public void reportGeofenceMonitorStatus(
            int monitoringType,
            int monitoringStatus,
            Location location,
            int source) {
        // TODO: use the source if needed in the future
        setMonitorAvailability(monitoringType, monitoringStatus);
        acquireWakeLock();
        Message m = mGeofenceHandler.obtainMessage(GEOFENCE_TRANSITION_CALLBACK, t);
        mGeofenceHandler.sendMessage(m);
        Message message = mCallbacksHandler.obtainMessage(GEOFENCE_STATUS, location);
        message.arg1 = monitoringStatus;
        message.arg2 = monitoringType;
        message.sendToTarget();
    }

    /**
     * called from GpsLocationProvider to report GPS status change.
     * Internal generic status report function for Geofence operations.
     *
     * @param operation The operation to be reported as defined internally.
     * @param geofenceId The id of the geofence the operation is related to.
     * @param operationStatus The status of the operation as defined in GeofenceHardware class. This
     *                        status is independent of the statuses reported by different HALs.
     */
    public void reportGpsGeofenceStatus(int status, int flags, double latitude,
            double longitude, double altitude, float speed, float bearing, float accuracy,
            long timestamp) {
        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
                accuracy, timestamp);
        boolean available = false;
        if (status == GeofenceHardware.GPS_GEOFENCE_AVAILABLE) available = true;

        int val = (available ? GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE :
                GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE);
        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, val);

    private void reportGeofenceOperationStatus(int operation, int geofenceId, int operationStatus) {
        acquireWakeLock();
        Message m = mCallbacksHandler.obtainMessage(GPS_GEOFENCE_STATUS, location);
        m.arg1 = val;
        mCallbacksHandler.sendMessage(m);
        Message message = mGeofenceHandler.obtainMessage(operation);
        message.arg1 = geofenceId;
        message.arg2 = operationStatus;
        message.sendToTarget();
    }

    /**
     * called from GpsLocationProvider add geofence callback.
     * Used to report the status of a Geofence Add operation.
     */
    public void reportGpsGeofenceAddStatus(int geofenceId, int status) {
        if (DEBUG) Log.d(TAG, "Add Callback: GPS : Id: " + geofenceId + " Status: " + status);
        acquireWakeLock();
        Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE_CALLBACK);
        m.arg1 = geofenceId;
        m.arg2 = getGeofenceStatus(status);
        mGeofenceHandler.sendMessage(m);
    public void reportGeofenceAddStatus(int geofenceId, int status) {
        if(DEBUG) Log.d(TAG, "AddCallback| id:" + geofenceId + ", status:" + status);
        reportGeofenceOperationStatus(ADD_GEOFENCE_CALLBACK, geofenceId, status);
    }

    /**
     * called from GpsLocationProvider remove geofence callback.
     * Used to report the status of a Geofence Remove operation.
     */
    public void reportGpsGeofenceRemoveStatus(int geofenceId, int status) {
        if (DEBUG) Log.d(TAG, "Remove Callback: GPS : Id: " + geofenceId + " Status: " + status);
        acquireWakeLock();
        Message m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE_CALLBACK);
        m.arg1 = geofenceId;
        m.arg2 = getGeofenceStatus(status);
        mGeofenceHandler.sendMessage(m);
    public void reportGeofenceRemoveStatus(int geofenceId, int status) {
        if(DEBUG) Log.d(TAG, "RemoveCallback| id:" + geofenceId + ", status:" + status);
        reportGeofenceOperationStatus(REMOVE_GEOFENCE_CALLBACK, geofenceId, status);
    }

    /**
     * called from GpsLocationProvider pause geofence callback.
     * Used to report the status of a Geofence Pause operation.
     */
    public void reportGpsGeofencePauseStatus(int geofenceId, int status) {
        if (DEBUG) Log.d(TAG, "Pause Callback: GPS : Id: " + geofenceId + " Status: " + status);
        acquireWakeLock();
        Message m = mGeofenceHandler.obtainMessage(PAUSE_GEOFENCE_CALLBACK);
        m.arg1 = geofenceId;
        m.arg2 = getGeofenceStatus(status);
        mGeofenceHandler.sendMessage(m);
    public void reportGeofencePauseStatus(int geofenceId, int status) {
        if(DEBUG) Log.d(TAG, "PauseCallbac| id:" + geofenceId + ", status" + status);
        reportGeofenceOperationStatus(PAUSE_GEOFENCE_CALLBACK, geofenceId, status);
    }

    /**
     * called from GpsLocationProvider resume geofence callback.
     * Used to report the status of a Geofence Resume operation.
     */
    public void reportGpsGeofenceResumeStatus(int geofenceId, int status) {
        if (DEBUG) Log.d(TAG, "Resume Callback: GPS : Id: " + geofenceId + " Status: " + status);
        acquireWakeLock();
        Message m = mGeofenceHandler.obtainMessage(RESUME_GEOFENCE_CALLBACK);
        m.arg1 = geofenceId;
        m.arg2 = getGeofenceStatus(status);
        mGeofenceHandler.sendMessage(m);
    public void reportGeofenceResumeStatus(int geofenceId, int status) {
        if(DEBUG) Log.d(TAG, "ResumeCallback| id:" + geofenceId + ", status:" + status);
        reportGeofenceOperationStatus(RESUME_GEOFENCE_CALLBACK, geofenceId, status);
    }

    // All operations on mGeofences
@@ -539,7 +613,7 @@ public final class GeofenceHardwareImpl {
                            callback.onGeofenceTransition(
                                    geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
                                    geofenceTransition.mLocation, geofenceTransition.mTimestamp,
                                    GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
                                    geofenceTransition.mMonitoringType);
                        } catch (RemoteException e) {}
                    }
                    releaseWakeLock();
@@ -571,21 +645,20 @@ public final class GeofenceHardwareImpl {
            IGeofenceHardwareMonitorCallback callback;

            switch (msg.what) {
                case GPS_GEOFENCE_STATUS:
                case GEOFENCE_STATUS:
                    Location location = (Location) msg.obj;
                    int val = msg.arg1;
                    monitoringType = msg.arg2;
                    boolean available;
                    available = (val == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE ?
                            true : false);
                    callbackList = mCallbacks[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE];
                    callbackList = mCallbacks[monitoringType];
                    if (callbackList != null) {
                        if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);

                        for (IGeofenceHardwareMonitorCallback c: callbackList) {
                            try {
                                c.onMonitoringSystemChange(
                                        GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
                                        location);
                                c.onMonitoringSystemChange(monitoringType, available, location);
                            } catch (RemoteException e) {}
                        }
                    }
@@ -666,12 +739,22 @@ public final class GeofenceHardwareImpl {
        private int mGeofenceId, mTransition;
        private long mTimestamp;
        private Location mLocation;

        GeofenceTransition(int geofenceId, int transition, long timestamp, Location location) {
        private int mMonitoringType;
        private int mSourcesUsed;

        GeofenceTransition(
                int geofenceId,
                int transition,
                long timestamp,
                Location location,
                int monitoringType,
                int sourcesUsed) {
            mGeofenceId = geofenceId;
            mTransition = transition;
            mTimestamp = timestamp;
            mLocation = location;
            mMonitoringType = monitoringType;
            mSourcesUsed = sourcesUsed;
        }
    }

@@ -686,6 +769,8 @@ public final class GeofenceHardwareImpl {
        switch (monitoringType) {
            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
                return RESOLUTION_LEVEL_FINE;
            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
                return RESOLUTION_LEVEL_FINE;
        }
        return RESOLUTION_LEVEL_NONE;
    }
@@ -752,22 +837,4 @@ public final class GeofenceHardwareImpl {
            return RESOLUTION_LEVEL_NONE;
        }
    }

    private int getGeofenceStatus(int status) {
        switch (status) {
            case GPS_GEOFENCE_OPERATION_SUCCESS:
                return GeofenceHardware.GEOFENCE_SUCCESS;
            case GPS_GEOFENCE_ERROR_GENERIC:
                return GeofenceHardware.GEOFENCE_FAILURE;
            case GPS_GEOFENCE_ERROR_ID_EXISTS:
                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
        }
        return -1;
    }
}
+19 −0
Original line number Diff line number Diff line
/*
 * 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 android.hardware.location;

parcelable GeofenceHardwareRequestParcelable;
Loading