Skip to content

Commit

Permalink
refactor: move everything from MultiplatformAdapter library into andr…
Browse files Browse the repository at this point in the history
…oid library folder
  • Loading branch information
gmiszewski-intent committed Oct 9, 2023
1 parent c69107b commit 33d1b30
Show file tree
Hide file tree
Showing 44 changed files with 3,642 additions and 35 deletions.
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ android {
repositories {
mavenCentral()
google()
maven { url 'https://jitpack.io' }
}


Expand All @@ -90,7 +89,8 @@ dependencies {
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation 'com.github.dotintent:MultiPlatformBleAdapter:a136c3f4ac'
implementation 'io.reactivex.rxjava2:rxjava:2.2.17'
implementation "com.polidea.rxandroidble2:rxandroidble:1.17.2"
}

if (isNewArchitectureEnabled()) {
Expand Down
19 changes: 18 additions & 1 deletion android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.bleplx">
package="com.bleplx"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT"
tools:targetApi="s" />
</manifest>
30 changes: 15 additions & 15 deletions android/src/main/java/com/bleplx/BlePlxModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.polidea.multiplatformbleadapter.BleAdapter;
import com.polidea.multiplatformbleadapter.BleAdapterFactory;
import com.polidea.multiplatformbleadapter.Characteristic;
import com.polidea.multiplatformbleadapter.ConnectionOptions;
import com.polidea.multiplatformbleadapter.ConnectionState;
import com.polidea.multiplatformbleadapter.Descriptor;
import com.polidea.multiplatformbleadapter.Device;
import com.polidea.multiplatformbleadapter.OnErrorCallback;
import com.polidea.multiplatformbleadapter.OnEventCallback;
import com.polidea.multiplatformbleadapter.OnSuccessCallback;
import com.polidea.multiplatformbleadapter.RefreshGattMoment;
import com.polidea.multiplatformbleadapter.ScanResult;
import com.polidea.multiplatformbleadapter.Service;
import com.polidea.multiplatformbleadapter.errors.BleError;
import com.bleplx.adapter.BleAdapter;
import com.bleplx.adapter.BleAdapterFactory;
import com.bleplx.adapter.Characteristic;
import com.bleplx.adapter.ConnectionOptions;
import com.bleplx.adapter.ConnectionState;
import com.bleplx.adapter.Descriptor;
import com.bleplx.adapter.Device;
import com.bleplx.adapter.OnErrorCallback;
import com.bleplx.adapter.OnEventCallback;
import com.bleplx.adapter.OnSuccessCallback;
import com.bleplx.adapter.RefreshGattMoment;
import com.bleplx.adapter.ScanResult;
import com.bleplx.adapter.Service;
import com.bleplx.adapter.errors.BleError;
import com.bleplx.converter.BleErrorToJsObjectConverter;
import com.bleplx.converter.CharacteristicToJsObjectConverter;
import com.bleplx.converter.DescriptorToJsObjectConverter;
Expand Down Expand Up @@ -936,7 +936,7 @@ public void onError(BleError bleError) {

@ReactMethod
public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
// Keep: Required for RN built in Event Emitter Calls.
}

@ReactMethod
Expand Down
250 changes: 250 additions & 0 deletions android/src/main/java/com/bleplx/adapter/AdvertisementData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
package com.bleplx.adapter;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

public class AdvertisementData {

private byte[] manufacturerData;
private Map<UUID, byte[]> serviceData;
private List<UUID> serviceUUIDs;
private String localName;
private Integer txPowerLevel;
private List<UUID> solicitedServiceUUIDs;
private byte[] rawScanRecord;

private static final long BLUETOOTH_BASE_UUID_LSB = 0x800000805F9B34FBL;
private static final int BLUETOOTH_BASE_UUID_MSB = 0x00001000;

public String getLocalName() {
return localName;
}

public byte[] getManufacturerData() {
return manufacturerData;
}

public Map<UUID, byte[]> getServiceData() {
return serviceData;
}

public List<UUID> getServiceUUIDs() {
return serviceUUIDs;
}

public Integer getTxPowerLevel() {
return txPowerLevel;
}

public List<UUID> getSolicitedServiceUUIDs() {
return solicitedServiceUUIDs;
}

public byte[] getRawScanRecord() {
return rawScanRecord;
}

private AdvertisementData() {}

public AdvertisementData(byte[] manufacturerData,
Map<UUID, byte[]> serviceData,
List<UUID> serviceUUIDs,
String localName,
Integer txPowerLevel,
List<UUID> solicitedServiceUUIDs) {
this.manufacturerData = manufacturerData;
this.serviceData = serviceData;
this.serviceUUIDs = serviceUUIDs;
this.localName = localName;
this.txPowerLevel = txPowerLevel;
this.solicitedServiceUUIDs = solicitedServiceUUIDs;
}

public static AdvertisementData parseScanResponseData(byte[] advertisement) {
AdvertisementData advData = new AdvertisementData();
advData.rawScanRecord = advertisement;

ByteBuffer rawData = ByteBuffer.wrap(advertisement).order(ByteOrder.LITTLE_ENDIAN);
while (rawData.remaining() >= 2) {
int adLength = rawData.get() & 0xFF;
if (adLength == 0) break;
adLength -= 1;
int adType = rawData.get() & 0xFF;
if (rawData.remaining() < adLength) break;
parseAdvertisementData(advData, adType, adLength, rawData.slice().order(ByteOrder.LITTLE_ENDIAN));
rawData.position(rawData.position() + adLength);
}
return advData;
}

private static void parseAdvertisementData(AdvertisementData advData, int adType, int adLength, ByteBuffer data) {
switch (adType) {
case 0xFF:
parseManufacturerData(advData, adLength, data);
break;

case 0x02:
case 0x03:
parseServiceUUIDs(advData, adLength, data, 2);
break;
case 0x04:
case 0x05:
parseServiceUUIDs(advData, adLength, data, 4);
break;
case 0x06:
case 0x07:
parseServiceUUIDs(advData, adLength, data, 16);
break;

case 0x08:
case 0x09:
parseLocalName(advData, adType, adLength, data);
break;

case 0x0A:
parseTxPowerLevel(advData, adLength, data);
break;

case 0x14:
parseSolicitedServiceUUIDs(advData, adLength, data, 2);
break;
case 0x1F:
parseSolicitedServiceUUIDs(advData, adLength, data, 4);
break;
case 0x15:
parseSolicitedServiceUUIDs(advData, adLength, data, 16);
break;

case 0x16:
parseServiceData(advData, adLength, data, 2);
break;
case 0x20:
parseServiceData(advData, adLength, data, 4);
break;
case 0x21:
parseServiceData(advData, adLength, data, 16);
break;
}
}

private static void parseLocalName(AdvertisementData advData, int adType, int adLength, ByteBuffer data) {
// Complete local name is preferred over short local name.
if (advData.localName == null || adType == 0x09) {
byte[] bytes = new byte[adLength];
data.get(bytes, 0, adLength);
advData.localName = new String(bytes, Charset.forName("UTF-8"));
}
}

private static UUID parseUUID(ByteBuffer data, int uuidLength) {
long lsb;
long msb;
switch (uuidLength) {
case 2:
msb = (((long) data.getShort() & 0xFFFF) << 32) + BLUETOOTH_BASE_UUID_MSB;
lsb = BLUETOOTH_BASE_UUID_LSB;
break;
case 4:
msb = ((long) data.getInt() << 32) + BLUETOOTH_BASE_UUID_MSB;
lsb = BLUETOOTH_BASE_UUID_LSB;
break;
case 16:
lsb = data.getLong();
msb = data.getLong();
break;
default:
data.position(data.position() + uuidLength);
return null;
}
return new UUID(msb, lsb);
}

private static void parseSolicitedServiceUUIDs(AdvertisementData advData, int adLength, ByteBuffer data, int uuidLength) {
if (advData.solicitedServiceUUIDs == null) advData.solicitedServiceUUIDs = new ArrayList<>();
while (data.remaining() >= uuidLength && data.position() < adLength) {
advData.solicitedServiceUUIDs.add(parseUUID(data, uuidLength));
}
}

private static void parseServiceUUIDs(AdvertisementData advData, int adLength, ByteBuffer data, int uuidLength) {
if (advData.serviceUUIDs == null) advData.serviceUUIDs = new ArrayList<>();
while (data.remaining() >= uuidLength && data.position() < adLength) {
advData.serviceUUIDs.add(parseUUID(data, uuidLength));
}
}

private static void parseServiceData(AdvertisementData advData, int adLength, ByteBuffer data, int uuidLength) {
if (adLength < uuidLength) return;
if (advData.serviceData == null) advData.serviceData = new HashMap<>();
UUID serviceUUID = parseUUID(data, uuidLength);
int serviceDataLength = adLength - uuidLength;
byte[] serviceData = new byte[serviceDataLength];
data.get(serviceData, 0, serviceDataLength);
advData.serviceData.put(serviceUUID, serviceData);
}

private static void parseTxPowerLevel(AdvertisementData advData, int adLength, ByteBuffer data) {
if (adLength != 1) return;
advData.txPowerLevel = (int) data.get();
}

private static void parseManufacturerData(AdvertisementData advData, int adLength, ByteBuffer data) {
if (adLength < 2) return;
advData.manufacturerData = new byte[adLength];
data.get(advData.manufacturerData, 0, adLength);
}

@Override
public String toString() {
return "AdvertisementData{" +
"manufacturerData=" + Arrays.toString(manufacturerData) +
", serviceData=" + serviceData +
", serviceUUIDs=" + serviceUUIDs +
", localName='" + localName + '\'' +
", txPowerLevel=" + txPowerLevel +
", solicitedServiceUUIDs=" + solicitedServiceUUIDs +
", rawScanRecord=" + Arrays.toString(rawScanRecord) +
'}';
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

AdvertisementData that = (AdvertisementData) o;

if (!Arrays.equals(manufacturerData, that.manufacturerData)) return false;
if (!Objects.equals(serviceData, that.serviceData))
return false;
if (!Objects.equals(serviceUUIDs, that.serviceUUIDs))
return false;
if (!Objects.equals(localName, that.localName))
return false;
if (!Objects.equals(txPowerLevel, that.txPowerLevel))
return false;
if (!Objects.equals(solicitedServiceUUIDs, that.solicitedServiceUUIDs))
return false;
return Arrays.equals(rawScanRecord, that.rawScanRecord);
}

@Override
public int hashCode() {
int result = Arrays.hashCode(manufacturerData);
result = 31 * result + (serviceData != null ? serviceData.hashCode() : 0);
result = 31 * result + (serviceUUIDs != null ? serviceUUIDs.hashCode() : 0);
result = 31 * result + (localName != null ? localName.hashCode() : 0);
result = 31 * result + (txPowerLevel != null ? txPowerLevel.hashCode() : 0);
result = 31 * result + (solicitedServiceUUIDs != null ? solicitedServiceUUIDs.hashCode() : 0);
result = 31 * result + Arrays.hashCode(rawScanRecord);
return result;
}
}
Loading

0 comments on commit 33d1b30

Please sign in to comment.