Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Multiple Notifiers Support (Range and Monitor) #392

Merged
merged 4 commits into from
Jun 24, 2016
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 17 additions & 12 deletions src/main/java/org/altbeacon/beacon/BeaconIntentProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import android.app.IntentService;
import android.content.Intent;

import java.util.List;

/**
* Converts internal intents to notifier callbacks
*/
Expand Down Expand Up @@ -59,10 +61,12 @@ protected void onHandleIntent(Intent intent) {
if (rangingData.getBeacons() == null) {
LogManager.w(TAG, "Ranging data has a null beacons collection");
}
RangeNotifier notifier = BeaconManager.getInstanceForApplication(this).getRangingNotifier();
List<RangeNotifier> notifiers = BeaconManager.getInstanceForApplication(this).getRangingNotifiers();
java.util.Collection<Beacon> beacons = rangingData.getBeacons();
if (notifier != null) {
notifier.didRangeBeaconsInRegion(beacons, rangingData.getRegion());
if (notifiers != null) {
for(RangeNotifier notifier : notifiers){
notifier.didRangeBeaconsInRegion(beacons, rangingData.getRegion());
}
}
else {
LogManager.d(TAG, "but ranging notifier is null, so we're dropping it.");
Expand All @@ -75,15 +79,16 @@ protected void onHandleIntent(Intent intent) {

if (monitoringData != null) {
LogManager.d(TAG, "got monitoring data");
MonitorNotifier notifier = BeaconManager.getInstanceForApplication(this).getMonitoringNotifier();
if (notifier != null) {
LogManager.d(TAG, "Calling monitoring notifier: %s", notifier);
notifier.didDetermineStateForRegion(monitoringData.isInside() ? MonitorNotifier.INSIDE : MonitorNotifier.OUTSIDE, monitoringData.getRegion());
if (monitoringData.isInside()) {
notifier.didEnterRegion(monitoringData.getRegion());
}
else {
notifier.didExitRegion(monitoringData.getRegion());
List<MonitorNotifier> notifiers = BeaconManager.getInstanceForApplication(this).getMonitoringNotifiers();
if (notifiers != null) {
for(MonitorNotifier notifier : notifiers) {
LogManager.d(TAG, "Calling monitoring notifier: %s", notifier);
notifier.didDetermineStateForRegion(monitoringData.isInside() ? MonitorNotifier.INSIDE : MonitorNotifier.OUTSIDE, monitoringData.getRegion());
if (monitoringData.isInside()) {
notifier.didEnterRegion(monitoringData.getRegion());
} else {
notifier.didExitRegion(monitoringData.getRegion());
}
}
}
}
Expand Down
142 changes: 131 additions & 11 deletions src/main/java/org/altbeacon/beacon/BeaconManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@
import org.altbeacon.beacon.logging.LogManager;
import org.altbeacon.beacon.logging.Loggers;
import org.altbeacon.beacon.service.BeaconService;
import org.altbeacon.beacon.service.scanner.NonBeaconLeScanCallback;
import org.altbeacon.beacon.service.RangeState;
import org.altbeacon.beacon.service.RangedBeacon;
import org.altbeacon.beacon.service.RunningAverageRssiFilter;
import org.altbeacon.beacon.service.StartRMData;
import org.altbeacon.beacon.service.scanner.NonBeaconLeScanCallback;
import org.altbeacon.beacon.simulator.BeaconSimulator;

import java.util.ArrayList;
Expand Down Expand Up @@ -109,9 +109,9 @@ public class BeaconManager {
protected static BeaconManager client = null;
private final ConcurrentMap<BeaconConsumer, ConsumerInfo> consumers = new ConcurrentHashMap<BeaconConsumer,ConsumerInfo>();
private Messenger serviceMessenger = null;
protected RangeNotifier rangeNotifier = null;
protected final List<RangeNotifier> rangeNotifiers = new CopyOnWriteArrayList<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good if these collections were based on Set not List. Because if folks repeatedly call addXxxNotifier() with the same object, it could cause trouble. Making this change could protect against this. Perhaps use ConcurrentHashMap.newKeySet()?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think to use an CopyOnWriteArraySet. What do you think?

As consequences, the getMonitorNotifier() and the getRangeNotifier() method are irrelevants. Do you want to keep them or can I remove them ?
(I think these methods are only useful internally to the library. They are not in usage any more inside the library)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do need to keep getMonitorNotifier() and getRangeNotifier() so that this is not a breaking API change. I think a CopyOnWriteArraySet is probably fine.

protected RangeNotifier dataRequestNotifier = null;
protected MonitorNotifier monitorNotifier = null;
protected List<MonitorNotifier> monitorNotifiers = new CopyOnWriteArrayList<>();
private final ArrayList<Region> monitoredRegions = new ArrayList<Region>();
private final ArrayList<Region> rangedRegions = new ArrayList<Region>();
private final List<BeaconParser> beaconParsers = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -422,9 +422,54 @@ public boolean isBackgroundModeUninitialized() {
*
* @param notifier
* @see RangeNotifier
* @deprecated replaced by (@link #addRangeNotifier)
*/
@Deprecated
public void setRangeNotifier(RangeNotifier notifier) {
rangeNotifier = notifier;
synchronized (rangeNotifiers) {
rangeNotifiers.clear();
}
addRangeNotifier(notifier);
}

/**
* Specifies a class that should be called each time the <code>BeaconService</code> gets ranging
* data, which is nominally once per second when beacons are detected.
* <p/>
* Permits to register several <code>RangeNotifier</code> objects.
* <p/>
*The notifier must be unregistered using (@link #removeRangeNotifier)
*
* @param notifier
* @see RangeNotifier
*/
public void addRangeNotifier(RangeNotifier notifier){
if(notifier != null){
synchronized (rangeNotifiers){
rangeNotifiers.add(notifier);
}
}
}

/**
* Specifies a class to remove from the array of <code>RangeNotifier</code>
*
* @param notifier
* @see RangeNotifier
*/
public boolean removeRangeNotifier(RangeNotifier notifier){
synchronized (rangeNotifiers){
return rangeNotifiers.remove(notifier);
}
}

/**
* Remove all the Range Notifiers
*/
public void removeAllRangeNotifiers(){
synchronized (rangeNotifiers){
rangeNotifiers.clear();
}
}

/**
Expand All @@ -439,9 +484,58 @@ public void setRangeNotifier(RangeNotifier notifier) {
* @see MonitorNotifier
* @see #startMonitoringBeaconsInRegion(Region region)
* @see Region
* @deprecated replaced by (@link #addMonitorNotifier)
*/
@Deprecated
public void setMonitorNotifier(MonitorNotifier notifier) {
monitorNotifier = notifier;
synchronized (monitorNotifiers) {
monitorNotifiers.clear();
}
addMonitorNotifier(notifier);
}

/**
* Specifies a class that should be called each time the <code>BeaconService</code> sees
* or stops seeing a Region of beacons.
* <p/>
* Permits to register severals <code>MonitorNotifier</code> objects.
*<p/>
* Unregister the notifier using (@link #removeMonitoreNotifier)
*
* @param notifier
* @see MonitorNotifier
* @see #startMonitoringBeaconsInRegion(Region region)
* @see Region
*/
public void addMonitorNotifier(MonitorNotifier notifier){
if(notifier != null){
synchronized (monitorNotifiers) {
monitorNotifiers.add(notifier);
}
}
}

/**
* Specifies a class to remove from the array of <code>MonitorNotifier</code>.
*
* @param notifier
* @see MonitorNotifier
* @see #startMonitoringBeaconsInRegion(Region region)
* @see Region
*/
public boolean removeMonitoreNotifier(MonitorNotifier notifier){
synchronized (monitorNotifiers){
return monitorNotifiers.remove(notifier);
}
}

/**
* Remove all the Monitor Notifers
*/
public void removeAllMonitorNotifiers(){
synchronized (monitorNotifiers){
monitorNotifiers.clear();
}
}

/**
Expand Down Expand Up @@ -603,19 +697,45 @@ private String callbackPackageName() {
}

/**
* @return monitorNotifier
* @see #monitorNotifier
* @return the first registered monitorNotifier
* @deprecated replaced by (@link #getMonitorNotifiers)
*/
@Deprecated
public MonitorNotifier getMonitoringNotifier() {
return this.monitorNotifier;
synchronized (monitorNotifiers) {
if (monitorNotifiers.size() > 0) {
return monitorNotifiers.get(0);
}
return null;
}
}

/**
* @return the list of registered monitorNotifier
*/
public List<MonitorNotifier> getMonitoringNotifiers(){
return monitorNotifiers;
}

/**
* @return rangeNotifier
* @see #rangeNotifier
* @return the first registered rangeNotifier
* @deprecated replaced by (@link #getRangeNotifiers)
*/
@Deprecated
public RangeNotifier getRangingNotifier() {
return this.rangeNotifier;
synchronized (rangeNotifiers) {
if (rangeNotifiers.size() > 0) {
return rangeNotifiers.get(0);
}
return null;
}
}

/**
* @return the list of registered rangeNotifier
*/
public List<RangeNotifier> getRangingNotifiers(){
return rangeNotifiers;
}

/**
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/org/altbeacon/beacon/notifier/RegionFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.altbeacon.beacon.notifier;

import org.altbeacon.beacon.Region;

import java.util.ArrayList;
import java.util.List;

/**
* Created by Connecthings on 21/06/16.
*/
public class RegionFilter {

private final List<Region> regions = new ArrayList<>();

/**
* @param region
*/
public void addRegion(Region region){
synchronized (regions){
regions.add(region);
}
}

/**
* @param region
* @return
*/
public boolean removeRegion(Region region){
synchronized (regions) {
return regions.remove(region);
}
}

/**
*
*/
public void removeAllRegions(){
synchronized (regions){
regions.clear();
}
}

public boolean containRegion(Region region){
synchronized (regions){
return regions.contains(region);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.altbeacon.beacon.notifier;

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.MonitorNotifier;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
*
* Created by Connecthings on 21/06/16.
*/
public abstract class RegionMonitorNotifier implements MonitorNotifier{

private final RegionFilter regionFilter = new RegionFilter();

public void addRegion(Region region) {
regionFilter.addRegion(region);
}

public boolean removeRegion(Region region) {
return regionFilter.removeRegion(region);
}

public void removeAllRegions() {
regionFilter.removeAllRegions();
}

@Override
public void didDetermineStateForRegion(int state, Region region) {
if(regionFilter.containRegion(region)){
didDetermineStateForInReferencedRegion(state, region);
}
}

@Override
public void didEnterRegion(Region region) {
if(regionFilter.containRegion(region)) {
didEnterInReferencedRegion(region);
}
}

@Override
public void didExitRegion(Region region) {
if(regionFilter.containRegion(region)){
didExitInReferencedRegion(region);
}
}

public abstract void didEnterInReferencedRegion (Region region );

public abstract void didExitInReferencedRegion (Region region );

public abstract void didDetermineStateForInReferencedRegion (int state, Region region );

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.altbeacon.beacon.notifier;

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* Created by Connecthings on 21/06/16.
*/
public abstract class RegionRangeNotifier implements RangeNotifier{

private final RegionFilter regionFilter = new RegionFilter();


public void addRegion(Region region) {
regionFilter.addRegion(region);
}


public boolean removeRegion(Region region) {
return regionFilter.removeRegion(region);
}

public void removeAllRegions() {
regionFilter.removeAllRegions();
}

@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if(regionFilter.containRegion(region)){
didRangeBeaconsInReferencedRegion(beacons, region);
}
}

/**
*
* @param beacons
* @param region
*/
public abstract void didRangeBeaconsInReferencedRegion ( Collection<Beacon> beacons, Region region );
}