org.fz.nettyx.util.BtFinder Maven / Gradle / Ivy
package org.fz.nettyx.util;
import cn.hutool.core.text.CharSequenceUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import javax.bluetooth.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
/**
* @author fengbinbin
* @version 1.0
* @since 2024/5/30 11:04
*/
@UtilityClass
public final class BtFinder {
private static final InternalLogger log = InternalLoggerFactory.getInstance(BtFinder.class);
@NoArgsConstructor
public static class DeviceFinder {
private final Object completedTag = new Object();
private final List devices = new ArrayList<>(64);
private DiscoveryListener listener = new DiscoveryListenerAdapter() {
@Override
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
devices.add(btDevice);
}
@Override
public void inquiryCompleted(int discType) {
synchronized (completedTag) {
completedTag.notifyAll();
}
}
};
public DeviceFinder(DiscoveryListener listener) {
this.listener = listener;
}
public List getDevices() {
return getDevices(device -> true);
}
@SneakyThrows({ InterruptedException.class })
public List getDevices(Predicate condition) {
try {
devices.clear();
synchronized (completedTag) {
DiscoveryAgent discoveryAgent = LocalDevice.getLocalDevice().getDiscoveryAgent();
boolean started = discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
if (started) {
completedTag.wait();
discoveryAgent.cancelInquiry(listener);
}
}
devices.removeIf(condition.negate());
} catch (BluetoothStateException stateException) {
log.error("bluetooth state is illegal, please check");
return Collections.emptyList();
}
return devices;
}
}
@RequiredArgsConstructor
public static class ServiceFinder {
private static final int DEFAULT_ATTR_ID = 0x0100;
private final Object completedTag = new Object();
private final List services = new ArrayList<>(32);
private DiscoveryListener listener = new DiscoveryListenerAdapter() {
@Override
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
for (ServiceRecord serviceRecord : servRecord) {
String url = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
if (CharSequenceUtil.isEmpty(url)) {
continue;
}
services.add(url);
}
}
@Override
public void serviceSearchCompleted(int transID, int respCode) {
synchronized (completedTag) {
completedTag.notifyAll();
}
}
};
public ServiceFinder(DiscoveryListener listener) {
this.listener = listener;
}
public List getServices(RemoteDevice btDevice, String serviceUUID) throws IOException, InterruptedException {
return getServices(btDevice, serviceUUID, s -> true);
}
public List getServices(RemoteDevice btDevice, String serviceUUID, Predicate condition) throws IOException, InterruptedException {
UUID[] searchUuidSet = new UUID[]{ new UUID(serviceUUID, false) };
synchronized (completedTag) {
LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(new int[]{ DEFAULT_ATTR_ID }, searchUuidSet, btDevice, listener);
completedTag.wait();
}
services.removeIf(condition.negate());
return services;
}
}
abstract static class DiscoveryListenerAdapter implements DiscoveryListener {
@Override
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
}
@Override
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
}
@Override
public void serviceSearchCompleted(int transID, int respCode) {
}
@Override
public void inquiryCompleted(int discType) {
}
}
}