com.backendless.geo.geofence.GeoFenceMonitoring Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of android Show documentation
Show all versions of android Show documentation
Android SDK used by developers to provide Backendless API in apps.
/*
* ********************************************************************************************************************
*
* 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 ) );
}
}
}