java
复制代码
// PermissionUtils.java
public class PermissionUtils {
public static final int REQUEST_CODE_BLUETOOTH_PERMISSIONS = 1001;
public static final int REQUEST_CODE_LOCATION_PERMISSIONS = 1002;
// 检查并请求蓝牙权限
public static boolean checkAndRequestBluetoothPermissions(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12+ 需要 BLUETOOTH_SCAN 和 BLUETOOTH_CONNECT
List<String> permissionsNeeded = new ArrayList<>();
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN);
}
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.BLUETOOTH_CONNECT);
}
if (!permissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(activity,
permissionsNeeded.toArray(new String[0]),
REQUEST_CODE_BLUETOOTH_PERMISSIONS);
return false;
}
} else {
// Android 11及以下需要传统蓝牙权限
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity,
new String[] {
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
},
REQUEST_CODE_BLUETOOTH_PERMISSIONS);
return false;
}
}
return true;
}
// 检查并请求位置权限
public static boolean checkAndRequestLocationPermissions(Activity activity) {
// Android 6.0+ 需要位置权限进行蓝牙扫描
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
List<String> permissionsNeeded = new ArrayList<>();
// 检查精确位置权限
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
// 检查粗略位置权限
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
// Android 10+ 如果需要在后台扫描,需要后台位置权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 注意:后台位置权限需要单独请求
}
}
if (!permissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(activity,
permissionsNeeded.toArray(new String[0]),
REQUEST_CODE_LOCATION_PERMISSIONS);
return false;
}
}
return true;
}
// 检查是否所有必要权限都已授予
public static boolean hasAllRequiredPermissions(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
return ContextCompat.checkSelfPermission(context,
Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(context,
Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
} else {
return ContextCompat.checkSelfPermission(context,
Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(context,
Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
}
// 解释为什么需要权限
public static void showPermissionRationale(Activity activity, String permission) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("需要权限")
.setMessage(getPermissionRationaleMessage(permission))
.setPositiveButton("确定", null)
.show();
}
private static String getPermissionRationaleMessage(String permission) {
switch (permission) {
case Manifest.permission.BLUETOOTH_SCAN:
return "需要蓝牙扫描权限来发现附近的蓝牙设备";
case Manifest.permission.BLUETOOTH_CONNECT:
return "需要蓝牙连接权限来配对和连接蓝牙设备";
case Manifest.permission.ACCESS_FINE_LOCATION:
return "需要位置权限来扫描蓝牙设备,这是Android系统的要求";
default:
return "需要此权限来使用蓝牙功能";
}
}
}
java
复制代码
// DeviceDiscoveryActivity.java
public class DeviceDiscoveryActivity extends AppCompatActivity {
private static final String TAG = "DeviceDiscovery";
// UI组件
private Button btnScan;
private Button btnStop;
private Button btnEnableBluetooth;
private TextView tvStatus;
private ProgressBar progressBar;
private RecyclerView recyclerView;
private TextView tvEmptyView;
// 蓝牙相关
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bleScanner;
private DeviceListAdapter deviceAdapter;
private List<BluetoothDevice> deviceList = new ArrayList<>();
private Map<String, DeviceInfo> deviceInfoMap = new HashMap<>();
// 扫描状态
private boolean isScanning = false;
private boolean isClassicScanning = false;
private long scanStartTime = 0;
// 广播接收器
private final BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) return;
switch (action) {
case BluetoothAdapter.ACTION_STATE_CHANGED:
handleBluetoothStateChange(intent);
break;
case BluetoothDevice.ACTION_FOUND:
handleDeviceFound(intent);
break;
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
handleDiscoveryStarted();
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
handleDiscoveryFinished();
break;
case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
handleBondStateChanged(intent);
break;
case BluetoothDevice.ACTION_ACL_CONNECTED:
case BluetoothDevice.ACTION_ACL_DISCONNECTED:
handleConnectionStateChanged(intent, action);
break;
}
}
};
// BLE扫描回调
private ScanCallback bleScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
handleBleDeviceFound(result);
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
for (ScanResult result : results) {
handleBleDeviceFound(result);
}
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
handleBleScanFailed(errorCode);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_discovery);
initViews();
initBluetooth();
setupRecyclerView();
// 检查并请求权限
if (!checkPermissions()) {
requestPermissions();
} else {
setupBluetooth();
}
}
private void initViews() {
btnScan = findViewById(R.id.btn_scan);
btnStop = findViewById(R.id.btn_stop);
btnEnableBluetooth = findViewById(R.id.btn_enable_bluetooth);
tvStatus = findViewById(R.id.tv_status);
progressBar = findViewById(R.id.progress_bar);
recyclerView = findViewById(R.id.recycler_view);
tvEmptyView = findViewById(R.id.tv_empty);
btnScan.setOnClickListener(v -> startScanning());
btnStop.setOnClickListener(v -> stopScanning());
btnEnableBluetooth.setOnClickListener(v -> enableBluetooth());
updateUIState();
}
private void initBluetooth() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
showErrorDialog("设备不支持蓝牙");
finish();
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
bleScanner = bluetoothAdapter.getBluetoothLeScanner();
}
}
private void setupRecyclerView() {
deviceAdapter = new DeviceListAdapter(deviceList, new DeviceListAdapter.OnDeviceClickListener() {
@Override
public void onDeviceClick(BluetoothDevice device) {
showDeviceOptions(device);
}
@Override
public void onPairClick(BluetoothDevice device) {
startPairing(device);
}
@Override
public void onConnectClick(BluetoothDevice device) {
connectToDevice(device);
}
});
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(deviceAdapter);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
}
private void registerBluetoothReceivers() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(bluetoothReceiver, filter);
}
private void unregisterBluetoothReceivers() {
try {
unregisterReceiver(bluetoothReceiver);
} catch (IllegalArgumentException e) {
// 忽略未注册的异常
}
}
private boolean checkPermissions() {
return PermissionUtils.hasAllRequiredPermissions(this);
}
private void requestPermissions() {
PermissionUtils.checkAndRequestBluetoothPermissions(this);
PermissionUtils.checkAndRequestLocationPermissions(this);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PermissionUtils.REQUEST_CODE_BLUETOOTH_PERMISSIONS ||
requestCode == PermissionUtils.REQUEST_CODE_LOCATION_PERMISSIONS) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
setupBluetooth();
} else {
showPermissionDeniedDialog();
}
}
}
private void setupBluetooth() {
registerBluetoothReceivers();
loadBondedDevices();
updateUIState();
}
private void updateUIState() {
boolean isBluetoothEnabled = bluetoothAdapter != null && bluetoothAdapter.isEnabled();
boolean canScan = isBluetoothEnabled && !isScanning;
btnEnableBluetooth.setVisibility(isBluetoothEnabled ? View.GONE : View.VISIBLE);
btnScan.setEnabled(canScan);
btnStop.setVisibility(isScanning ? View.VISIBLE : View.GONE);
progressBar.setVisibility(isScanning ? View.VISIBLE : View.GONE);
if (isScanning) {
long elapsedSeconds = (System.currentTimeMillis() - scanStartTime) / 1000;
tvStatus.setText(String.format("扫描中... %ds", elapsedSeconds));
} else {
tvStatus.setText(isBluetoothEnabled ? "就绪" : "蓝牙未启用");
}
tvEmptyView.setVisibility(deviceList.isEmpty() ? View.VISIBLE : View.GONE);
recyclerView.setVisibility(deviceList.isEmpty() ? View.GONE : View.VISIBLE);
}
private void loadBondedDevices() {
if (bluetoothAdapter == null) return;
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
addOrUpdateDevice(device, DeviceType.CLASSIC, -1, true);
}
}
private void startScanning() {
if (!checkPermissions()) {
requestPermissions();
return;
}
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Toast.makeText(this, "请先启用蓝牙", Toast.LENGTH_SHORT).show();
return;
}
clearDeviceList();
isScanning = true;
scanStartTime = System.currentTimeMillis();
// 同时开始经典蓝牙扫描和BLE扫描
startClassicBluetoothScan();
startBleScan();
// 设置扫描超时(30秒)
new Handler(Looper.getMainLooper()).postDelayed(this::stopScanning, 30000);
updateUIState();
Toast.makeText(this, "开始扫描设备", Toast.LENGTH_SHORT).show();
}
private void startClassicBluetoothScan() {
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
isClassicScanning = true;
boolean started = bluetoothAdapter.startDiscovery();
if (!started) {
Log.e(TAG, "经典蓝牙扫描启动失败");
isClassicScanning = false;
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startBleScan() {
if (bleScanner == null) {
bleScanner = bluetoothAdapter.getBluetoothLeScanner();
if (bleScanner == null) {
Log.e(TAG, "BLE扫描器不可用");
return;
}
}
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
.setReportDelay(0)
.build();
List<ScanFilter> filters = new ArrayList<>();
// 可以添加过滤器,例如只扫描特定服务的设备
// filters.add(new ScanFilter.Builder()
// .setServiceUuid(ParcelUuid.fromString(SERVICE_UUID))
// .build());
try {
bleScanner.startScan(filters, settings, bleScanCallback);
} catch (SecurityException e) {
Log.e(TAG, "BLE扫描权限错误", e);
Toast.makeText(this, "缺少BLE扫描权限", Toast.LENGTH_SHORT).show();
} catch (IllegalStateException e) {
Log.e(TAG, "蓝牙未启用", e);
}
}
private void stopScanning() {
if (!isScanning) return;
isScanning = false;
// 停止经典蓝牙扫描
if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
isClassicScanning = false;
// 停止BLE扫描
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && bleScanner != null) {
try {
bleScanner.stopScan(bleScanCallback);
} catch (Exception e) {
Log.e(TAG, "停止BLE扫描失败", e);
}
}
updateUIState();
Toast.makeText(this, "扫描停止", Toast.LENGTH_SHORT).show();
}
private void enableBluetooth() {
if (bluetoothAdapter == null) return;
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "蓝牙已启用", Toast.LENGTH_SHORT).show();
setupBluetooth();
} else {
Toast.makeText(this, "蓝牙启用被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
private void handleBluetoothStateChange(Intent intent) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_ON:
Log.d(TAG, "蓝牙已启用");
loadBondedDevices();
break;
case BluetoothAdapter.STATE_OFF:
Log.d(TAG, "蓝牙已禁用");
clearDeviceList();
stopScanning();
break;
case BluetoothAdapter.STATE_TURNING_ON:
Log.d(TAG, "蓝牙正在启用");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
Log.d(TAG, "蓝牙正在禁用");
break;
}
updateUIState();
}
private void handleDeviceFound(Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device == null) return;
// 获取RSSI信号强度
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
// 获取设备类别(如果可用)
BluetoothClass bluetoothClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
addOrUpdateDevice(device, DeviceType.CLASSIC, rssi, false);
}
private void handleBleDeviceFound(ScanResult result) {
BluetoothDevice device = result.getDevice();
if (device == null) return;
int rssi = result.getRssi();
ScanRecord scanRecord = result.getScanRecord();
String deviceName = device.getName();
// 从广播数据中获取更多信息
List<ParcelUuid> serviceUuids = null;
String manufacturerData = null;
if (scanRecord != null) {
serviceUuids = scanRecord.getServiceUuids();
Map<Integer, byte[]> manufacturerDataMap = scanRecord.getManufacturerSpecificData();
if (manufacturerDataMap != null && !manufacturerDataMap.isEmpty()) {
for (Map.Entry<Integer, byte[]> entry : manufacturerDataMap.entrySet()) {
manufacturerData = bytesToHex(entry.getValue());
break;
}
}
}
DeviceInfo info = new DeviceInfo();
info.device = device;
info.deviceType = DeviceType.BLE;
info.rssi = rssi;
info.lastSeen = System.currentTimeMillis();
info.serviceUuids = serviceUuids;
info.manufacturerData = manufacturerData;
deviceInfoMap.put(device.getAddress(), info);
addOrUpdateDevice(device, DeviceType.BLE, rssi, false);
}
private void handleDiscoveryStarted() {
Log.d(TAG, "经典蓝牙扫描开始");
}
private void handleDiscoveryFinished() {
Log.d(TAG, "经典蓝牙扫描结束");
isClassicScanning = false;
// 如果BLE扫描也结束了,则完全停止扫描
if (!isClassicScanning && isScanning) {
// BLE扫描需要手动停止
}
}
private void handleBleScanFailed(int errorCode) {
Log.e(TAG, "BLE扫描失败,错误码: " + errorCode);
String errorMessage;
switch (errorCode) {
case ScanCallback.SCAN_FAILED_ALREADY_STARTED:
errorMessage = "扫描已在进行中";
break;
case ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
errorMessage = "应用注册失败";
break;
case ScanCallback.SCAN_FAILED_INTERNAL_ERROR:
errorMessage = "内部错误";
break;
case ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED:
errorMessage = "不支持此功能";
break;
case ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES:
errorMessage = "硬件资源不足";
break;
default:
errorMessage = "未知错误";
}
runOnUiThread(() -> Toast.makeText(this, "BLE扫描失败: " + errorMessage,
Toast.LENGTH_SHORT).show());
}
private void handleBondStateChanged(Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
BluetoothDevice.ERROR);
if (device != null) {
// 更新设备列表中的绑定状态
updateDeviceBondState(device, bondState);
}
}
private void handleConnectionStateChanged(Intent intent, String action) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null) {
boolean isConnected = action.equals(BluetoothDevice.ACTION_ACL_CONNECTED);
updateDeviceConnectionState(device, isConnected);
}
}
private void addOrUpdateDevice(BluetoothDevice device, DeviceType type,
int rssi, boolean isBonded) {
String address = device.getAddress();
// 检查是否已存在
boolean exists = false;
for (BluetoothDevice existing : deviceList) {
if (existing.getAddress().equals(address)) {
exists = true;
break;
}
}
if (!exists) {
deviceList.add(device);
}
// 更新设备信息
DeviceInfo info = deviceInfoMap.get(address);
if (info == null) {
info = new DeviceInfo();
}
info.device = device;
info.deviceType = type;
info.rssi = rssi;
info.lastSeen = System.currentTimeMillis();
info.isBonded = isBonded || device.getBondState() == BluetoothDevice.BOND_BONDED;
deviceInfoMap.put(address, info);
// 按信号强度排序
sortDeviceList();
runOnUiThread(() -> {
deviceAdapter.notifyDataSetChanged();
updateUIState();
});
}
private void sortDeviceList() {
Collections.sort(deviceList, (device1, device2) -> {
DeviceInfo info1 = deviceInfoMap.get(device1.getAddress());
DeviceInfo info2 = deviceInfoMap.get(device2.getAddress());
if (info1 == null || info2 == null) return 0;
// 首先按绑定状态排序(已绑定的在前)
if (info1.isBonded != info2.isBonded) {
return info1.isBonded ? -1 : 1;
}
// 然后按信号强度排序(信号强的在前)
if (info1.rssi != info2.rssi) {
return Integer.compare(info2.rssi, info1.rssi);
}
// 最后按设备名称排序
String name1 = device1.getName();
String name2 = device2.getName();
if (name1 == null) name1 = "";
if (name2 == null) name2 = "";
return name1.compareToIgnoreCase(name2);
});
}
private void clearDeviceList() {
// 不清除已绑定的设备
List<BluetoothDevice> bondedDevices = new ArrayList<>();
for (BluetoothDevice device : deviceList) {
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
bondedDevices.add(device);
}
}
deviceList.clear();
deviceList.addAll(bondedDevices);
deviceAdapter.notifyDataSetChanged();
updateUIState();
}
private void updateDeviceBondState(BluetoothDevice device, int bondState) {
DeviceInfo info = deviceInfoMap.get(device.getAddress());
if (info != null) {
info.isBonded = bondState == BluetoothDevice.BOND_BONDED;
}
sortDeviceList();
runOnUiThread(() -> deviceAdapter.notifyDataSetChanged());
}
private void updateDeviceConnectionState(BluetoothDevice device, boolean isConnected) {
DeviceInfo info = deviceInfoMap.get(device.getAddress());
if (info != null) {
info.isConnected = isConnected;
}
runOnUiThread(() -> deviceAdapter.notifyDataSetChanged());
}
private void showDeviceOptions(BluetoothDevice device) {
DeviceInfo info = deviceInfoMap.get(device.getAddress());
if (info == null) return;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("设备选项")
.setMessage(getDeviceInfoString(device, info));
List<CharSequence> options = new ArrayList<>();
List<Runnable> actions = new ArrayList<>();
// 配对/取消配对选项
if (info.isBonded) {
options.add("取消配对");
actions.add(() -> unpairDevice(device));
} else {
options.add("配对");
actions.add(() -> startPairing(device));
}
// 连接选项
if (!info.isConnected && info.isBonded) {
options.add("连接");
actions.add(() -> connectToDevice(device));
} else if (info.isConnected) {
options.add("断开连接");
actions.add(() -> disconnectDevice(device));
}
// 查看详细信息
options.add("详细信息");
actions.add(() -> showDeviceDetails(device, info));
// 忘记设备
options.add("从列表中移除");
actions.add(() -> removeDevice(device));
builder.setItems(options.toArray(new CharSequence[0]),
(dialog, which) -> actions.get(which).run());
builder.setNegativeButton("取消", null);
builder.show();
}
private String getDeviceInfoString(BluetoothDevice device, DeviceInfo info) {
StringBuilder sb = new StringBuilder();
sb.append("名称: ").append(device.getName() != null ? device.getName() : "未知")
.append("\n地址: ").append(device.getAddress())
.append("\n类型: ").append(info.deviceType == DeviceType.BLE ? "BLE" : "经典蓝牙")
.append("\n绑定状态: ").append(info.isBonded ? "已绑定" : "未绑定")
.append("\n连接状态: ").append(info.isConnected ? "已连接" : "未连接");
if (info.rssi != -1) {
sb.append("\n信号强度: ").append(info.rssi).append(" dBm");
}
if (info.lastSeen > 0) {
long secondsAgo = (System.currentTimeMillis() - info.lastSeen) / 1000;
sb.append("\n发现时间: ").append(secondsAgo).append("秒前");
}
return sb.toString();
}
private void startPairing(BluetoothDevice device) {
try {
boolean result = device.createBond();
if (result) {
Toast.makeText(this, "正在配对...", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "配对请求失败", Toast.LENGTH_SHORT).show();
}
} catch (SecurityException e) {
Log.e(TAG, "配对权限错误", e);
Toast.makeText(this, "缺少蓝牙连接权限", Toast.LENGTH_SHORT).show();
}
}
private void connectToDevice(BluetoothDevice device) {
// 这里需要根据设备类型实现具体的连接逻辑
Toast.makeText(this, "开始连接设备", Toast.LENGTH_SHORT).show();
// 实际连接逻辑需要根据具体设备类型(A2DP, HFP, GATT等)实现
}
private void showDeviceDetails(BluetoothDevice device, DeviceInfo info) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("设备详细信息")
.setMessage(getDetailedDeviceInfo(device, info))
.setPositiveButton("确定", null)
.show();
}
private String getDetailedDeviceInfo(BluetoothDevice device, DeviceInfo info) {
StringBuilder sb = new StringBuilder();
sb.append(getDeviceInfoString(device, info));
try {
// 获取设备类型
int deviceType = device.getType();
sb.append("\n设备类型: ").append(getDeviceTypeString(deviceType));
// 获取蓝牙类别
BluetoothClass bluetoothClass = device.getBluetoothClass();
if (bluetoothClass != null) {
sb.append("\n设备类别: ").append(bluetoothClass.getDeviceClass());
sb.append("\n主要类别: ").append(bluetoothClass.getMajorDeviceClass());
// 获取服务类别
int services = bluetoothClass.getServices();
if (services > 0) {
sb.append("\n支持的服务: ");
List<String> serviceList = new ArrayList<>();
if ((services & BluetoothClass.Service.AUDIO) != 0)
serviceList.add("音频");
if ((services & BluetoothClass.Service.CAPTURE) != 0)
serviceList.add("捕获");
if ((services & BluetoothClass.Service.INFORMATION) != 0)
serviceList.add("信息");
if ((services & BluetoothClass.Service.LIMITED_DISCOVERABILITY) != 0)
serviceList.add("有限发现");
if ((services & BluetoothClass.Service.NETWORKING) != 0)
serviceList.add("网络");
if ((services & BluetoothClass.Service.OBJECT_TRANSFER) != 0)
serviceList.add("对象传输");
if ((services & BluetoothClass.Service.POSITIONING) != 0)
serviceList.add("定位");
if ((services & BluetoothClass.Service.RENDER) != 0)
serviceList.add("渲染");
if ((services & BluetoothClass.Service.TELEPHONY) != 0)
serviceList.add("电话");
sb.append(String.join(", ", serviceList));
}
}
} catch (Exception e) {
Log.e(TAG, "获取设备详细信息失败", e);
}
return sb.toString();
}
private String getDeviceTypeString(int deviceType) {
switch (deviceType) {
case BluetoothDevice.DEVICE_TYPE_CLASSIC:
return "经典蓝牙";
case BluetoothDevice.DEVICE_TYPE_LE:
return "低功耗蓝牙(BLE)";
case BluetoothDevice.DEVICE_TYPE_DUAL:
return "双模蓝牙";
default:
return "未知";
}
}
private void unpairDevice(BluetoothDevice device) {
try {
Method method = device.getClass().getMethod("removeBond");
boolean result = (boolean) method.invoke(device);
if (result) {
Toast.makeText(this, "正在取消配对", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "取消配对失败", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "取消配对失败", e);
Toast.makeText(this, "取消配对失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void disconnectDevice(BluetoothDevice device) {
Toast.makeText(this, "断开连接", Toast.LENGTH_SHORT).show();
// 实际断开连接逻辑需要根据具体连接类型实现
}
private void removeDevice(BluetoothDevice device) {
deviceList.remove(device);
deviceInfoMap.remove(device.getAddress());
deviceAdapter.notifyDataSetChanged();
updateUIState();
}
private void showErrorDialog(String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("错误")
.setMessage(message)
.setPositiveButton("确定", (dialog, which) -> finish())
.setCancelable(false)
.show();
}
private void showPermissionDeniedDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("权限被拒绝")
.setMessage("需要蓝牙和位置权限才能扫描设备。\n\n请在设置中授予权限。")
.setPositiveButton("去设置", (dialog, which) -> openAppSettings())
.setNegativeButton("退出", (dialog, which) -> finish())
.setCancelable(false)
.show();
}
private void openAppSettings() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_D