Android13-蓝牙-发现,配对,连接-例子

Android 13 蓝牙设备发现与显示列表完整实现

一、权限处理与配置

1. AndroidManifest.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- Android 12+ (API 31+) 需要的权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    
    <!-- Android 6.0+ 需要的位置权限(用于扫描) -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    
    <!-- Android 10+ 后台位置权限(可选) -->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" 
        tools:ignore="ManifestOrder" />
    
    <!-- Android 11及以下兼容权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
    
    <!-- 如果是 Android 8.0 以下,还需要这些权限 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
        android:maxSdkVersion="28" />
    
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.BluetoothDiscovery">
        
        <activity
            android:name=".DeviceDiscoveryActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
    </application>
</manifest>

2. 权限请求工具类

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 "需要此权限来使用蓝牙功能";
        }
    }
}

二、主界面实现

1. DeviceDiscoveryActivity

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
相关推荐
游戏开发爱好者82 小时前
iOS App 抓不到包时的常见成因与判断思路,结合iOS 调试经验
android·ios·小程序·https·uni-app·iphone·webview
林多3 小时前
【Android】SU命令源码解析
android·源码·命令·cat·su
低调小一13 小时前
深度复盘:KMP 在字节跳动的工程化落地实践
android·kotlin
歪楼小能手16 小时前
Android16系统go版关闭重力旋转开关后缺失手动旋转屏幕悬浮按钮
android·java·平板
崇山峻岭之间16 小时前
Matlab学习记录37
android·学习·matlab
stevenzqzq19 小时前
Android 协程 Channel 菜鸟教程
android·channel
遗悲风19 小时前
PHP伪协议全面解析:原理、常用场景、攻防实战与安全防护
android·安全·php
撩得Android一次心动19 小时前
Android Lifecycle 全面解析:掌握生命周期管理的艺术(源码篇)
android·lifecycle
stevenzqzq19 小时前
android fow 限流
android·限流·flow