Skip to content

Commit

Permalink
feat: add support for missing scan closures
Browse files Browse the repository at this point in the history
  • Loading branch information
0x7061 committed Dec 10, 2024
1 parent b98e68c commit 37e71f5
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,30 +197,33 @@ class AbrevvaPluginBLE : Plugin() {
}

@PluginMethod
fun requestLEScan(call: PluginCall) {
fun startScan(call: PluginCall) {
val macFilter = call.getString("macFilter", null)
val timeout = call.getFloat("timeout", 15000.0F)!!.toLong()

this.manager.startScan({ device ->
Logger.debug(tag, "Found device: ${device.address}")

Logger.debug(tag, "onScanResult(): device found: ${device.address}")
val bleDevice = getBleDeviceData(device)
try {
notifyListeners("onScanResult", bleDevice)
} catch (e: Exception) {
Logger.error(tag, "requestLEScan()", e)
Logger.error(tag, "onScanResult()", e)
}
}, { success ->
if (success) {
call.resolve()
} else {
call.reject("requestLEScan(): failed to start")
}
}, {}, macFilter, false, timeout)
val data = JSObject()
data.put("value", success)
notifyListeners("onScanStart", data)
call.resolve()
}, { success ->
val data = JSObject()
data.put("value", success)
notifyListeners("onScanStop", data)
call.resolve()
}, macFilter, false, timeout)
}

@PluginMethod
fun stopLEScan(call: PluginCall) {
fun stopScan(call: PluginCall) {
manager.stopScan()
call.resolve()
}
Expand Down
45 changes: 29 additions & 16 deletions src/plugins/ble/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { AbrevvaBLE } from "./plugin";

interface AbrevvaBLEClientWithPrivate extends AbrevvaBLEClientInterface {
eventListeners: Map<string, PluginListenerHandle>;
scanListener: PluginListenerHandle | null;
scanResultListener: PluginListenerHandle | null;
scanStartListener: PluginListenerHandle | null;
scanStopListener: PluginListenerHandle | null;
}

jest.mock("@capacitor/core", () => {
Expand All @@ -30,8 +32,8 @@ jest.mock("./plugin", () => {
startEnabledNotifications: jest.fn(),
stopEnabledNotifications: jest.fn(),
requestDevice: jest.fn(),
requestLEScan: jest.fn(),
stopLEScan: jest.fn(),
startScan: jest.fn(),
stopScan: jest.fn(),
connect: jest.fn(),
createBond: jest.fn(),
isBonded: jest.fn(),
Expand Down Expand Up @@ -125,30 +127,41 @@ describe("AbrevvaBLEClient", () => {
).toBeUndefined();
});

it("should run requestLEScan", async () => {
const mockCallback = jest.fn();
const mockScanListener = {
it("should run startScan", async () => {
const mockScanResultCallback = jest.fn();
const mockScanStartCallback = jest.fn();
const mockScanStopCallback = jest.fn();

const mockScanResultListener = {
remove: jest.fn(),
};
(AbrevvaBLE.addListener as jest.Mock).mockReturnValue(mockScanListener);
await AbrevvaBLEClient.requestLEScan({}, mockCallback);

(AbrevvaBLE.addListener as jest.Mock).mockReturnValue(mockScanResultListener);
await AbrevvaBLEClient.startScan({}, mockScanResultCallback, mockScanStartCallback, mockScanStopCallback);

expect(AbrevvaBLE.addListener).toHaveBeenCalledWith("onScanResult", expect.any(Function));
expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanListener).toBe(mockScanListener);
expect(AbrevvaBLE.requestLEScan).toHaveBeenCalledTimes(1);
expect(AbrevvaBLE.addListener).toHaveBeenCalledWith("onScanStart", expect.any(Function));
expect(AbrevvaBLE.addListener).toHaveBeenCalledWith("onScanStop", expect.any(Function));

expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanResultListener).toBe(
mockScanResultListener,
);

expect(AbrevvaBLE.startScan).toHaveBeenCalledTimes(1);
});

it("should run stopLEScan", async () => {
it("should run stopScan", async () => {
const mockCallback = jest.fn();
const mockScanListener = {
remove: jest.fn(),
};
(AbrevvaBLE.addListener as jest.Mock).mockReturnValue(mockScanListener);
await AbrevvaBLEClient.requestLEScan({}, mockCallback);
expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanListener).toBe(mockScanListener);
await AbrevvaBLEClient.stopLEScan();
await AbrevvaBLEClient.startScan({}, mockCallback);
expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanResultListener).toBe(mockScanListener);
await AbrevvaBLEClient.stopScan();
expect(mockScanListener.remove).toHaveBeenCalledTimes(1);
expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanListener).toBe(null);
expect(AbrevvaBLE.stopLEScan).toHaveBeenCalledTimes(1);
expect((AbrevvaBLEClient as unknown as AbrevvaBLEClientWithPrivate).scanResultListener).toBe(null);
expect(AbrevvaBLE.stopScan).toHaveBeenCalledTimes(1);
});

it("should run connect without disconnect callback", async () => {
Expand Down
51 changes: 39 additions & 12 deletions src/plugins/ble/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ export interface AbrevvaBLEClientInterface {
openLocationSettings(): Promise<void>;
openBluetoothSettings(): Promise<void>;
openAppSettings(): Promise<void>;
requestLEScan(options: BleScannerOptions, callback: (result: BleDevice) => void): Promise<void>;
stopLEScan(): Promise<void>;
startScan(
options: BleScannerOptions,
onScanResult: (result: BleDevice) => void,
onScanStart?: (success: boolean) => void,
onScanStop?: (success: boolean) => void,
): Promise<void>;
stopScan(): Promise<void>;
connect(deviceId: string, onDisconnect?: (deviceId: string) => void, options?: TimeoutOptions): Promise<void>;
disconnect(deviceId: string): Promise<void>;
read(deviceId: string, service: string, characteristic: string, options?: TimeoutOptions): Promise<DataView>;
Expand Down Expand Up @@ -46,7 +51,10 @@ export interface AbrevvaBLEClientInterface {
}

class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
private scanListener: PluginListenerHandle | null = null;
private scanResultListener: PluginListenerHandle | null = null;
private scanStartListener: PluginListenerHandle | null = null;
private scanStopListener: PluginListenerHandle | null = null;

private eventListeners = new Map<string, PluginListenerHandle>();
private queue = getQueue(true);

Expand Down Expand Up @@ -109,21 +117,40 @@ class AbrevvaBLEClientClass implements AbrevvaBLEClientInterface {
});
}

async requestLEScan(options: BleScannerOptions, callback: (result: BleDevice) => void): Promise<void> {
async startScan(
options: BleScannerOptions,
onScanResult: (result: BleDevice) => void,
onScanStart?: (success: boolean) => void,
onScanStop?: (success: boolean) => void,
): Promise<void> {
await this.queue(async () => {
await this.scanListener?.remove();
this.scanListener = AbrevvaBLE.addListener("onScanResult", (device: BleDevice) => {
callback(device);
await this.scanResultListener?.remove();
this.scanResultListener = AbrevvaBLE.addListener("onScanResult", (device: BleDevice) => {
onScanResult(device);
});
await AbrevvaBLE.requestLEScan(options);
if (onScanStart) {
await this.scanStartListener?.remove();
this.scanStartListener = AbrevvaBLE.addListener("onScanStart", (result) => {
onScanStart(result.value);
this.scanStartListener?.remove();
});
}
if (onScanStop) {
await this.scanStopListener?.remove();
this.scanStopListener = AbrevvaBLE.addListener("onScanStop", (result) => {
onScanStop(result.value);
this.scanStopListener?.remove();
});
}
await AbrevvaBLE.startScan(options);
});
}

async stopLEScan(): Promise<void> {
async stopScan(): Promise<void> {
await this.queue(async () => {
await this.scanListener?.remove();
this.scanListener = null;
await AbrevvaBLE.stopLEScan();
await this.scanResultListener?.remove();
this.scanResultListener = null;
await AbrevvaBLE.stopScan();
});
}

Expand Down
6 changes: 4 additions & 2 deletions src/plugins/ble/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,13 @@ export interface AbrevvaBLEInterface {
openLocationSettings(): Promise<void>;
openBluetoothSettings(): Promise<void>;
openAppSettings(): Promise<void>;
requestLEScan(options?: BleScannerOptions): Promise<void>;
stopLEScan(): Promise<void>;
startScan(options?: BleScannerOptions): Promise<void>;
stopScan(): Promise<void>;
addListener(eventName: "onEnabledChanged", listenerFunc: (result: BooleanResult) => void): PluginListenerHandle;
addListener(eventName: string, listenerFunc: (event: ReadResult) => void): PluginListenerHandle;
addListener(eventName: "onScanResult", listenerFunc: (result: BleDevice) => void): PluginListenerHandle;
addListener(eventName: "onScanStart", listenerFunc: (success: BooleanResult) => void): PluginListenerHandle;
addListener(eventName: "onScanStop", listenerFunc: (success: BooleanResult) => void): PluginListenerHandle;
connect(options: DeviceIdOptions & TimeoutOptions): Promise<void>;
disconnect(options: DeviceIdOptions): Promise<void>;
read(options: ReadOptions & TimeoutOptions): Promise<ReadResult>;
Expand Down

0 comments on commit 37e71f5

Please sign in to comment.