blob: 47c304097372c9144f9dd1d8cb9a6b069bed0198 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.wifi.rtt;
import android.location.Address;
import android.location.Location;
import android.net.MacAddress;
import android.os.Parcel;
import android.webkit.MimeTypeMap;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.List;
/**
* Tests for {@link ResponderLocation}.
*/
@RunWith(JUnit4.class)
public class ResponderLocationTest {
private static final double LATLNG_TOLERANCE_DEGREES = 0.00001;
private static final double ALT_TOLERANCE_METERS = 0.01;
private static final double HEIGHT_TOLERANCE_METERS = 0.01;
private static final int INDEX_ELEMENT_TYPE = 2;
private static final int INDEX_SUBELEMENT_TYPE = 0;
private static final int INDEX_SUBELEMENT_LENGTH = 1;
/* Test Buffers */
private static final byte[] sTestLciIeHeader = {
(byte) 0x01, (byte) 0x00, (byte) 0x08 // LCI Information Element (IE)
};
private static final byte[] sTestLciShortBuffer = {
(byte) 0x00
};
private static final byte[] sTestLciSE = {
(byte) 0x00, // Subelement LCI
(byte) 16, // Subelement LCI length always = 16
(byte) 0x52,
(byte) 0x83,
(byte) 0x4d,
(byte) 0x12,
(byte) 0xef,
(byte) 0xd2,
(byte) 0xb0,
(byte) 0x8b,
(byte) 0x9b,
(byte) 0x4b,
(byte) 0xf1,
(byte) 0xcc,
(byte) 0x2c,
(byte) 0x00,
(byte) 0x00,
(byte) 0x41
};
private static final byte[] sTestZHeightSE = {
(byte) 0x04, // Subelement Z
(byte) 6, // Length always 6
(byte) 0x00, // LSB STA Floor Info (2 bytes)
(byte) 0x01, // MSB
(byte) 0xcd, // LSB Height(m) (3 bytes)
(byte) 0x2c,
(byte) 0x00, // MSB Height(m)
(byte) 0x0e, // STA Height Uncertainty
};
private static final byte[] sTestUsageSE1 = {
(byte) 0x06, // Subelement Usage Rights
(byte) 1, // Length 1 (with no retention limit)
(byte) 0x01, // Retransmit ok, No expiration, no extra info available
};
private static final byte[] sTestUsageSE2 = {
(byte) 0x06, // Subelement Usage Rights
(byte) 3, // Length 3 (including retention limit)
(byte) 0x06, // Retransmit not ok, Expiration, extra info available
(byte) 0x00, // LSB expiration time (0x8000 = 32768 hrs)
(byte) 0x80 // MSB expiration time
};
private static final byte[] sTestBssidListSE = {
(byte) 0x07, // Subelement BSSID list
(byte) 13, // length dependent on number of BSSIDs in list
(byte) 0x02, // Number of BSSIDs in list
(byte) 0x01, // BSSID #1 (MSB)
(byte) 0x02,
(byte) 0x03,
(byte) 0x04,
(byte) 0x05,
(byte) 0x06, // (LSB)
(byte) 0xf1, // BSSID #2 (MSB)
(byte) 0xf2,
(byte) 0xf3,
(byte) 0xf4,
(byte) 0xf5,
(byte) 0xf6 // (LSB)
};
private static final byte[] sTestLcrBufferHeader = {
(byte) 0x01, (byte) 0x00, (byte) 0x0b,
};
private static final byte[] sEmptyBuffer = {};
private static final byte[] sTestCivicLocationSEWithAddress = {
(byte) 0, // Civic Location Subelement
(byte) 39, // Length of subelement value
(byte) 'U', // CountryCodeChar1
(byte) 'S', // CountryCodeChar2
(byte) CivicLocationKeys.HNO,
(byte) 2,
(byte) '1',
(byte) '5',
(byte) CivicLocationKeys.PRIMARY_ROAD_NAME,
(byte) 4,
(byte) 'A',
(byte) 'l',
(byte) 't',
(byte) 'o',
(byte) CivicLocationKeys.STREET_NAME_POST_MODIFIER,
(byte) 4,
(byte) 'R',
(byte) 'o',
(byte) 'a',
(byte) 'd',
(byte) CivicLocationKeys.CITY,
(byte) 8,
(byte) 'M',
(byte) 't',
(byte) 'n',
(byte) ' ',
(byte) 'V',
(byte) 'i',
(byte) 'e',
(byte) 'w',
(byte) CivicLocationKeys.STATE,
(byte) 2,
(byte) 'C',
(byte) 'A',
(byte) CivicLocationKeys.POSTAL_CODE,
(byte) 5,
(byte) '9',
(byte) '4',
(byte) '0',
(byte) '4',
(byte) '3'
};
// Buffer representing: "https://map.com/mall.jpg"
private static final byte[] sTestMapUrlSE = {
(byte) 5, // Map URL Subelement
(byte) 25,
(byte) 0, // MAP_TYPE_URL_DEFINED
(byte) 'h',
(byte) 't',
(byte) 't',
(byte) 'p',
(byte) 's',
(byte) ':',
(byte) '/',
(byte) '/',
(byte) 'm',
(byte) 'a',
(byte) 'p',
(byte) '.',
(byte) 'c',
(byte) 'o',
(byte) 'm',
(byte) '/',
(byte) 'm',
(byte) 'a',
(byte) 'l',
(byte) 'l',
(byte) '.',
(byte) 'j',
(byte) 'p',
(byte) 'g'
};
/**
* Test if the lci and lcr buffers are null.
*/
@Test
public void testIfLciOrLcrIsNull() {
ResponderLocation responderLocation = new ResponderLocation(null, null);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test if the lci and lcr buffers are empty.
*/
@Test
public void testIfLciOrLcrIsEmpty() {
ResponderLocation responderLocation = new ResponderLocation(sEmptyBuffer, sEmptyBuffer);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test if the lci subelement only has one byte
*/
@Test
public void testIfLciShortBuffer() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciShortBuffer);
ResponderLocation responderLocation =
new ResponderLocation(testLciBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test that the example buffer contains a valid LCI Subelement.
*/
@Test
public void testLciValidSubelement() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
ResponderLocation responderLocation =
new ResponderLocation(testLciBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
Location location = responderLocation.toLocation();
assertTrue(valid);
assertTrue(lciValid);
assertFalse(zValid);
assertEquals(0.0009765625, responderLocation.getLatitudeUncertainty());
assertEquals(-33.857009, responderLocation.getLatitude(),
LATLNG_TOLERANCE_DEGREES);
assertEquals(0.0009765625, responderLocation.getLongitudeUncertainty());
assertEquals(151.215200, responderLocation.getLongitude(),
LATLNG_TOLERANCE_DEGREES);
assertEquals(1, responderLocation.getAltitudeType());
assertEquals(64.0, responderLocation.getAltitudeUncertainty());
assertEquals(11.2, responderLocation.getAltitude(), ALT_TOLERANCE_METERS);
assertEquals(1, responderLocation.getDatum()); // WGS84
assertEquals(false, responderLocation.getRegisteredLocationAgreementIndication());
assertEquals(false, responderLocation.getRegisteredLocationDseIndication());
assertEquals(false, responderLocation.getDependentStationIndication());
assertEquals(1, responderLocation.getLciVersion());
// Testing Location Object
assertEquals(-33.857009, location.getLatitude(),
LATLNG_TOLERANCE_DEGREES);
assertEquals(151.215200, location.getLongitude(),
LATLNG_TOLERANCE_DEGREES);
assertEquals((0.0009765625 + 0.0009765625) / 2, location.getAccuracy(),
LATLNG_TOLERANCE_DEGREES);
assertEquals(11.2, location.getAltitude(), ALT_TOLERANCE_METERS);
assertEquals(64.0, location.getVerticalAccuracyMeters(), ALT_TOLERANCE_METERS);
}
/**
* Test for an invalid LCI element.
*/
@Test
public void testLciInvalidElement() {
byte[] testBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
testBuffer[INDEX_ELEMENT_TYPE] = (byte) 0xFF;
ResponderLocation responderLocation =
new ResponderLocation(testBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test for an invalid subelement type.
*/
@Test
public void testSkipLciSubElementUnusedOrUnknown() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
// Corrupt the subelement type to an unknown type.
testLciBuffer[sTestLciIeHeader.length + INDEX_SUBELEMENT_TYPE] = (byte) 0x77;
ResponderLocation responderLocation =
new ResponderLocation(testLciBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test for a subelement LCI length too small.
*/
@Test
public void testInvalidLciSubElementLengthTooSmall() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
// Corrupt the length making it too small.
testLciBuffer[sTestLciIeHeader.length + INDEX_SUBELEMENT_LENGTH] = (byte) 0x01;
ResponderLocation responderLocation =
new ResponderLocation(testLciBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test for a subelement LCI length too big.
*/
@Test
public void testInvalidLciSubElementLengthTooBig() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
// Corrupt the length making it too big.
testLciBuffer[sTestLciIeHeader.length + INDEX_SUBELEMENT_TYPE] = (byte) 0x11;
ResponderLocation responderLocation =
new ResponderLocation(testLciBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean lciValid = responderLocation.isLciSubelementValid();
boolean zValid = responderLocation.isZaxisSubelementValid();
assertFalse(valid);
assertFalse(lciValid);
assertFalse(zValid);
}
/**
* Test for a valid Z (Height) subelement following an LCI subelement.
*/
@Test
public void testLciValidZBufferSEAfterLci() {
byte[] testBufferTmp = concatenateArrays(sTestLciIeHeader, sTestLciSE);
byte[] testBuffer = concatenateArrays(testBufferTmp, sTestZHeightSE);
ResponderLocation responderLocation =
new ResponderLocation(testBuffer, sTestLcrBufferHeader);
boolean isValid = responderLocation.isValid();
boolean isZValid = responderLocation.isZaxisSubelementValid();
boolean isLciValid = responderLocation.isLciSubelementValid();
double staFloorNumber = responderLocation.getFloorNumber();
double staHeightAboveFloorMeters = responderLocation.getHeightAboveFloorMeters();
double staHeightAboveFloorUncertaintyMeters =
responderLocation.getHeightAboveFloorUncertaintyMeters();
assertTrue(isValid);
assertTrue(isZValid);
assertTrue(isLciValid);
assertEquals(4.0, staFloorNumber);
assertEquals(2.8, staHeightAboveFloorMeters, HEIGHT_TOLERANCE_METERS);
assertEquals(0.125, staHeightAboveFloorUncertaintyMeters);
}
/**
* Test for a valid Usage Policy that is unrestrictive
*/
@Test
public void testLciOpenUsagePolicy() {
byte[] testBufferTmp = concatenateArrays(sTestLciIeHeader, sTestLciSE);
byte[] testBuffer = concatenateArrays(testBufferTmp, sTestUsageSE1);
ResponderLocation responderLocation =
new ResponderLocation(testBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean retransmit = responderLocation.getRetransmitPolicyIndication();
boolean expiration = responderLocation.getRetentionExpiresIndication();
boolean extraInfo = responderLocation.getExtraInfoOnAssociationIndication();
assertTrue(valid);
assertTrue(retransmit);
assertFalse(expiration);
assertFalse(extraInfo);
}
/**
* Test for a valid Usage Policy that is restrictive
*/
@Test
public void testLciRestrictiveUsagePolicy() {
byte[] testBufferTmp = concatenateArrays(sTestLciIeHeader, sTestLciSE);
byte[] testBuffer = concatenateArrays(testBufferTmp, sTestUsageSE2);
ResponderLocation responderLocation =
new ResponderLocation(testBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
boolean retransmit = responderLocation.getRetransmitPolicyIndication();
boolean expiration = responderLocation.getRetentionExpiresIndication();
boolean extraInfo = responderLocation.getExtraInfoOnAssociationIndication();
assertFalse(valid);
assertFalse(retransmit);
assertTrue(expiration);
assertTrue(extraInfo);
}
/**
* Test for a valid BSSID element following an LCI subelement.
*/
@Test
public void testLciBssidListSEAfterLci() {
byte[] testBufferTmp = concatenateArrays(sTestLciIeHeader, sTestLciSE);
byte[] testBuffer = concatenateArrays(testBufferTmp, sTestBssidListSE);
ResponderLocation responderLocation =
new ResponderLocation(testBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
List<MacAddress> bssidList = responderLocation.getColocatedBssids();
assertTrue(valid);
assertEquals(2, bssidList.size());
MacAddress macAddress1 = bssidList.get(0);
assertEquals("01:02:03:04:05:06", macAddress1.toString());
MacAddress macAddress2 = bssidList.get(1);
assertEquals("f1:f2:f3:f4:f5:f6", macAddress2.toString());
}
/**
* Test for a valid BSSID element before and LCI element
*/
@Test
public void testLciBssidListSEBeforeLci() {
byte[] testBufferTmp = concatenateArrays(sTestLciIeHeader, sTestBssidListSE);
byte[] testBuffer = concatenateArrays(testBufferTmp, sTestLciSE);
ResponderLocation responderLocation =
new ResponderLocation(testBuffer, sTestLcrBufferHeader);
boolean valid = responderLocation.isValid();
List<MacAddress> bssidList = responderLocation.getColocatedBssids();
assertTrue(valid);
assertEquals(2, bssidList.size());
MacAddress macAddress1 = bssidList.get(0);
assertEquals("01:02:03:04:05:06", macAddress1.toString());
MacAddress macAddress2 = bssidList.get(1);
assertEquals("f1:f2:f3:f4:f5:f6", macAddress2.toString());
}
/**
* Test that a valid address can be extracted from a valid lcr buffer with Civic Location.
*/
@Test
public void testLcrTestCivicLocationAddress() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
byte[] testLcrBuffer =
concatenateArrays(sTestLcrBufferHeader, sTestCivicLocationSEWithAddress);
ResponderLocation responderLocation = new ResponderLocation(testLciBuffer, testLcrBuffer);
boolean valid = responderLocation.isValid();
String countryCode = responderLocation.getCivicLocationCountryCode();
Address address = responderLocation.toCivicLocationAddress();
assertTrue(valid);
assertEquals("US", countryCode);
assertEquals("", address.getAddressLine(0));
assertEquals("15 Alto", address.getAddressLine(1));
assertEquals("Mtn View", address.getAddressLine(2));
assertEquals("CA 94043", address.getAddressLine(3));
assertEquals("US", address.getAddressLine(4));
}
/**
* Test that a URL can be extracted from a valid lcr buffer with a map image subelement.
*/
@Test
public void testLcrCheckMapUriIsValid() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
byte[] testLcrBuffer = concatenateArrays(sTestLcrBufferHeader, sTestMapUrlSE);
ResponderLocation responderLocation = new ResponderLocation(testLciBuffer, testLcrBuffer);
boolean valid = responderLocation.isValid();
String mapImageMimeType = responderLocation.getMapImageMimeType();
String urlString = "";
if (responderLocation.getMapImageUri() != null) {
urlString = responderLocation.getMapImageUri().toString();
}
assertTrue(valid);
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
assertEquals(mimeTypeMap.getMimeTypeFromExtension("jpg"), mapImageMimeType);
assertEquals("https://map.com/mall.jpg", urlString);
}
/**
* Test the object is parcelable
*/
@Test
public void testResponderLocationParcelable() {
byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
ResponderLocation responderLocation =
new ResponderLocation(testLciBuffer, sTestLcrBufferHeader);
Parcel parcel = Parcel.obtain();
responderLocation.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
ResponderLocation responderLocationFromParcel =
ResponderLocation.CREATOR.createFromParcel(parcel);
assertEquals(responderLocationFromParcel, responderLocation);
}
/* Helper Method */
/**
* Concatenate two arrays.
*
* @param a first array
* @param b second array
* @return a third array which is the concatenation of the two array params
*/
private byte[] concatenateArrays(byte[] a, byte[] b) {
int aLen = a.length;
int bLen = b.length;
byte[] c = new byte[aLen + bLen];
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
}