diff --git a/src/main/java/com/firebase/geofire/GeoQueryDataEventListener.java b/src/main/java/com/firebase/geofire/GeoQueryDataEventListener.java index a8b4e39..0537380 100644 --- a/src/main/java/com/firebase/geofire/GeoQueryDataEventListener.java +++ b/src/main/java/com/firebase/geofire/GeoQueryDataEventListener.java @@ -67,9 +67,14 @@ public interface GeoQueryDataEventListener { /** * Called if a dataSnapshot changed within the search area. - * An onDataMoved() event would always be preceded by onDataChanged() but it would be possible to see onDataChanged() without an antecedent onDataMoved(). * - * This method can be called multiple times. + * An onDataMoved() is always followed by onDataChanged() but it is be possible to see + * onDataChanged() without an preceding onDataMoved(). + * + * This method can be called multiple times for a single location change, due to the way + * the Realtime Database handles floating point numbers. + * + * Note: this method is not related to ValueEventListener#onDataChange(DataSnapshot). * * @param dataSnapshot The associated dataSnapshot that moved within the search area * @param location The location for this dataSnapshot as a GeoLocation object diff --git a/src/test/java/com/firebase/geofire/GeoQueryDataEventTestListener.java b/src/test/java/com/firebase/geofire/GeoQueryDataEventTestListener.java new file mode 100644 index 0000000..923b5aa --- /dev/null +++ b/src/test/java/com/firebase/geofire/GeoQueryDataEventTestListener.java @@ -0,0 +1,80 @@ +package com.firebase.geofire; + +import static java.util.Locale.US; + +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DataSnapshot; + +public class GeoQueryDataEventTestListener extends TestListener implements GeoQueryDataEventListener { + + private boolean recordEntered; + private boolean recordMoved; + private boolean recordChanged; + private boolean recordExited; + + public static String dataEntered(String key, double latitude, double longitude) { + return String.format(US, "DATA_ENTERED(%s,%f,%f)", key, latitude, longitude); + } + + public static String dataExited(String key) { + return String.format("DATA_EXITED(%s)", key); + } + + public static String dataMoved(String key, double latitude, double longitude) { + return String.format(US, "DATA_MOVED(%s,%f,%f)", key, latitude, longitude); + } + + public static String dataChanged(String key, double latitude, double longitude) { + return String.format(US, "DATA_CHANGED(%s,%f,%f)", key, latitude, longitude); + } + + public GeoQueryDataEventTestListener(boolean recordEntered, + boolean recordMoved, + boolean recordChanged, + boolean recordExited) { + this.recordEntered = recordEntered; + this.recordMoved = recordMoved; + this.recordChanged = recordChanged; + this.recordExited = recordExited; + + } + + @Override + public void onDataEntered(DataSnapshot dataSnapshot, GeoLocation location) { + if (recordEntered) { + this.addEvent(dataEntered(dataSnapshot.getKey(), location.latitude, location.longitude)); + } + } + + @Override + public void onDataExited(DataSnapshot dataSnapshot) { + if (recordExited) { + this.addEvent(dataExited(dataSnapshot.getKey())); + } + } + + @Override + public void onDataMoved(DataSnapshot dataSnapshot, GeoLocation location) { + if (recordMoved) { + this.addEvent(dataMoved(dataSnapshot.getKey(), location.latitude, location.longitude)); + } + } + + @Override + public void onDataChanged(DataSnapshot dataSnapshot, GeoLocation location) { + if (recordChanged) { + this.addEvent(dataChanged(dataSnapshot.getKey(), location.latitude, location.longitude)); + } + } + + @Override + public void onGeoQueryReady() { + + } + + @Override + public void onGeoQueryError(DatabaseError error) { + + } + +} diff --git a/src/test/java/com/firebase/geofire/GeoQueryTest.java b/src/test/java/com/firebase/geofire/GeoQueryTest.java index d9978f3..3c76a9e 100644 --- a/src/test/java/com/firebase/geofire/GeoQueryTest.java +++ b/src/test/java/com/firebase/geofire/GeoQueryTest.java @@ -1,6 +1,7 @@ package com.firebase.geofire; import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; import junit.framework.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -109,6 +110,43 @@ public void keyMoved() throws InterruptedException { testListener.expectEvents(events); } + @Test + public void dataChanged() throws InterruptedException { + GeoFire geoFire = newTestGeoFire(); + setLoc(geoFire, "0", 0, 0); + setLoc(geoFire, "1", 37.0000, -122.0001); + setLoc(geoFire, "2", 37.0001, -122.0001); + setLoc(geoFire, "3", 37.1000, -122.0000); + setLoc(geoFire, "4", 37.0002, -121.9998, true); + + GeoQuery query = geoFire.queryAtLocation(new GeoLocation(37, -122), 0.5); + + GeoQueryDataEventTestListener testListener = new GeoQueryDataEventTestListener( + false, true, true, false); + query.addGeoQueryDataEventListener(testListener); + + waitForGeoFireReady(geoFire); + + setLoc(geoFire, "0", 1, 1, true); // outside of query + setLoc(geoFire, "1", 37.0001, -122.0001, true); // moved + setLoc(geoFire, "2", 37.0001, -122.0001, true); // location stayed the same + setLoc(geoFire, "4", 37.0002, -121.9999, true); // moved + + DatabaseReference childRef = geoFire.getDatabaseRefForKey("2").child("some_child"); + setValueAndWait(childRef, "some_value"); // data changed + + List events = new LinkedList<>(); + events.add(GeoQueryDataEventTestListener.dataMoved("1", 37.0001, -122.0001)); + events.add(GeoQueryDataEventTestListener.dataChanged("1", 37.0001, -122.0001)); + + events.add(GeoQueryDataEventTestListener.dataMoved("4", 37.0002, -121.9999)); + events.add(GeoQueryDataEventTestListener.dataChanged("4", 37.0002, -121.9999)); + + events.add(GeoQueryDataEventTestListener.dataChanged("2", 37.0001, -122.0001)); + + testListener.expectEvents(events); + } + @Test public void subQueryTriggersKeyMoved() throws InterruptedException { GeoFire geoFire = newTestGeoFire();