mirror of
https://github.com/RfidResearchGroup/ChameleonBLEAPI.git
synced 2026-05-12 11:20:47 -07:00
Add files via upload
This commit is contained in:
@@ -1,116 +1,116 @@
|
||||
package com.proxgrind.chameleon.utils.device.ble;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.proxgrind.chameleon.utils.system.LogUtils;
|
||||
import com.proxgrind.chameleon.utils.tools.ArrayUtils;
|
||||
import com.proxgrind.chameleon.utils.tools.HexUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class BLERawUtils {
|
||||
// 解析!
|
||||
public static Details[] parse(byte[] raw) {
|
||||
ArrayList<Details> details = new ArrayList<>(3);
|
||||
// 02 01 02
|
||||
// 02 0A 04
|
||||
// 03 02 F0 FF
|
||||
// 0C FF 5A 69 63 6F 78 DC 0D 30 02 74 CC
|
||||
// 06 09 58 54 34 32 33
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000
|
||||
for (int i = 0; i < raw.length; ) {
|
||||
// 分三段取长度字节!
|
||||
int len = raw[i];
|
||||
// 必定超过一个字节!
|
||||
if (len > 1) {
|
||||
// 足够一帧数据!
|
||||
if (len < raw.length + i) {
|
||||
// 建立存储对象!
|
||||
Details tmp = new Details();
|
||||
tmp.setLength(len);
|
||||
tmp.setType(raw[i + 1]);
|
||||
// 建立一个存放值字节的数组,长度减去类型可以得到有效的值长度!
|
||||
byte[] bytes = new byte[len - 1];
|
||||
// 进行值拷贝!
|
||||
try {
|
||||
System.arraycopy(raw, i + 2, bytes, 0, bytes.length);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 存放进对象中!
|
||||
tmp.setValue(bytes);
|
||||
// 添加到结果集!
|
||||
details.add(tmp);
|
||||
i += (len + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ArrayUtils.list2Arr(details);
|
||||
}
|
||||
|
||||
// 按照某个类型搜索值
|
||||
public static Details find(int typeByte, Details[] details) {
|
||||
if (details != null) {
|
||||
for (Details tmp : details) {
|
||||
/*LogUtils.d("len: "
|
||||
+ HexUtil.toHexString(tmp.getLength()) + ", "
|
||||
+ "type: " + HexUtil.toHexString(tmp.getType()) + ", "
|
||||
+ "value: " + HexUtil.toHexString(tmp.getValue()) + ", "
|
||||
+ "str: " + new String(tmp.getValue())
|
||||
);*/
|
||||
if (tmp.getType() == typeByte) {
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 直接获得某个类型的值!
|
||||
public static Details find(int typeByte, byte[] raw) {
|
||||
// 进行raw分包查询!
|
||||
BLERawUtils.Details[] details = BLERawUtils.parse(raw);
|
||||
return BLERawUtils.find(typeByte, details);
|
||||
}
|
||||
|
||||
// 存放详细信息的类!
|
||||
public static class Details {
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
private void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private void setValue(byte[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
int length;
|
||||
int type;
|
||||
byte[] value;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Type=" + type + "]" + "[Value=]" + HexUtil.toHexString(value) + "]" + "[Length=" + length + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.proxgrind.chameleon.utils.device.ble;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.proxgrind.chameleon.utils.system.LogUtils;
|
||||
import com.proxgrind.chameleon.utils.tools.ArrayUtils;
|
||||
import com.proxgrind.chameleon.utils.tools.HexUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class BLERawUtils {
|
||||
// 解析!
|
||||
public static Details[] parse(byte[] raw) {
|
||||
ArrayList<Details> details = new ArrayList<>(3);
|
||||
// 02 01 02
|
||||
// 02 0A 04
|
||||
// 03 02 F0 FF
|
||||
// 0C FF 5A 69 63 6F 78 DC 0D 30 02 74 CC
|
||||
// 06 09 58 54 34 32 33
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000
|
||||
for (int i = 0; i < raw.length; ) {
|
||||
// 分三段取长度字节!
|
||||
int len = raw[i];
|
||||
// 必定超过一个字节!
|
||||
if (len > 1) {
|
||||
// 足够一帧数据!
|
||||
if (len < raw.length + i) {
|
||||
// 建立存储对象!
|
||||
Details tmp = new Details();
|
||||
tmp.setLength(len);
|
||||
tmp.setType(raw[i + 1]);
|
||||
// 建立一个存放值字节的数组,长度减去类型可以得到有效的值长度!
|
||||
byte[] bytes = new byte[len - 1];
|
||||
// 进行值拷贝!
|
||||
try {
|
||||
System.arraycopy(raw, i + 2, bytes, 0, bytes.length);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 存放进对象中!
|
||||
tmp.setValue(bytes);
|
||||
// 添加到结果集!
|
||||
details.add(tmp);
|
||||
i += (len + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ArrayUtils.list2Arr(details);
|
||||
}
|
||||
|
||||
// 按照某个类型搜索值
|
||||
public static Details find(int typeByte, Details[] details) {
|
||||
if (details != null) {
|
||||
for (Details tmp : details) {
|
||||
/*LogUtils.d("len: "
|
||||
+ HexUtil.toHexString(tmp.getLength()) + ", "
|
||||
+ "type: " + HexUtil.toHexString(tmp.getType()) + ", "
|
||||
+ "value: " + HexUtil.toHexString(tmp.getValue()) + ", "
|
||||
+ "str: " + new String(tmp.getValue())
|
||||
);*/
|
||||
if (tmp.getType() == typeByte) {
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 直接获得某个类型的值!
|
||||
public static Details find(int typeByte, byte[] raw) {
|
||||
// 进行raw分包查询!
|
||||
BLERawUtils.Details[] details = BLERawUtils.parse(raw);
|
||||
return BLERawUtils.find(typeByte, details);
|
||||
}
|
||||
|
||||
// 存放详细信息的类!
|
||||
public static class Details {
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
private void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private void setValue(byte[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
int length;
|
||||
int type;
|
||||
byte[] value;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Type=" + type + "]" + "[Value=]" + HexUtil.toHexString(value) + "]" + "[Length=" + length + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.proxgrind.chameleon.utils.device.ble;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import com.proxgrind.devices.BleSerialControl;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static android.bluetooth.BluetoothDevice.ACTION_BOND_STATE_CHANGED;
|
||||
|
||||
/**
|
||||
* 蓝牙状态监听!
|
||||
*/
|
||||
public class BluetoothUtils {
|
||||
public static BroadcastReceiver startStatusReceicer(Context context, OnStatusChange callback) {
|
||||
if (callback != null) {
|
||||
if (!check(context, callback)) return null;
|
||||
// 创建广播!
|
||||
BroadcastReceiver blueToothValueReceiver = new BroadcastReceiver() {
|
||||
public int DEFAULT_VALUE_BULUETOOTH = 1000;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
|
||||
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, DEFAULT_VALUE_BULUETOOTH);
|
||||
switch (state) {
|
||||
case BluetoothAdapter.STATE_OFF:
|
||||
callback.onStateOff(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_ON:
|
||||
callback.onStateOn(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_TURNING_ON:
|
||||
callback.onStateTurningOn(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_TURNING_OFF:
|
||||
callback.onStateTurningOff(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_CONNECTING:
|
||||
callback.onConnecting(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_CONNECTED:
|
||||
callback.onConnected(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_DISCONNECTING:
|
||||
callback.onDisconnecting(context);
|
||||
break;
|
||||
case BluetoothAdapter.STATE_DISCONNECTED:
|
||||
callback.onDisconnected(context);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//注册广播,蓝牙状态监听
|
||||
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
context.registerReceiver(blueToothValueReceiver, filter);
|
||||
return blueToothValueReceiver;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BroadcastReceiver startActionReceiver(Context context, OnActionChange callback) {
|
||||
if (callback != null) {
|
||||
if (!check(context, callback)) return null;
|
||||
// 创建广播!
|
||||
BroadcastReceiver blueToothValueReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
|
||||
callback.onScanStarted(context);
|
||||
}
|
||||
if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
|
||||
callback.onScanFinished(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
//注册广播,蓝牙状态监听
|
||||
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
|
||||
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
|
||||
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
|
||||
context.registerReceiver(blueToothValueReceiver, filter);
|
||||
return blueToothValueReceiver;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean check(Context context, OnBlueNoSupport callback) {
|
||||
BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
if (manager == null || manager.getAdapter() == null) {
|
||||
callback.onBlueNoSupported(context);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void stop(BroadcastReceiver receiver, Context context) {
|
||||
try {
|
||||
context.unregisterReceiver(receiver);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class OnBlueNoSupport {
|
||||
public void onBlueNoSupported(Context context) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnStatusChange extends OnBlueNoSupport {
|
||||
public void onStateOff(Context context) {
|
||||
}
|
||||
|
||||
public void onStateOn(Context context) {
|
||||
}
|
||||
|
||||
public void onStateTurningOn(Context context) {
|
||||
}
|
||||
|
||||
public void onStateTurningOff(Context context) {
|
||||
}
|
||||
|
||||
public void onConnecting(Context context) {
|
||||
}
|
||||
|
||||
public void onConnected(Context context) {
|
||||
}
|
||||
|
||||
public void onDisconnecting(Context context) {
|
||||
}
|
||||
|
||||
public void onDisconnected(Context context) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnActionChange extends OnBlueNoSupport {
|
||||
public void onScanStarted(Context context) {
|
||||
}
|
||||
|
||||
public void onScanFinished(Context context) {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBlueOpen(Context context) {
|
||||
return BleSerialControl.get().getAdapter().isEnabled();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.proxgrind.chameleon.utils.device.ble;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ClsUtils {
|
||||
/**
|
||||
* 与设备配对 参考源码:platform/packages/apps/Settings.git
|
||||
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
|
||||
*/
|
||||
@SuppressLint("ObsoleteSdkInt")
|
||||
static public boolean createBond(Class btClass, BluetoothDevice btDevice) {
|
||||
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) return false;
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
Method createBondMethod = btClass.getMethod("createBond");
|
||||
Object obj = createBondMethod.invoke(btDevice);
|
||||
return obj instanceof Boolean ? (Boolean) obj : false;
|
||||
} else {
|
||||
return btDevice.createBond();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 与设备解除配对 参考源码:platform/packages/apps/Settings.git
|
||||
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
|
||||
*/
|
||||
static public boolean removeBond(Class<?> btClass, BluetoothDevice btDevice) {
|
||||
try {
|
||||
Method removeBondMethod = btClass.getMethod("removeBond");
|
||||
Object obj = removeBondMethod.invoke(btDevice);
|
||||
return obj instanceof Boolean ? (Boolean) obj : false;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean setPin(Class<? extends BluetoothDevice> btClass, BluetoothDevice btDevice, String str) throws Exception {
|
||||
byte[] key = str != null ? str.getBytes() : null;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
Method removeBondMethod = btClass.getDeclaredMethod("setPin", byte[].class);
|
||||
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[]{key});
|
||||
Log.d("returnValue", "" + returnValue);
|
||||
} catch (SecurityException e) {
|
||||
// throw new RuntimeException(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// throw new RuntimeException(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return btDevice.setPin(key);
|
||||
}
|
||||
}
|
||||
|
||||
// 取消用户输入
|
||||
static public boolean cancelPairingUserInput(Class<?> btClass, BluetoothDevice device) throws Exception {
|
||||
Method createBondMethod = btClass.getMethod("cancelPairingUserInput");
|
||||
// cancelBondProcess(btClass, device);
|
||||
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
|
||||
return returnValue.booleanValue();
|
||||
}
|
||||
|
||||
// 取消配对
|
||||
static public boolean cancelBondProcess(Class<?> btClass, BluetoothDevice device) throws Exception {
|
||||
Method createBondMethod = btClass.getMethod("cancelBondProcess");
|
||||
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
|
||||
return returnValue.booleanValue();
|
||||
}
|
||||
|
||||
//确认配对
|
||||
static public void setPairingConfirmation(Class<?> btClass, BluetoothDevice device, boolean isConfirm) throws Exception {
|
||||
Method setPairingConfirmation = btClass.getDeclaredMethod("setPairingConfirmation", boolean.class);
|
||||
setPairingConfirmation.invoke(device, isConfirm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clsShow
|
||||
*/
|
||||
static public void printAllInform(Class clsShow) {
|
||||
try {
|
||||
// 取得所有方法
|
||||
Method[] hideMethod = clsShow.getMethods();
|
||||
int i = 0;
|
||||
for (; i < hideMethod.length; i++) {
|
||||
Log.e("method name", hideMethod[i].getName() + ";and the i is:"
|
||||
+ i);
|
||||
}
|
||||
// 取得所有常量
|
||||
Field[] allFields = clsShow.getFields();
|
||||
for (i = 0; i < allFields.length; i++) {
|
||||
Log.e("Field name", allFields[i].getName());
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
// throw new RuntimeException(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// throw new RuntimeException(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新设备的缓存!
|
||||
*/
|
||||
static public void refreshDeviceCache(BluetoothGatt gatt) {
|
||||
if (gatt == null) return;
|
||||
/*
|
||||
* If the device is bonded this is up to the Service Changed characteristic to notify Android that the services has changed.
|
||||
* There is no need for this trick in that case.
|
||||
* If not bonded, the Android should not keep the services cached when the Service Changed characteristic is present in the target device database.
|
||||
* However, due to the Android bug (still exists in Android 5.0.1), it is keeping them anyway and the only way to clear services is by using this hidden refresh method.
|
||||
*/
|
||||
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
|
||||
/*
|
||||
* There is a refresh() method in BluetoothGatt class but for now it's hidden. We will call it using reflections.
|
||||
*/
|
||||
try {
|
||||
//noinspection JavaReflectionMemberAccess
|
||||
final Method refresh = gatt.getClass().getMethod("refresh");
|
||||
refresh.invoke(gatt);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user