FileDocCategorySizeDatePackage
GeofenceHardwareImpl.javaAPI DocAndroid 5.1 API36228Thu Mar 12 22:22:10 GMT 2015android.hardware.location

GeofenceHardwareImpl

public final class GeofenceHardwareImpl extends Object
This class manages the geofences which are handled by hardware.
hide

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private final android.content.Context
mContext
private static GeofenceHardwareImpl
sInstance
private PowerManager.WakeLock
mWakeLock
private final android.util.SparseArray
mGeofences
private final ArrayList[]
mCallbacks
private final ArrayList
mReapers
private android.location.IFusedGeofenceHardware
mFusedService
private android.location.IGpsGeofenceHardware
mGpsService
private int[]
mSupportedMonitorTypes
private static final int
GEOFENCE_TRANSITION_CALLBACK
private static final int
ADD_GEOFENCE_CALLBACK
private static final int
REMOVE_GEOFENCE_CALLBACK
private static final int
PAUSE_GEOFENCE_CALLBACK
private static final int
RESUME_GEOFENCE_CALLBACK
private static final int
GEOFENCE_CALLBACK_BINDER_DIED
private static final int
GEOFENCE_STATUS
private static final int
CALLBACK_ADD
private static final int
CALLBACK_REMOVE
private static final int
MONITOR_CALLBACK_BINDER_DIED
private static final int
REAPER_GEOFENCE_ADDED
private static final int
REAPER_MONITOR_CALLBACK_ADDED
private static final int
REAPER_REMOVED
private static final int
LOCATION_INVALID
private static final int
LOCATION_HAS_LAT_LONG
private static final int
LOCATION_HAS_ALTITUDE
private static final int
LOCATION_HAS_SPEED
private static final int
LOCATION_HAS_BEARING
private static final int
LOCATION_HAS_ACCURACY
private static final int
RESOLUTION_LEVEL_NONE
private static final int
RESOLUTION_LEVEL_COARSE
private static final int
RESOLUTION_LEVEL_FINE
private android.os.Handler
mGeofenceHandler
private android.os.Handler
mCallbacksHandler
private android.os.Handler
mReaperHandler
Constructors Summary
private GeofenceHardwareImpl(android.content.Context context)

        mContext = context;
        // Init everything to unsupported.
        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
                GeofenceHardware.MONITOR_UNSUPPORTED);
        setMonitorAvailability(
                GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
                GeofenceHardware.MONITOR_UNSUPPORTED);

    
Methods Summary
private voidacquireWakeLock()

        if (mWakeLock == null) {
            PowerManager powerManager =
                    (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
            mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
        }
        mWakeLock.acquire();
    
public booleanaddCircularFence(int monitoringType, GeofenceHardwareRequestParcelable request, IGeofenceHardwareCallback callback)

        int geofenceId = request.getId();

        // This API is not thread safe. Operations on the same geofence need to be serialized
        // by upper layers
        if (DEBUG) {
            String message = String.format(
                    "addCircularFence: monitoringType=%d, %s",
                    monitoringType,
                    request);
            Log.d(TAG, message);
        }
        boolean result;

        // The callback must be added before addCircularHardwareGeofence is called otherwise the
        // callback might not be called after the geofence is added in the geofence hardware.
        // This also means that the callback must be removed if the addCircularHardwareGeofence
        // operations is not called or fails.
        synchronized (mGeofences) {
            mGeofences.put(geofenceId, callback);
        }

        switch (monitoringType) {
            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
                if (mGpsService == null) return false;
                try {
                    result = mGpsService.addCircularHardwareGeofence(
                            request.getId(),
                            request.getLatitude(),
                            request.getLongitude(),
                            request.getRadius(),
                            request.getLastTransition(),
                            request.getMonitorTransitions(),
                            request.getNotificationResponsiveness(),
                            request.getUnknownTimer());
                } catch (RemoteException e) {
                    Log.e(TAG, "AddGeofence: Remote Exception calling LocationManagerService");
                    result = false;
                }
                break;
            case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
                if(mFusedService == null) {
                    return false;
                }
                try {
                    mFusedService.addGeofences(
                            new GeofenceHardwareRequestParcelable[] { request });
                    result = true;
                } catch(RemoteException e) {
                    Log.e(TAG, "AddGeofence: RemoteException calling LocationManagerService");
                    result = false;
                }
                break;
            default:
                result = false;
        }
        if (result) {
            Message m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
            m.arg1 = monitoringType;
            mReaperHandler.sendMessage(m);
        } else {
            synchronized (mGeofences) {
                mGeofences.remove(geofenceId);
            }
        }

        if (DEBUG) Log.d(TAG, "addCircularFence: Result is: " + result);
        return result;
    
intgetAllowedResolutionLevel(int pid, int uid)

        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                pid, uid) == PackageManager.PERMISSION_GRANTED) {
            return RESOLUTION_LEVEL_FINE;
        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
                pid, uid) == PackageManager.PERMISSION_GRANTED) {
            return RESOLUTION_LEVEL_COARSE;
        } else {
            return RESOLUTION_LEVEL_NONE;
        }
    
public static synchronized android.hardware.location.GeofenceHardwareImplgetInstance(android.content.Context context)


          
        if (sInstance == null) {
            sInstance = new GeofenceHardwareImpl(context);
        }
        return sInstance;
    
intgetMonitoringResolutionLevel(int monitoringType)

        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;
    
public int[]getMonitoringTypes()

        boolean gpsSupported;
        boolean fusedSupported;
        synchronized (mSupportedMonitorTypes) {
            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];
        }
    
public intgetStatusOfMonitoringType(int monitoringType)

        synchronized (mSupportedMonitorTypes) {
            if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) {
                throw new IllegalArgumentException("Unknown monitoring type");
            }
            return mSupportedMonitorTypes[monitoringType];
        }
    
public booleanpauseGeofence(int geofenceId, int monitoringType)

        // This API is not thread safe. Operations on the same geofence need to be serialized
        // by upper layers
        if (DEBUG) Log.d(TAG, "Pause Geofence: GeofenceId: " + geofenceId);
        boolean result;
        synchronized (mGeofences) {
            if (mGeofences.get(geofenceId) == null) {
                throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
            }
        }
        switch (monitoringType) {
            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
                if (mGpsService == null) return false;
                try {
                    result = mGpsService.pauseHardwareGeofence(geofenceId);
                } catch (RemoteException e) {
                    Log.e(TAG, "PauseGeofence: Remote Exception calling LocationManagerService");
                    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;
        }
        if (DEBUG) Log.d(TAG, "pauseGeofence: Result is: " + result);
        return result;
    
public booleanregisterForMonitorStateChangeCallback(int monitoringType, IGeofenceHardwareMonitorCallback callback)

        Message reaperMessage =
                mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback);
        reaperMessage.arg1 = monitoringType;
        mReaperHandler.sendMessage(reaperMessage);

        Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
        m.arg1 = monitoringType;
        mCallbacksHandler.sendMessage(m);
        return true;
    
private voidreleaseWakeLock()

        if (mWakeLock.isHeld()) mWakeLock.release();
    
public booleanremoveGeofence(int geofenceId, int monitoringType)

        // This API is not thread safe. Operations on the same geofence need to be serialized
        // by upper layers
        if (DEBUG) Log.d(TAG, "Remove Geofence: GeofenceId: " + geofenceId);
        boolean result = false;

        synchronized (mGeofences) {
            if (mGeofences.get(geofenceId) == null) {
                throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
            }
        }
        switch (monitoringType) {
            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
                if (mGpsService == null) return false;
                try {
                    result = mGpsService.removeHardwareGeofence(geofenceId);
                } catch (RemoteException e) {
                    Log.e(TAG, "RemoveGeofence: Remote Exception calling LocationManagerService");
                    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;
        }
        if (DEBUG) Log.d(TAG, "removeGeofence: Result is: " + result);
        return result;
    
public voidreportGeofenceAddStatus(int geofenceId, int status)
Used to report the status of a Geofence Add operation.

        if(DEBUG) Log.d(TAG, "AddCallback| id:" + geofenceId + ", status:" + status);
        reportGeofenceOperationStatus(ADD_GEOFENCE_CALLBACK, geofenceId, status);
    
public voidreportGeofenceMonitorStatus(int monitoringType, int monitoringStatus, android.location.Location location, int source)
Used to report Monitor status changes.

        setMonitorAvailability(monitoringType, monitoringStatus);
        acquireWakeLock();
        GeofenceHardwareMonitorEvent event = new GeofenceHardwareMonitorEvent(
                monitoringType,
                monitoringStatus,
                source,
                location);
        Message message = mCallbacksHandler.obtainMessage(GEOFENCE_STATUS, event);
        message.sendToTarget();
    
private voidreportGeofenceOperationStatus(int operation, int geofenceId, int operationStatus)
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.

        acquireWakeLock();
        Message message = mGeofenceHandler.obtainMessage(operation);
        message.arg1 = geofenceId;
        message.arg2 = operationStatus;
        message.sendToTarget();
    
public voidreportGeofencePauseStatus(int geofenceId, int status)
Used to report the status of a Geofence Pause operation.

        if(DEBUG) Log.d(TAG, "PauseCallbac| id:" + geofenceId + ", status" + status);
        reportGeofenceOperationStatus(PAUSE_GEOFENCE_CALLBACK, geofenceId, status);
    
public voidreportGeofenceRemoveStatus(int geofenceId, int status)
Used to report the status of a Geofence Remove operation.

        if(DEBUG) Log.d(TAG, "RemoveCallback| id:" + geofenceId + ", status:" + status);
        reportGeofenceOperationStatus(REMOVE_GEOFENCE_CALLBACK, geofenceId, status);
    
public voidreportGeofenceResumeStatus(int geofenceId, int status)
Used to report the status of a Geofence Resume operation.

        if(DEBUG) Log.d(TAG, "ResumeCallback| id:" + geofenceId + ", status:" + status);
        reportGeofenceOperationStatus(RESUME_GEOFENCE_CALLBACK, geofenceId, status);
    
public voidreportGeofenceTransition(int geofenceId, android.location.Location location, int transition, long transitionTimestamp, int monitoringType, int sourcesUsed)
Used to report geofence transitions

        if(location == null) {
            Log.e(TAG, String.format("Invalid Geofence Transition: location=%p", location));
            return;
        }
        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();
    
public booleanresumeGeofence(int geofenceId, int monitoringType, int monitorTransition)

        // This API is not thread safe. Operations on the same geofence need to be serialized
        // by upper layers
        if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
        boolean result;
        synchronized (mGeofences) {
            if (mGeofences.get(geofenceId) == null) {
                throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
            }
        }
        switch (monitoringType) {
            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
                if (mGpsService == null) return false;
                try {
                    result = mGpsService.resumeHardwareGeofence(geofenceId, monitorTransition);
                } catch (RemoteException e) {
                    Log.e(TAG, "ResumeGeofence: Remote Exception calling LocationManagerService");
                    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;
        }
        if (DEBUG) Log.d(TAG, "resumeGeofence: Result is: " + result);
        return result;
    
public voidsetFusedGeofenceHardware(android.location.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 voidsetGpsHardwareGeofence(android.location.IGpsGeofenceHardware service)

        if (mGpsService == null) {
            mGpsService = service;
            updateGpsHardwareAvailability();
        } else if (service == null) {
            mGpsService = null;
            Log.w(TAG, "GPS Geofence Hardware service seems to have crashed");
        } else {
            Log.e(TAG, "Error: GpsService being set again.");
        }
    
private voidsetMonitorAvailability(int monitor, int val)

        synchronized (mSupportedMonitorTypes) {
            mSupportedMonitorTypes[monitor] = val;
        }
    
public booleanunregisterForMonitorStateChangeCallback(int monitoringType, IGeofenceHardwareMonitorCallback callback)

        Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
        m.arg1 = monitoringType;
        mCallbacksHandler.sendMessage(m);
        return true;
    
private voidupdateFusedHardwareAvailability()

        boolean fusedSupported;
        try {
            fusedSupported = (mFusedService != null ? mFusedService.isSupported() : false);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException calling LocationManagerService");
            fusedSupported = false;
        }

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

        //Check which monitors are available.
        boolean gpsSupported;
        try {
            gpsSupported = mGpsService.isHardwareGeofenceSupported();
        } catch (RemoteException e) {
            Log.e(TAG, "Remote Exception calling LocationManagerService");
            gpsSupported = false;
        }

        if (gpsSupported) {
            // Its assumed currently available at startup.
            // native layer will update later.
            setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
                    GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE);
        }