content: package org.altbeacon.beacon;
  
  import android.bluetooth.BluetoothDevice;
  import android.os.Parcel;
  
  import org.junit.Test;
  import org.robolectric.annotation.Config;
  
  import java.util.ArrayList;
  
  import static junit.framework.Assert.assertEquals;
  import static junit.framework.Assert.assertNotNull;
  
  @Config(sdk = 28)
  
  /**
   * Created by dyoung on 7/22/14.
   */
  public class SBeaconTest {
  
      @Test
      public void testDetectsSBeacon() {
          org.robolectric.shadows.ShadowLog.stream = System.err;
          byte[] bytes = hexStringToByteArray("02011a1bff1801031501000100c502000000000000000003");
          SBeaconParser parser = new SBeaconParser();
          SBeacon sBeacon = (SBeacon) parser.fromScanData(bytes, -55, null, 123456L);
          assertNotNull("SBeacon should be not null if parsed successfully", sBeacon);
          assertEquals("id should be parsed", "0x000000000003", sBeacon.getId());
          assertEquals("group should be parsed", 1, sBeacon.getGroup());
          assertEquals("time should be parsed", 2, sBeacon.getTime());
          assertEquals("txPower should be parsed", -59, sBeacon.getTxPower());
      }
  
      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;
      }
  
      class SBeacon extends Beacon {
          private static final String TAG = "SBeacon";
          private int mTime;
  
          protected SBeacon(int group, String id, int time, int txPower, int rssi, int beaconTypeCode, String bluetoothAddress) {
              super();
              mTxPower = txPower;
              mRssi = rssi;
              mBeaconTypeCode = beaconTypeCode;
              mBluetoothAddress = bluetoothAddress;
              mIdentifiers = new ArrayList<Identifier>(2);
              mIdentifiers.add(Identifier.fromInt(group));
              mIdentifiers.add(Identifier.parse(id));
              mTime = time;
              //BeaconManager.logDebug(TAG, "constructed a new sbeacon with id2: " + getIdentifier(2));
          }
  
          public int getGroup() {
              return mIdentifiers.get(0).toInt();
          }
          public int getTime() {
              return mTime;
          }
          public String getId() {
              return mIdentifiers.get(1).toString();
          }
  
          @Override
          public int describeContents() {
              return 0;
          }
  
          @Override
          public void writeToParcel(Parcel dest, int flags) {
              // TODO: Implement me
          }
  
          protected SBeacon(Parcel in) {
              // TODO: Implement me
          }
      }
  
      class SBeaconParser extends BeaconParser {
          private static final String TAG = "SBeaconParser";
  
          @Override
          public Beacon fromScanData(byte[] scanData, int rssi, BluetoothDevice device, long timestamp) {
              int startByte = 2;
              while (startByte <= 5) {
                  // "m:2-3=0203,i:2-2,i:7-8,i:14-19,d:10-13,p:9-9"
                  if (((int)scanData[startByte+3] & 0xff) == 0x03 &&
                          ((int)scanData[startByte+4] & 0xff) == 0x15) {
                      //BeaconManager.logDebug(TAG, "This is a SBeacon beacon advertisement");
                      // startByte+0 company id (2 bytes)
                      // startByte+2 = 02 (1) byte header
                      // startByte+3 = 0315 (2 bytes) header
                      // startByte+5 = Beacon Type 0x01
                      // startByte+6 = Reserved (1 bytes)
                      // startByte+7 = Security Code (2 bytes) => Major little endian
                      // startByte+9 = Tx Power => Tx Power
                      // startByte+10 = Timestamp (4 bytes) => Minor (2 LSBs) little endian
                      // startByte+14 = Beacon ID (6 bytes) -> UUID little endian
                      int group = (scanData[startByte+8] & 0xff) * 0x100 + (scanData[startByte+7] & 0xff);
                      int clock = (scanData[startByte+13] & 0xff) * 0x1000000 + (scanData[startByte+12] & 0xff) * 0x10000 + (scanData[startByte+11] & 0xff) * 0x100 + (scanData[startByte+10] & 0xff);
                      int txPower = (int)scanData[startByte+9]; // this one is signed
  
                      byte[] beaconId = new byte[6];
                      System.arraycopy(scanData, startByte+14, beaconId, 0, 6);
                      String hexString = bytesToHex(beaconId);
                      StringBuilder sb = new StringBuilder();
                      sb.append(hexString.substring(0,12));
                      String id = "0x" + sb.toString();
                      int beaconTypeCode = (scanData[startByte+3] & 0xff) * 0x100 + (scanData[startByte+2] & 0xff);
  
  
                      String mac = null;
                      if (device != null) {
                          mac = device.getAddress();
                      }
                      Beacon beacon = new SBeacon(group, id, clock, txPower, rssi, beaconTypeCode, mac);
                      return beacon;
                  }
                  startByte++;
              }
              return null;
          }
      }
  }
  