diff --git a/CHANGELOG.md b/CHANGELOG.md index be72e1c02..355264a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ Bug Fixes: - Fix NPE on ExtraBeaconDataTracker (#626, David G. Young) - Fix regression with `RunningAverageRssiFilter.setSampleExpirationMilliseconds` being overwritten when committing ranged beacon measurements. (#629, Aaron Kromer) + - Fix missing running average RSSI in callbacks when apps do not use the + scheduled scan job feature. (#630, Aaron Kromer) + - Fix copying of multi-frame beacon flag in `Beacon(Beacon)` constructor (#630, Aaron Kromer) + - Fix the `AltBeaon(Beacon)` copy constructor which omitted some data fields (#630, Aaron Kromer) ### 2.12.3 / 2017-10-14 @@ -15,7 +19,7 @@ Bug Fixes: Bug Fixes: - Fix NullPointerException in ProcessUtils. (#598, David G. Young) - Fix ConcurrentModificationException crashing app on Android 8 when monitored regions are - changed at the same time the app shifts from active scanning to passive scanning. + changed at the same time the app shifts from active scanning to passive scanning. (#578, David G. Young) - Fix ConcurrentModifictionExceptions starting ScanJobs. (#584, #588, David G. Young) - Fix NullPointerException when BluetoothLeScanner cannot be obtained. @@ -52,7 +56,7 @@ Bug Fixes: [Full Changelog](https://github.com/AltBeacon/android-beacon-library/compare/2.11...2.12) Enhancements: - - Add Android O support with ScanJob using JobScheduler to do scans instead of BeaconService, + - Add Android O support with ScanJob using JobScheduler to do scans instead of BeaconService, set as default for Android O. (#484, David G. Young) Bug Fixes: diff --git a/src/main/java/org/altbeacon/beacon/AltBeacon.java b/src/main/java/org/altbeacon/beacon/AltBeacon.java index 891829e81..ccfd27775 100644 --- a/src/main/java/org/altbeacon/beacon/AltBeacon.java +++ b/src/main/java/org/altbeacon/beacon/AltBeacon.java @@ -64,20 +64,14 @@ public AltBeacon[] newArray(int size) { * @param beacon */ protected AltBeacon(Beacon beacon) { - super(); - this.mBluetoothAddress = beacon.mBluetoothAddress; - this.mIdentifiers = beacon.mIdentifiers; - this.mBeaconTypeCode = beacon.mBeaconTypeCode; - this.mDataFields = beacon.mDataFields; - this.mDistance = beacon.mDistance; - this.mRssi = beacon.mRssi; - this.mTxPower = beacon.mTxPower; + super(beacon); } /** * @see AltBeacon.Builder to make AltBeacon instances */ protected AltBeacon() { + super(); } /** diff --git a/src/main/java/org/altbeacon/beacon/Beacon.java b/src/main/java/org/altbeacon/beacon/Beacon.java index bace60eaa..f46e9edcd 100644 --- a/src/main/java/org/altbeacon/beacon/Beacon.java +++ b/src/main/java/org/altbeacon/beacon/Beacon.java @@ -279,6 +279,8 @@ protected Beacon(Beacon otherBeacon) { this.mServiceUuid = otherBeacon.getServiceUuid(); this.mBluetoothName = otherBeacon.mBluetoothName; this.mParserIdentifier = otherBeacon.mParserIdentifier; + this.mMultiFrameBeacon = otherBeacon.mMultiFrameBeacon; + this.mManufacturer = otherBeacon.mManufacturer; } /** diff --git a/src/test/java/org/altbeacon/beacon/AltBeaconTest.java b/src/test/java/org/altbeacon/beacon/AltBeaconTest.java index 2519ad132..2d726781a 100644 --- a/src/test/java/org/altbeacon/beacon/AltBeaconTest.java +++ b/src/test/java/org/altbeacon/beacon/AltBeaconTest.java @@ -2,15 +2,20 @@ import android.os.Parcel; -import static org.junit.Assert.assertEquals; - -import org.altbeacon.beacon.logging.Loggers; -import org.robolectric.RobolectricTestRunner; - -import org.junit.runner.RunWith; +import org.junit.After; import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import java.util.Arrays; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasProperty; +import static org.junit.Assert.assertEquals; + @Config(sdk = 18) @RunWith(RobolectricTestRunner.class) @@ -26,36 +31,128 @@ 4. Expand the System.err section */ public class AltBeaconTest { + private Parcel aParcel = null; - public static byte[] hexStringToByteArray(String s) { - int len = s.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) - + Character.digit(s.charAt(i+1), 16)); - } - return data; - } - - @Test - public void testRecognizeBeacon() { - byte[] bytes = hexStringToByteArray("02011a1bff1801beac2f234454cf6d4a0fadf2f4911ba9ffa600010002c509"); - AltBeaconParser parser = new AltBeaconParser(); - Beacon beacon = parser.fromScanData(bytes, -55, null); - assertEquals("manData should be parsed", 9, ((AltBeacon) beacon).getMfgReserved() ); - } + @After + public void after() { + // Clean up any obtained parcel + if (null != aParcel) { + aParcel.recycle(); + } + } + + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } + @Test + public void testRecognizeBeacon() { + byte[] bytes = hexStringToByteArray("02011a1bff1801beac2f234454cf6d4a0fadf2f4911ba9ffa600010002c509"); + AltBeaconParser parser = new AltBeaconParser(); + Beacon beacon = parser.fromScanData(bytes, -55, null); + assertEquals("manData should be parsed", 9, ((AltBeacon) beacon).getMfgReserved() ); + } @Test public void testCanSerializeParcelable() { org.robolectric.shadows.ShadowLog.stream = System.err; - Parcel parcel = Parcel.obtain(); - Beacon beacon = new AltBeacon.Builder().setMfgReserved(7).setId1("1").setId2("2").setId3("3").setRssi(4) - .setBeaconTypeCode(5).setTxPower(6) - .setBluetoothAddress("1:2:3:4:5:6").build(); - beacon.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - Beacon beacon2 = new AltBeacon(parcel); - assertEquals("beaconMfgReserved is same after deserialization", ((AltBeacon)beacon).getMfgReserved(), ((AltBeacon)beacon2).getMfgReserved()); + final Beacon original = new AltBeacon.Builder().setMfgReserved(2) + .setBluetoothAddress("aa:bb:cc:dd:ee:ff") + .setBluetoothName("Any Bluetooth") + .setBeaconTypeCode(1) + .setExtraDataFields(Arrays.asList(4L, 5L)) + .setId1("6") + .setId2("7") + .setId3("8") + .setManufacturer(10) + .setMultiFrameBeacon(true) + .setParserIdentifier("Any Parser ID") + .setRssi(-11) + .setRunningAverageRssi(-12.3) + .setServiceUuid(13) + .setTxPower(14) + .build(); + original.setPacketCount(15); + original.setRssiMeasurementCount(16); + + aParcel = Parcel.obtain(); + original.writeToParcel(aParcel, 0); + aParcel.setDataPosition(0); + final AltBeacon parceled = AltBeacon.CREATOR.createFromParcel(aParcel); + assertThat( + parceled, + allOf( + hasProperty("bluetoothAddress", equalTo("aa:bb:cc:dd:ee:ff")), + hasProperty("bluetoothName", equalTo("Any Bluetooth")), + hasProperty("beaconTypeCode", equalTo(1)), + hasProperty("dataFields", equalTo(Arrays.asList(2L))), + hasProperty("extraDataFields", equalTo(Arrays.asList(4L, 5L))), + hasProperty("id1", equalTo(Identifier.fromInt(6))), + hasProperty("id2", equalTo(Identifier.fromInt(7))), + hasProperty("id3", equalTo(Identifier.fromInt(8))), + hasProperty("manufacturer", equalTo(10)), + hasProperty("multiFrameBeacon", equalTo(true)), + hasProperty("parserIdentifier", equalTo("Any Parser ID")), + hasProperty("rssi", equalTo(-11)), + hasProperty("runningAverageRssi", equalTo(-12.3)), + hasProperty("serviceUuid", equalTo(13)), + hasProperty("txPower", equalTo(14)), + hasProperty("mfgReserved", equalTo(2)), + hasProperty("packetCount", equalTo(15)), + hasProperty("measurementCount", equalTo(16)) + ) + ); + } + + + @Test + public void copyingBeaconTransfersAllFields() { + final Beacon original = new AltBeacon.Builder().setMfgReserved(2) + .setBluetoothAddress("aa:bb:cc:dd:ee:ff") + .setBluetoothName("Any Bluetooth") + .setBeaconTypeCode(1) + .setExtraDataFields(Arrays.asList(4L, 5L)) + .setId1("6") + .setId2("7") + .setId3("8") + .setManufacturer(10) + .setMultiFrameBeacon(true) + .setParserIdentifier("Any Parser ID") + .setRssi(-11) + .setRunningAverageRssi(-12.3) + .setServiceUuid(13) + .setTxPower(14) + .build(); + original.setPacketCount(15); + original.setRssiMeasurementCount(16); + final AltBeacon copied = new AltBeacon(original); + assertThat( + copied, + allOf( + hasProperty("bluetoothAddress", equalTo("aa:bb:cc:dd:ee:ff")), + hasProperty("bluetoothName", equalTo("Any Bluetooth")), + hasProperty("beaconTypeCode", equalTo(1)), + hasProperty("dataFields", equalTo(Arrays.asList(2L))), + hasProperty("extraDataFields", equalTo(Arrays.asList(4L, 5L))), + hasProperty("id1", equalTo(Identifier.fromInt(6))), + hasProperty("id2", equalTo(Identifier.fromInt(7))), + hasProperty("id3", equalTo(Identifier.fromInt(8))), + hasProperty("manufacturer", equalTo(10)), + hasProperty("multiFrameBeacon", equalTo(true)), + hasProperty("parserIdentifier", equalTo("Any Parser ID")), + hasProperty("rssi", equalTo(-11)), + hasProperty("runningAverageRssi", equalTo(-12.3)), + hasProperty("serviceUuid", equalTo(13)), + hasProperty("txPower", equalTo(14)), + hasProperty("packetCount", equalTo(15)), + hasProperty("measurementCount", equalTo(16)) + ) + ); } } diff --git a/src/test/java/org/altbeacon/beacon/BeaconTest.java b/src/test/java/org/altbeacon/beacon/BeaconTest.java index d95fb0e72..63d37ea8f 100644 --- a/src/test/java/org/altbeacon/beacon/BeaconTest.java +++ b/src/test/java/org/altbeacon/beacon/BeaconTest.java @@ -1,11 +1,18 @@ package org.altbeacon.beacon; +import android.os.Parcel; + import org.altbeacon.beacon.distance.ModelSpecificDistanceCalculator; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasProperty; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -35,11 +42,21 @@ 4. Expand the System.err section */ public class BeaconTest { + private Parcel aParcel = null; @Before public void before() { Beacon.setHardwareEqualityEnforced(false); } + + @After + public void after() { + // Clean up any obtained parcel + if (null != aParcel) { + aParcel.recycle(); + } + } + @Test public void testAccessBeaconIdentifiers() { Beacon beacon = new AltBeacon.Builder().setMfgReserved(7).setId1("1").setId2("2").setId3("3").setRssi(4) @@ -206,6 +223,102 @@ public void testHashCodeWithNullIdentifier() { .build(); assertTrue("hashCode() should not throw exception", beacon.hashCode() >= Integer.MIN_VALUE); } + + @Test + public void parcelingBeaconContainsAllFields() { + final Beacon original = new Beacon.Builder().setBluetoothAddress("aa:bb:cc:dd:ee:ff") + .setBluetoothName("Any Bluetooth") + .setBeaconTypeCode(1) + .setDataFields(Arrays.asList(2L, 3L)) + .setExtraDataFields(Arrays.asList(4L, 5L)) + .setId1("6") + .setId2("7") + .setId3("8") + .setManufacturer(10) + .setMultiFrameBeacon(true) + .setParserIdentifier("Any Parser ID") + .setRssi(-11) + .setRunningAverageRssi(-12.3) + .setServiceUuid(13) + .setTxPower(14) + .build(); + original.setPacketCount(15); + original.setRssiMeasurementCount(16); + + aParcel = Parcel.obtain(); + original.writeToParcel(aParcel, 0); + aParcel.setDataPosition(0); + final Beacon parceled = Beacon.CREATOR.createFromParcel(aParcel); + assertThat( + parceled, + allOf( + hasProperty("bluetoothAddress", equalTo("aa:bb:cc:dd:ee:ff")), + hasProperty("bluetoothName", equalTo("Any Bluetooth")), + hasProperty("beaconTypeCode", equalTo(1)), + hasProperty("dataFields", equalTo(Arrays.asList(2L, 3L))), + hasProperty("extraDataFields", equalTo(Arrays.asList(4L, 5L))), + hasProperty("id1", equalTo(Identifier.fromInt(6))), + hasProperty("id2", equalTo(Identifier.fromInt(7))), + hasProperty("id3", equalTo(Identifier.fromInt(8))), + hasProperty("manufacturer", equalTo(10)), + hasProperty("multiFrameBeacon", equalTo(true)), + hasProperty("parserIdentifier", equalTo("Any Parser ID")), + hasProperty("rssi", equalTo(-11)), + hasProperty("runningAverageRssi", equalTo(-12.3)), + hasProperty("serviceUuid", equalTo(13)), + hasProperty("txPower", equalTo(14)), + hasProperty("packetCount", equalTo(15)), + hasProperty("measurementCount", equalTo(16)) + ) + ); + } + + @Test + public void copyingBeaconContainsAllFields() { + final Beacon original = new Beacon.Builder().setBluetoothAddress("aa:bb:cc:dd:ee:ff") + .setBluetoothName("Any Bluetooth") + .setBeaconTypeCode(1) + .setDataFields(Arrays.asList(2L, 3L)) + .setExtraDataFields(Arrays.asList(4L, 5L)) + .setId1("6") + .setId2("7") + .setId3("8") + .setManufacturer(10) + .setMultiFrameBeacon(true) + .setParserIdentifier("Any Parser ID") + .setRssi(-11) + .setRunningAverageRssi(-12.3) + .setServiceUuid(13) + .setTxPower(14) + .build(); + original.setPacketCount(15); + original.setRssiMeasurementCount(16); + + final Beacon copied = new Beacon(original); + assertThat( + copied, + allOf( + hasProperty("bluetoothAddress", equalTo("aa:bb:cc:dd:ee:ff")), + hasProperty("bluetoothName", equalTo("Any Bluetooth")), + hasProperty("beaconTypeCode", equalTo(1)), + hasProperty("dataFields", equalTo(Arrays.asList(2L, 3L))), + hasProperty("extraDataFields", equalTo(Arrays.asList(4L, 5L))), + hasProperty("id1", equalTo(Identifier.fromInt(6))), + hasProperty("id2", equalTo(Identifier.fromInt(7))), + hasProperty("id3", equalTo(Identifier.fromInt(8))), + hasProperty("manufacturer", equalTo(10)), + hasProperty("multiFrameBeacon", equalTo(true)), + hasProperty("parserIdentifier", equalTo("Any Parser ID")), + hasProperty("rssi", equalTo(-11)), + hasProperty("runningAverageRssi", equalTo(-12.3)), + hasProperty("serviceUuid", equalTo(13)), + hasProperty("txPower", equalTo(14)), + hasProperty("packetCount", equalTo(15)), + hasProperty("measurementCount", equalTo(16)) + ) + ); + } + // utilty methods for testing serialization private byte[] convertToBytes(Object object) throws IOException { diff --git a/src/test/java/org/altbeacon/beacon/service/RangingDataTest.java b/src/test/java/org/altbeacon/beacon/service/RangingDataTest.java index 403cd9553..90f92dbf1 100644 --- a/src/test/java/org/altbeacon/beacon/service/RangingDataTest.java +++ b/src/test/java/org/altbeacon/beacon/service/RangingDataTest.java @@ -41,7 +41,14 @@ public void testSerialization() throws Exception { identifiers.add(Identifier.parse("2")); Region region = new Region("testRegion", identifiers); ArrayList beacons = new ArrayList(); - Beacon beacon = new Beacon.Builder().setIdentifiers(identifiers).setRssi(-1).setRunningAverageRssi(-2).setTxPower(-50).setBluetoothAddress("01:02:03:04:05:06").build(); + Beacon beacon = new Beacon.Builder().setIdentifiers(identifiers) + .setRssi(-1) + .setRunningAverageRssi(-2) + .setTxPower(-50) + .setBluetoothAddress("01:02:03:04:05:06") + .build(); + beacon.setRssiMeasurementCount(1); + beacon.setPacketCount(2); for (int i=0; i < 10; i++) { beacons.add(beacon); } @@ -49,8 +56,14 @@ public void testSerialization() throws Exception { Bundle bundle = data.toBundle(); RangingData data2 = RangingData.fromBundle(bundle); assertEquals("beacon count shouild be restored", 10, data2.getBeacons().size()); - assertEquals("beacon identifier 1 shouild be restored", "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6", data2.getBeacons().iterator().next().getId1().toString()); assertEquals("region identifier 1 shouild be restored", "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6", data2.getRegion().getId1().toString()); + Beacon restoredBeacon = data2.getBeacons().iterator().next(); + assertEquals("beacon identifier 1 shouild be restored", "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6", restoredBeacon.getId1().toString()); + assertEquals("RSSI is restored", -1, restoredBeacon.getRssi()); + assertEquals("Average RSSI is restored", -2.0, restoredBeacon.getRunningAverageRssi(), 0.0); + assertEquals("TXPower is restored", -50, restoredBeacon.getTxPower()); + assertEquals("Measurement count is restored", 1, restoredBeacon.getMeasurementCount()); + assertEquals("Packet count is restored", 2, restoredBeacon.getPacketCount()); } @Test