bluetooth_device_info.dart 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /// A Bluetooth Classic device already paired with the tablet.
  2. ///
  3. /// [deviceClass] is Android's class-of-device value. CarDash uses it to keep
  4. /// phones, headsets and other non-SPP devices out of the default OBD-II
  5. /// adapter list. Devices with no class information stay visible; hiding a real
  6. /// adapter would be worse than showing an extra device.
  7. class BluetoothDeviceInfo {
  8. const BluetoothDeviceInfo({
  9. required this.name,
  10. required this.address,
  11. this.deviceClass,
  12. this.uuids = const [],
  13. });
  14. static const _sppUuid = '00001101-0000-1000-8000-00805f9b34fb';
  15. /// Names commonly used by ELM327 and compatible OBD-II adapters.
  16. static const _obdNameHints = <String>[
  17. 'obd',
  18. 'elm',
  19. 'vlink',
  20. 'v-link',
  21. 'vgate',
  22. 'v-gate',
  23. 'veepeak',
  24. 'bafx',
  25. 'obdlink',
  26. 'scantool',
  27. 'konnwei',
  28. 'autel',
  29. 'car scanner',
  30. ];
  31. /// Android major device classes that can plausibly carry an SPP ELM327.
  32. static const _likelyMajorClasses = <int>{
  33. 0x0000, // Miscellaneous
  34. 0x0100, // Computer
  35. 0x0300, // Networking / LAN access
  36. 0x1F00, // Uncategorized
  37. };
  38. final String name;
  39. final String address;
  40. final int? deviceClass;
  41. /// Cached SDP UUIDs, when Android already has them.
  42. final List<String> uuids;
  43. factory BluetoothDeviceInfo.fromMap(Map<dynamic, dynamic> map) {
  44. final rawUuids = map['uuids'];
  45. return BluetoothDeviceInfo(
  46. name: (map['name'] as String?)?.trim() ?? 'Unknown device',
  47. address: (map['address'] as String?) ?? '',
  48. deviceClass: (map['deviceClass'] as num?)?.toInt(),
  49. uuids: rawUuids is List
  50. ? rawUuids
  51. .whereType<String>()
  52. .map((uuid) => uuid.toLowerCase())
  53. .toList(growable: false)
  54. : const [],
  55. );
  56. }
  57. int? get majorClass => deviceClass == null ? null : deviceClass! & 0x1F00;
  58. bool get hasSppService => uuids.contains(_sppUuid);
  59. bool get hasObdName {
  60. final normalized = name.toLowerCase();
  61. return _obdNameHints.any(normalized.contains);
  62. }
  63. /// Whether the adapter is likely to be a Bluetooth Classic OBD-II device.
  64. ///
  65. /// A recognised name or the SPP service UUID always wins. Otherwise the
  66. /// Android major class decides; unknown class information is treated as
  67. /// possibly usable so a real adapter is never hidden.
  68. bool get isLikelyObd {
  69. if (hasObdName || hasSppService) return true;
  70. final major = majorClass;
  71. if (major == null) return true;
  72. return _likelyMajorClasses.contains(major);
  73. }
  74. String get label => name.isEmpty ? address : '$name · $address';
  75. }