
com.backendless.geo.geofence.GeoFenceMonitoring Maven / Gradle / Ivy
Show all versions of android Show documentation
/*
* ********************************************************************************************************************
*
* BACKENDLESS.COM CONFIDENTIAL
*
* ********************************************************************************************************************
*
* Copyright 2012 BACKENDLESS.COM. All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of Backendless.com and its suppliers,
* if any. The intellectual and technical concepts contained herein are proprietary to Backendless.com and its
* suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret
* or copyright law. Dissemination of this information or reproduction of this material is strictly forbidden
* unless prior written permission is obtained from Backendless.com.
*
* ********************************************************************************************************************
*/
package com.backendless.geo.geofence;
import android.location.Location;
import com.backendless.exceptions.BackendlessException;
import com.backendless.exceptions.ExceptionMessage;
import com.backendless.geo.GeoMath;
import com.backendless.geo.GeoPoint;
import com.backendless.geo.IBackendlessLocationListener;
import com.backendless.geo.LocationTracker;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by baas on 01.04.15.
*/
public class GeoFenceMonitoring implements IBackendlessLocationListener
{
public static String NAME = "GeoFenceMonitoring";
private static ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
private Set onStaySet = Collections.synchronizedSet( new HashSet() );
private transient Map fencesToCallback = Collections.synchronizedMap( new HashMap() );
private Set pointFences = new HashSet();
private Map fenceNamesToFence = Collections.synchronizedMap( new HashMap() );
private Map fenceNamesToCallback = Collections.synchronizedMap( new HashMap() );
private volatile transient Location location;
private static GeoFenceMonitoring instance = null;
public GeoFenceMonitoring()
{
instance = this;
}
// public static class SingletonHolder
// {
// public static final GeoFenceMonitoring HOLDER_INSTANCE = new GeoFenceMonitoring();
// }
public static GeoFenceMonitoring getInstance()
{
if ( instance == null )
{
return new GeoFenceMonitoring();
}
else
{
return instance;
}
// return SingletonHolder.HOLDER_INSTANCE;
}
@Override
public void onLocationChanged( Location location )
{
Set oldFences, newFences, currFence;
synchronized( this )
{
initFencesToCallback();
this.location = location;
oldFences = pointFences;
currFence = findGeoPointsFence( new GeoPoint( location.getLatitude(), location.getLongitude() ), fencesToCallback.keySet() );
newFences = new HashSet( currFence );
newFences.removeAll( oldFences );
oldFences.removeAll( currFence );
callOnEnter( newFences );
callOnStay( newFences );
callOnExit( oldFences );
cancelOnStay( oldFences );
pointFences = currFence;
}
}
@Override
public void onLocationChanged( Location oldLocation, Location newLocation )
{
if( newLocation == null )
{
pointFences.clear();
onStaySet.clear();
return;
}
if( oldLocation.distanceTo( newLocation ) > LocationTracker.ACCEPTABLE_DISTANCE )
{
pointFences.clear();
onStaySet.clear();
}
onLocationChanged( newLocation );
}
private void callOnEnter( Set geoFences )
{
for( GeoFence geoFence : geoFences )
{
fencesToCallback.get( geoFence ).callOnEnter( geoFence, location );
}
}
private void callOnStay( Set geoFences )
{
for( GeoFence geoFence : geoFences )
{
if( geoFence.getOnStayDuration() > 0 )
addOnStay( geoFence );
}
}
private void cancelOnStay( Set geoFences )
{
for( GeoFence geoFence : geoFences )
{
cancelOnStay( geoFence );
}
}
private void callOnExit( Set geoFences )
{
for( GeoFence geoFence : geoFences )
{
fencesToCallback.get( geoFence ).callOnExit( geoFence, location );
}
}
public void addGeoFences( Set geoFences, ICallback callback )
{
if( !fencesToCallback.isEmpty() )
throw new BackendlessException( ExceptionMessage.GEOFENCES_MONITORING );
for( GeoFence geoFence : geoFences )
{
addGeoFence( geoFence, callback );
}
}
public void addGeoFence( GeoFence geoFence, ICallback callback )
{
if( fencesToCallback.containsKey( geoFence ) )
{
return;
}
if( !isDefiniteRect( geoFence.getNwPoint(), geoFence.getSePoint() ) )
{
definiteRect( geoFence );
}
this.fencesToCallback.put( geoFence, callback );
this.fenceNamesToFence.put( geoFence.getGeofenceName(), geoFence );
this.fenceNamesToCallback.put( geoFence.getGeofenceName(), callback );
if( location != null && isPointInFence( new GeoPoint( location.getLatitude(), location.getLongitude() ), geoFence ) )
{
pointFences.add( geoFence );
callback.callOnEnter( geoFence, location );
addOnStay( geoFence );
}
}
public boolean containsGeoFence( String geoFenceName )
{
GeoFence geoFence = new GeoFence( geoFenceName );
return fencesToCallback.containsKey( geoFence );
}
public void removeGeoFence( String geoFenceName )
{
GeoFence removed = new GeoFence( geoFenceName );
if( fencesToCallback.containsKey( removed ) )
{
fencesToCallback.remove( removed );
cancelOnStay( removed );
pointFences.remove( removed );
}
if ( fenceNamesToFence.containsKey( geoFenceName ) )
{
fenceNamesToFence.remove( geoFenceName );
}
if ( fenceNamesToCallback.containsKey( geoFenceName ) )
{
fenceNamesToCallback.remove( geoFenceName );
}
}
public void removeGeoFences()
{
onStaySet.clear();
pointFences.clear();
fencesToCallback.clear();
fenceNamesToFence.clear();
fenceNamesToCallback.clear();
}
public boolean isMonitoring()
{
return !fencesToCallback.isEmpty();
}
// public int countFences()
// {
// return fencesToCallback.size();
// }
private Set findGeoPointsFence( GeoPoint geoPoint, Set geoFences )
{
Set pointFences = new HashSet();
for( GeoFence geoFence : geoFences )
{
if( isPointInFence( geoPoint, geoFence ) )
{
pointFences.add( geoFence );
}
}
return pointFences;
}
private boolean isPointInFence( GeoPoint geoPoint, GeoFence geoFence )
{
if( geoFence.getNwPoint() == null || geoFence.getSePoint() == null )
{
definiteRect( geoFence );
}
if( !GeoMath.isPointInRectangular( geoPoint, geoFence.getNwPoint(), geoFence.getSePoint() ) )
{
return false;
}
if( geoFence.getType() == FenceType.CIRCLE && !GeoMath.isPointInCircle( geoPoint, geoFence.getNodes().get( 0 ), GeoMath.distance( geoFence.getNodes().get( 0 ).getLatitude(), geoFence.getNodes().get( 0 ).getLongitude(), geoFence.getNodes().get( 1 ).getLatitude(), geoFence.getNodes().get( 1 ).getLongitude() ) ) )
{
return false;
}
if( geoFence.getType() == FenceType.SHAPE && !GeoMath.isPointInShape( geoPoint, geoFence.getNodes() ) )
{
return false;
}
return true;
}
private boolean isDefiniteRect( GeoPoint nwPoint, GeoPoint sePoint )
{
return nwPoint != null && sePoint != null;
}
private void definiteRect( GeoFence geoFence )
{
switch( geoFence.getType() )
{
case RECT:
{
GeoPoint nwPoint = geoFence.getNodes().get( 0 );
GeoPoint sePoint = geoFence.getNodes().get( 1 );
geoFence.setNwPoint( nwPoint );
geoFence.setSePoint( sePoint );
break;
}
case CIRCLE:
{
double[] outRect = GeoMath.getOutRectangle( geoFence.getNodes().get( 0 ), geoFence.getNodes().get( 1 ) );
geoFence.setNwPoint( new GeoPoint( outRect[ 0 ], outRect[ 1 ] ) );
geoFence.setSePoint( new GeoPoint( outRect[ 2 ], outRect[ 3 ] ) );
break;
}
case SHAPE:
{
double[] outRect = GeoMath.getOutRectangle( geoFence.getNodes() );
geoFence.setNwPoint( new GeoPoint( outRect[ 0 ], outRect[ 1 ] ) );
geoFence.setSePoint( new GeoPoint( outRect[ 2 ], outRect[ 3 ] ) );
break;
}
default:
}
}
private void addOnStay( final GeoFence geoFence )
{
onStaySet.add( geoFence );
scheduledExecutorService.schedule( new Runnable()
{
@Override
public void run()
{
if( onStaySet.contains( geoFence ) )
{
fencesToCallback.get( geoFence ).callOnStay( geoFence, location );
cancelOnStay( geoFence );
}
}
}, geoFence.getOnStayDuration(), TimeUnit.SECONDS );
}
private void cancelOnStay( GeoFence geoFence )
{
onStaySet.remove( geoFence );
}
public Set getOnStaySet()
{
return onStaySet;
}
public void setOnStaySet( Set onStaySet )
{
this.onStaySet = onStaySet;
}
public Set getPointFences() {
return pointFences;
}
public void setPointFences( Set pointFences )
{
this.pointFences = pointFences;
}
public Map getFenceNamesToFence()
{
return fenceNamesToFence;
}
public void setFenceNamesToFence( Map fenceNamesToFence )
{
this.fenceNamesToFence = fenceNamesToFence;
}
public Map getFenceNamesToCallback()
{
return fenceNamesToCallback;
}
public void setFenceNamesToCallback( Map fenceNamesToCallback )
{
this.fenceNamesToCallback = fenceNamesToCallback;
}
private void initFencesToCallback()
{
if ( fenceNamesToFence == null || fencesToCallback == null || !fenceNamesToFence.keySet().equals( fenceNamesToCallback.keySet() ) )
return;
for ( String fenceName : fenceNamesToFence.keySet() )
{
fencesToCallback.put( fenceNamesToFence.get( fenceName ), fenceNamesToCallback.get( fenceName ) );
}
}
}