Skip to content

Feature: Bluetooth device enumeration#3255

Merged
dbwiddis merged 5 commits into
oshi:masterfrom
dbwiddis:feature/bluetooth-devices
May 17, 2026
Merged

Feature: Bluetooth device enumeration#3255
dbwiddis merged 5 commits into
oshi:masterfrom
dbwiddis:feature/bluetooth-devices

Conversation

@dbwiddis
Copy link
Copy Markdown
Member

@dbwiddis dbwiddis commented May 17, 2026

Closes #3253

Adds Bluetooth device enumeration to OSHI across Linux, Windows, and macOS.

Public API

  • BluetoothDevice interface (oshi-common): name, MAC address, major device class (CoD), connected/paired status, battery level, adapter name
  • HardwareAbstractionLayer.getBluetoothDevices(): default method returning empty list; overridden on supported platforms

Platform Implementations

Linux

  • Reads adapter info from /sys/class/bluetooth/hciX/address
  • Reads paired device properties from /var/lib/bluetooth/<adapter>/<device>/info (BlueZ)
  • Parses Class of Device, battery level, connected/paired state
  • Lives in oshi-common (no native calls needed); shared by JNA/FFM/NativeFree HALs

Windows (JNA + FFM)

  • Native calls to BluetoothApis.dll (Vista+, gated by VersionHelpers)
  • BluetoothFindFirstRadio/BluetoothFindNextRadio for adapter enumeration
  • BluetoothFindFirstDevice/BluetoothFindNextDevice with BLUETOOTH_DEVICE_INFO struct
  • BLUETOOTH_ADDRESS mapped as a proper JNA Union with getAddress()/getBytes() accessors
  • JNA mappings contributed upstream: Add BluetoothApis to c.s.j.p.win32 java-native-access/jna#1725

macOS (JNA + FFM)

  • IOKit registry enumeration via IOBluetoothDevice class
  • Reads Name, DeviceAddress, ClassOfDevice, Connected, Paired, BatteryPercent properties

Shared Utilities

  • FormatUtil.formatMacAddress(long) and formatMacAddress(String): MAC address formatting with hex validation
  • AbstractBluetoothDevice.parseMajorDeviceClass(int): Bluetooth CoD bit parsing (Miscellaneous through Health + Uncategorized)

Other Changes

  • SystemInfoHelper: added printBluetoothDevices(), added CgroupInfo to printOperatingSystem()
  • oshi-core/SystemInfoTest: refactored to use SystemInfoHelper static imports (removed ~390 lines of duplication)
  • All SystemInfoTest variants: print Bluetooth devices after USB
  • README.md + site index: "USB Devices" → "Peripheral devices (USB, Bluetooth)"
  • CHANGELOG.md: entry for this PR

Summary by CodeRabbit

  • New Features

    • Cross-platform Bluetooth device enumeration (Linux, Windows, macOS): lists paired/connected peripherals with name, MAC, adapter, major device class, connection/paired state, and battery level.
  • Improvements

    • Normalized MAC-address formatting/display.
    • OS reporting extended to include container/cgroup details.
    • System info output now includes a Bluetooth Devices section.
  • Documentation

    • README and CHANGELOG updated to list Bluetooth under supported peripherals.
  • Tests

    • Added unit and integration tests covering Bluetooth discovery, parsing, normalization, and display.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a00b4ce1-4a26-4b59-92ff-b46a983ab1e8

📥 Commits

Reviewing files that changed from the base of the PR and between 62ff37a and 3f335e3.

📒 Files selected for processing (10)
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
🚧 Files skipped from review as they are similar to previous changes (9)
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
  • GitHub Check: Analyze (java)
🔇 Additional comments (1)
oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java (1)

23-36: LGTM!


📝 Walkthrough

Walkthrough

Adds a public BluetoothDevice API and AbstractBluetoothDevice implementation, platform enumerators for Linux/Windows/macOS (Windows via JNA and FFM), HAL wiring, MAC-format utilities, printing/cgroup reporting, unit/integration tests, and documentation updates.

Changes

Bluetooth Device Enumeration

Layer / File(s) Summary
BluetoothDevice public interface
oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java, oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java
Immutable @PublicApi interface defining getters for name, address, major device class, connection/pairing state, battery level (-1 when unavailable), and adapter name; HAL default method returns empty immutable list.
AbstractBluetoothDevice base class
oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
Immutable abstract base storing device properties in final fields with battery normalization (negative → -1, clamp >100 to 100); implements all getters, toString(), and parseMajorDeviceClass(int) helper extracting CoD bits and mapping to human-readable device class strings.
MAC address formatting
oshi-common/src/main/java/oshi/util/FormatUtil.java, oshi-common/src/test/java/oshi/util/FormatUtilTest.java
Two formatMacAddress overloads: long input formats low 48 bits as colon-delimited uppercase hex; String input normalizes separators/trimming, validates 12 hex chars, returns normalized colon form or original uppercased; private isHex helper.
Linux BlueZ enumeration
oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
Reads sysfs adapters from /sys/class/bluetooth/*/address, locates BlueZ state under /var/lib/bluetooth/ using uppercase-then-lowercase MAC lookup, parses device info files (Name, Class, Paired, Connected, Battery), skips malformed entries, returns unmodifiable list.
Linux enumeration tests
oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java
Comprehensive coverage: missing sysfs/varlib paths, empty adapter lists, adapters without address files, varlib discovery failures, single paired/connected device parsing with defaults, battery level extraction, ignored non-MAC/short directories and missing info files, CoD mapping validation, lowercase varlib fallback.
Windows JNA enumeration
oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java, oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
JNA BluetoothApis interface with native structures and methods; enumerator iterates Windows radios via find-first/next, queries devices per radio with search params filtering authenticated/remembered/connected, closes handles, formats addresses, maps fConnected/fRemembered to paired state, battery level fixed to -1.
Windows FFM enumeration
oshi-core-ffm/src/main/java/oshi/ffm/windows/BluetoothApisFFM.java, oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
FFM StructLayout definitions and downcall MethodHandles for Bluetooth APIs; enumerator allocates confined arena, enumerates radios/devices via find-first/next, decodes names from 2-byte fixed buffers, formats addresses, derives major class, manages handle cleanup, returns unmodifiable list or empty on pre-Vista.
macOS enumeration
oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
Runs system_profiler SPBluetoothDataType and parses output via state machine tracking connected/not-connected sections, detects device headers, extracts address, major type, battery level, paired/connected state, returns unmodifiable list.
HAL platform wiring
oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java, Windows (JNA/FFM), macOS
Platform HAL implementations override getBluetoothDevices() delegating to respective platform enumerators (LinuxBluetoothDevice, WindowsBluetoothDeviceJNA/FFM, MacBluetoothDevice).
Printing and system reporting
oshi-common/src/main/java/oshi/util/SystemInfoHelper.java
New printBluetoothDevices method appends device list to output (or "None detected"); extended printOperatingSystem conditionally appends cgroup/containerization details (CPU quota/CPUs, memory limit/usage, PID limit/current) with "unlimited" sentinel handling.
Unit and integration tests
oshi-common/src/test/java/oshi/hardware/common/AbstractBluetoothDeviceTest.java, test harnesses and shared tests
AbstractBluetoothDevice tests validate getters, battery normalization, toString(); test harnesses centralize printing via SystemInfoHelper static imports, add Bluetooth device enumeration output, and add BluetoothDeviceTest integration validating metadata and battery bounds.
Documentation
CHANGELOG.md, README.md, src/site/markdown/index.md
Updates version 7.2.0 changelog, README, and site docs to list Bluetooth device enumeration as new peripheral device support across Linux, Windows, and macOS.

Sequence Diagram(s)

sequenceDiagram
  participant SystemInfo
  participant HAL as HardwareAbstractionLayer
  participant PlatformEnum as PlatformEnumerator
  participant NativeFS as FileSystem/NativeAPI

  SystemInfo->>HAL: getBluetoothDevices()
  HAL->>PlatformEnum: getBluetoothDevices()
  PlatformEnum->>NativeFS: enumerate adapters / query native API
  NativeFS-->>PlatformEnum: adapter/device info
  PlatformEnum->>HAL: List<BluetoothDevice>
  HAL-->>SystemInfo: List<BluetoothDevice>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • oshi/oshi#3238: Adds native-free SystemInfoTest printing that this PR extends with Bluetooth output.
  • oshi/oshi#3183: Prior PublicApi/annotation work referenced by the new Bluetooth public types.

"🐰
I hopped through sysfs, name in paw,
Read MACs and classes — oh what a draw!
Paired and connected, batteries few,
I print them all, in lists for you.
Hooray for tiny lights of blue!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feature: Bluetooth device enumeration' is clear, specific, and directly describes the main feature being added. It matches the core objective of implementing Bluetooth device enumeration.
Linked Issues check ✅ Passed The PR fully implements all primary coding objectives from #3253: BluetoothDevice interface with required getters (name, address, class, connected, paired, battery, adapter), platform implementations for Linux/Windows/macOS, both JNA and FFM variants, MAC address formatting utilities, and HAL integration.
Out of Scope Changes check ✅ Passed The PR includes comprehensive test coverage, SystemInfoHelper enhancements for printing Bluetooth info, documentation updates (README, CHANGELOG), and code refactoring of SystemInfoTest to use centralized helpers—all supporting the primary Bluetooth enumeration feature without introducing unrelated changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java (1)

35-43: ⚡ Quick win

Enforce the battery-level contract in the base constructor.

BluetoothDevice#getBatteryLevel() documents -1 or 0..100, but Line 42 currently stores raw input unchanged. Normalizing here prevents invalid values from leaking through any platform implementation.

Proposed change
     protected AbstractBluetoothDevice(String name, String address, String majorDeviceClass, boolean connected,
             boolean paired, int batteryLevel, String adapterName) {
         this.name = name;
         this.address = address;
         this.majorDeviceClass = majorDeviceClass;
         this.connected = connected;
         this.paired = paired;
-        this.batteryLevel = batteryLevel;
+        this.batteryLevel = batteryLevel < 0 ? -1 : Math.min(100, batteryLevel);
         this.adapterName = adapterName;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java`
around lines 35 - 43, The constructor AbstractBluetoothDevice(String name,
String address, String majorDeviceClass, boolean connected, boolean paired, int
batteryLevel, String adapterName) should normalize the batteryLevel per
BluetoothDevice#getBatteryLevel() contract (allowed values: -1 or 0..100) before
storing it: if batteryLevel == -1 keep it, if batteryLevel < -1 set to -1, if
batteryLevel > 100 clamp to 100, otherwise accept 0..100; then assign the
normalized value to the batteryLevel field (so all platform implementations go
through this validation).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java`:
- Around line 96-101: The paired-state for discovered BlueZ device dirs is
currently derived with boolean paired = "true".equals(props.get("Paired")),
which yields false when the Paired key is absent; update the logic in
LinuxBluetoothDevice (around the props / paired variables) to treat a missing
"Paired" key as paired when the device entry was discovered from the
paired-device listing: change to something like checking
props.containsKey("Paired") ? "true".equals(props.get("Paired")) : true so that
absence of the key preserves paired=true for devices enumerated from the
paired-device path while leaving explicit Paired values unchanged.

---

Nitpick comments:
In `@oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java`:
- Around line 35-43: The constructor AbstractBluetoothDevice(String name, String
address, String majorDeviceClass, boolean connected, boolean paired, int
batteryLevel, String adapterName) should normalize the batteryLevel per
BluetoothDevice#getBatteryLevel() contract (allowed values: -1 or 0..100) before
storing it: if batteryLevel == -1 keep it, if batteryLevel < -1 set to -1, if
batteryLevel > 100 clamp to 100, otherwise accept 0..100; then assign the
normalized value to the batteryLevel field (so all platform implementations go
through this validation).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b5d152b8-b646-47ab-b324-45691f294e1b

📥 Commits

Reviewing files that changed from the base of the PR and between 7039753 and a88667c.

📒 Files selected for processing (5)
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 11, windows-latest
  • GitHub Check: Test JDK 25, ubuntu-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 11, macos-latest
  • GitHub Check: Test JDK 21, windows-latest
  • GitHub Check: Test JDK 21, macos-latest
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
  • GitHub Check: Analyze (java)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-04-12T19:22:09.716Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3149
File: oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacCentralProcessor.java:159-163
Timestamp: 2026-04-12T19:22:09.716Z
Learning: When reviewing OSHI hardware platform code that uses or implements `CentralProcessor`/`PhysicalProcessor.getEfficiency()`, remember the API’s counterintuitive semantics: a *higher* efficiency-class value indicates *greater performance* (lower efficiency). P-cores/“performance cores” should therefore have higher values (e.g., 1) than E-cores/“efficiency cores” (e.g., 0), as documented in the `CentralProcessor` Javadoc. Do not flag code as incorrect solely because ARM_P_CORES or Intel P-cores are assigned higher efficiency values.

Applied to files:

  • oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java
🔇 Additional comments (3)
oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java (1)

17-71: LGTM!

oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java (1)

165-173: LGTM!

oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java (1)

65-68: LGTM!

@codecov
Copy link
Copy Markdown

codecov Bot commented May 17, 2026

Codecov Report

❌ Patch coverage is 41.48936% with 165 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.15%. Comparing base (7039753) to head (3f335e3).

Files with missing lines Patch % Lines
...re/platform/windows/WindowsBluetoothDeviceFFM.java 12.50% 60 Missing and 3 partials ⚠️
...rdware/common/platform/mac/MacBluetoothDevice.java 26.78% 37 Missing and 4 partials ⚠️
...re/platform/windows/WindowsBluetoothDeviceJNA.java 13.33% 37 Missing and 2 partials ⚠️
...mmon/src/main/java/oshi/util/SystemInfoHelper.java 20.00% 14 Missing and 2 partials ⚠️
...shi-common/src/main/java/oshi/util/FormatUtil.java 76.92% 1 Missing and 2 partials ⚠️
...re/common/platform/linux/LinuxBluetoothDevice.java 95.00% 1 Missing and 1 partial ⚠️
...n/java/oshi/hardware/HardwareAbstractionLayer.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3255      +/-   ##
============================================
- Coverage     74.83%   74.15%   -0.68%     
  Complexity       73       73              
============================================
  Files           391      396       +5     
  Lines         15814    16096     +282     
  Branches       2541     2589      +48     
============================================
+ Hits          11834    11936     +102     
- Misses         2484     2639     +155     
- Partials       1496     1521      +25     
Flag Coverage Δ
linux 38.62% <29.78%> (-0.20%) ⬇️
macos 39.28% <16.66%> (-0.42%) ⬇️
windows 46.95% <17.02%> (-0.62%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

dbwiddis added 2 commits May 17, 2026 15:18
Adds Bluetooth device enumeration (issue oshi#3253):
- BluetoothDevice interface in oshi-common with name, address,
  major device class, connected/paired status, battery level
- AbstractBluetoothDevice base class
- Linux implementation reading from /sys/class/bluetooth/ and
  /var/lib/bluetooth/ (BlueZ)
- HardwareAbstractionLayer.getBluetoothDevices() default method
- Wired into LinuxHardwareAbstractionLayer (shared by JNA/FFM/NF)
- LinuxBluetoothDeviceTest: covers sysfs parsing, paired-state defaults,
  battery level, device class parsing, fallback paths
- AbstractBluetoothDeviceTest: covers getters, toString, battery normalization
- SystemInfoHelper: add printBluetoothDevices(), add CgroupInfo to
  printOperatingSystem()
- oshi-core SystemInfoTest: replace duplicated print methods with static
  imports from SystemInfoHelper
- All SystemInfoTest variants: add Bluetooth device output after USB
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from a88667c to cac243b Compare May 17, 2026 15:19
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java`:
- Around line 95-117: The parseMajorDeviceClass method currently returns an
empty string for major CoD values 0 and 31; update the switch in
parseMajorDeviceClass(int cod) to explicitly handle case 0 and case 31,
returning "Miscellaneous" for 0 and "Uncategorized" (or equivalent canonical
label) for 31, keeping all other existing cases unchanged so valid
classifications are preserved.

In
`@oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java`:
- Around line 130-138: The paired boolean is derived only from fAuthenticated
which misses devices returned as remembered-only; update the logic in
WindowsBluetoothDeviceFFM where paired is computed (the local variable paired
set from fAuthenticated) to consider either flag by using fRemembered ||
fAuthenticated when reading from BLUETOOTH_DEVICE_INFO_LAYOUT (same area that
reads fConnected and szName), so the WindowsBluetoothDeviceFFM constructor
receives paired=true for remembered or authenticated devices.

In
`@oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java`:
- Around line 103-105: The paired flag is currently set using only
info.fAuthenticated which misses remembered-but-not-authenticated devices;
update the logic in the method that builds the device object (where boolean
paired = info.fAuthenticated and the return new WindowsBluetoothDeviceJNA(...))
to set paired = info.fRemembered || info.fAuthenticated; apply the same fix in
the analogous code path in WindowsBluetoothDeviceFFM (where the device is
constructed there) so remembered devices are reported as paired.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 08b932fa-d002-4397-8b08-81dab5fb557b

📥 Commits

Reviewing files that changed from the base of the PR and between cac243b and 4343d4d.

📒 Files selected for processing (9)
  • oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java
  • oshi-core-ffm/src/main/java/oshi/ffm/windows/BluetoothApisFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerFFM.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerJNA.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Test JDK 21, macos-latest
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 11, macos-latest
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: Analyze (java)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).

Applied to files:

  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerJNA.java
📚 Learning: 2026-04-12T19:22:09.716Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3149
File: oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacCentralProcessor.java:159-163
Timestamp: 2026-04-12T19:22:09.716Z
Learning: When reviewing OSHI hardware platform code that uses or implements `CentralProcessor`/`PhysicalProcessor.getEfficiency()`, remember the API’s counterintuitive semantics: a *higher* efficiency-class value indicates *greater performance* (lower efficiency). P-cores/“performance cores” should therefore have higher values (e.g., 1) than E-cores/“efficiency cores” (e.g., 0), as documented in the `CentralProcessor` Javadoc. Do not flag code as incorrect solely because ARM_P_CORES or Intel P-cores are assigned higher efficiency values.

Applied to files:

  • oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
🔇 Additional comments (4)
oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java (1)

35-85: LGTM!

oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java (1)

54-111: LGTM!

oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java (1)

21-21: Verify the JNA binding loads the exported module.

Microsoft documents these entry points in bthprops.cpl, while JNA's Native.load(String, ...) treats its argument as the library base name. Please verify "bthprops" resolves correctly on supported Windows builds, or load bthprops.cpl explicitly here. (learn.microsoft.com)

oshi-core-ffm/src/main/java/oshi/ffm/windows/BluetoothApisFFM.java (1)

28-28: Verify the FFM lookup targets the actual exporting module.

These APIs are documented as exports from bthprops.cpl. Please confirm lib("bthprops") resolves that module on supported Windows builds before relying on this binding. (learn.microsoft.com)

- BluetoothApis JNA interface for bthprops.cpl with struct mappings
- WindowsBluetoothDeviceJNA using BluetoothFindFirst/NextDevice
- BluetoothApisFFM with FFM struct layouts and method handles
- WindowsBluetoothDeviceFFM using Foreign Function API
- Move parseMajorDeviceClass() to AbstractBluetoothDevice (shared)
- Wire into both Windows HAL variants
dbwiddis added a commit to dbwiddis/oshi that referenced this pull request May 17, 2026
- MacBluetoothDeviceJNA: IOKit IOBluetoothDevice registry enumeration
- MacBluetoothDeviceFFM: same via FFM IOKit bindings
- Wire into both macOS HAL variants
- CHANGELOG.md: add entry for oshi#3255
- README.md, site index: USB Devices -> Peripheral devices (USB, Bluetooth)
- Update parseMajorDeviceClass test for Miscellaneous/Uncategorized cases
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from 4343d4d to 92af33e Compare May 17, 2026 15:50
- MacBluetoothDeviceJNA: IOKit IOBluetoothDevice registry enumeration
- MacBluetoothDeviceFFM: same via FFM IOKit bindings
- Wire into both macOS HAL variants
- CHANGELOG.md: add entry for oshi#3255
- README.md, site index: USB Devices -> Peripheral devices (USB, Bluetooth)
- Update parseMajorDeviceClass test for Miscellaneous/Uncategorized cases
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from 92af33e to 0aa2a61 Compare May 17, 2026 16:37
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@oshi-common/src/main/java/oshi/util/FormatUtil.java`:
- Around line 244-251: The formatMacAddress method currently only checks
cleaned.length() == 12 before formatting; update formatMacAddress to validate
that all 12 characters are valid hexadecimal digits (e.g., match cleaned against
a hex regex like "[0-9A-Fa-f]{12}" or verify each char with Character.digit) and
only perform the colon-insert formatting when that validation passes; if
validation fails, fall back to returning raw.toUpperCase(Locale.ROOT) as before.
Ensure you reference the method name formatMacAddress and keep the existing
cleaning (replace("-", "").replace(":", "").trim()) logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 65f6f394-3aa4-407c-8558-4f61bb53baab

📥 Commits

Reviewing files that changed from the base of the PR and between 0aa2a61 and 4834e4f.

📒 Files selected for processing (8)
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 21, macos-latest
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: Analyze (java)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-04-12T19:22:09.716Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3149
File: oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacCentralProcessor.java:159-163
Timestamp: 2026-04-12T19:22:09.716Z
Learning: When reviewing OSHI hardware platform code that uses or implements `CentralProcessor`/`PhysicalProcessor.getEfficiency()`, remember the API’s counterintuitive semantics: a *higher* efficiency-class value indicates *greater performance* (lower efficiency). P-cores/“performance cores” should therefore have higher values (e.g., 1) than E-cores/“efficiency cores” (e.g., 0), as documented in the `CentralProcessor` Javadoc. Do not flag code as incorrect solely because ARM_P_CORES or Intel P-cores are assigned higher efficiency values.

Applied to files:

  • oshi-common/src/main/java/oshi/util/FormatUtil.java
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).

Applied to files:

  • oshi-core/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceJNA.java
🔇 Additional comments (5)
oshi-common/src/main/java/oshi/util/FormatUtil.java (1)

225-235: LGTM!

oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java (1)

23-37: LGTM!

oshi-common/src/test/java/oshi/util/FormatUtilTest.java (1)

160-165: LGTM!

Also applies to: 167-173

oshi-core/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceJNA.java (1)

38-70: LGTM!

oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java (1)

37-69: LGTM!

Comment thread oshi-common/src/main/java/oshi/util/FormatUtil.java
@dbwiddis
Copy link
Copy Markdown
Member Author

@CodeRabbit full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
oshi-common/src/test/java/oshi/util/FormatUtilTest.java (1)

167-173: ⚡ Quick win

Add a regression case for 12-character non-hex input.

This path is now validation-sensitive (isHex) and worth pinning with one explicit negative-case test.

Suggested test addition
 `@Test`
 void testFormatMacAddressFromString() {
     assertThat(FormatUtil.formatMacAddress("aa-bb-cc-dd-ee-ff"), is("AA:BB:CC:DD:EE:FF"));
     assertThat(FormatUtil.formatMacAddress("11:22:33:44:55:66"), is("11:22:33:44:55:66"));
     assertThat(FormatUtil.formatMacAddress("aabbccddeeff"), is("AA:BB:CC:DD:EE:FF"));
+    assertThat(FormatUtil.formatMacAddress("zzzzzzzzzzzz"), is("ZZZZZZZZZZZZ"));
     assertThat(FormatUtil.formatMacAddress("abcd"), is("ABCD"));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@oshi-common/src/test/java/oshi/util/FormatUtilTest.java` around lines 167 -
173, Add a negative regression test to FormatUtilTest that covers a 12-character
non-hex input so the validation-sensitive path in FormatUtil.formatMacAddress is
pinned; specifically, in the testFormatMacAddressFromString method add an
assertion calling FormatUtil.formatMacAddress with a 12-character non-hex string
(e.g., "abcdefghijkl") and assert the method returns the uppercased input (e.g.,
"ABCDEFGHIJKL"), referencing the FormatUtil.formatMacAddress call in
FormatUtilTest.
oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java (1)

37-70: ⚡ Quick win

Consider adding try-finally for native resource cleanup.

If an exception occurs during property extraction (lines 45-62), neither the current device nor iter will be released, potentially leaking native IOKit handles.

While IOKit property accessors typically return null rather than throw, wrapping in try-finally ensures robustness against unexpected failures.

♻️ Proposed defensive resource handling
     public static List<BluetoothDevice> getBluetoothDevices() {
         List<BluetoothDevice> devices = new ArrayList<>();
         IOIterator iter = IOKitUtilFFM.getMatchingServices(IO_BLUETOOTH_DEVICE);
         if (iter == null) {
             return Collections.emptyList();
         }
-        IORegistryEntry device = iter.next();
-        while (device != null) {
-            String name = device.getStringProperty("Name");
-            if (name == null) {
-                name = device.getName();
-            }
-            String address = device.getStringProperty("DeviceAddress");
-            if (address == null) {
-                address = "";
-            } else {
-                address = FormatUtil.formatMacAddress(address);
+        try {
+            IORegistryEntry device = iter.next();
+            while (device != null) {
+                try {
+                    String name = device.getStringProperty("Name");
+                    if (name == null) {
+                        name = device.getName();
+                    }
+                    String address = device.getStringProperty("DeviceAddress");
+                    if (address == null) {
+                        address = "";
+                    } else {
+                        address = FormatUtil.formatMacAddress(address);
+                    }
+                    Long cod = device.getLongProperty("ClassOfDevice");
+                    String majorClass = parseMajorDeviceClass(cod != null ? cod.intValue() : 0);
+                    Long connectedVal = device.getLongProperty("Connected");
+                    boolean connected = connectedVal != null && connectedVal != 0;
+                    Long pairedVal = device.getLongProperty("Paired");
+                    boolean paired = pairedVal != null && pairedVal != 0;
+                    Long batteryVal = device.getLongProperty("BatteryPercent");
+                    int batteryLevel = batteryVal != null ? batteryVal.intValue() : -1;
+
+                    devices.add(new MacBluetoothDeviceFFM(name, address, majorClass, connected, paired, batteryLevel, ""));
+                } finally {
+                    device.release();
+                }
+                device = iter.next();
             }
-            Long cod = device.getLongProperty("ClassOfDevice");
-            String majorClass = parseMajorDeviceClass(cod != null ? cod.intValue() : 0);
-            Long connectedVal = device.getLongProperty("Connected");
-            boolean connected = connectedVal != null && connectedVal != 0;
-            Long pairedVal = device.getLongProperty("Paired");
-            boolean paired = pairedVal != null && pairedVal != 0;
-            Long batteryVal = device.getLongProperty("BatteryPercent");
-            int batteryLevel = batteryVal != null ? batteryVal.intValue() : -1;
-
-            devices.add(new MacBluetoothDeviceFFM(name, address, majorClass, connected, paired, batteryLevel, ""));
-            device.release();
-            device = iter.next();
+        } finally {
+            iter.release();
         }
-        iter.release();
         return Collections.unmodifiableList(devices);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java`
around lines 37 - 70, The getBluetoothDevices method can leak native handles if
an exception occurs while iterating properties; wrap use of IOIterator and the
per-iteration IORegistryEntry in try/finally blocks so both the current
IORegistryEntry (device) and the IOIterator (iter) are always released: after
obtaining iter = IOKitUtilFFM.getMatchingServices(IO_BLUETOOTH_DEVICE) check for
null as now, then use try { while (...) { IORegistryEntry device = iter.next();
try { ... devices.add(new MacBluetoothDeviceFFM(...)); } finally { if (device !=
null) device.release(); } } } finally { iter.release(); } to guarantee cleanup
in getBluetoothDevices.
oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java (1)

26-27: ⚡ Quick win

Run these parsing tests on all OSes (remove Linux-only gate).

These tests are temp-dir fixture tests and don’t require Linux runtime APIs, so the OS restriction unnecessarily reduces coverage.

Suggested patch
-import org.junit.jupiter.api.condition.EnabledOnOs;
-import org.junit.jupiter.api.condition.OS;
@@
-@EnabledOnOs(OS.LINUX)
 class LinuxBluetoothDeviceTest {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java`
around lines 26 - 27, Remove the Linux-only test gate by deleting the
`@EnabledOnOs`(OS.LINUX) annotation on the LinuxBluetoothDeviceTest class so the
temp-dir parsing tests in class LinuxBluetoothDeviceTest run on all OSes; ensure
no other OS-specific setup remains that would require Linux runtime APIs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java`:
- Around line 71-75: The code in LinuxBluetoothDevice that builds
adapterStateDir currently tries an uppercase address then falls back to the raw
adapterAddress, which misses lowercase-only directories; update the fallback to
use adapterAddress.toLowerCase(Locale.ROOT) so the second File construction
checks the lowercase path. Modify the File adapterStateDir creation logic in the
class/method where adapterAddress is used (replace new File(varLibPath +
adapterAddress) with new File(varLibPath +
adapterAddress.toLowerCase(Locale.ROOT))).
- Around line 88-90: The current directory-name filter in LinuxBluetoothDevice
uses only a colon presence and length check on dirName; tighten this by
validating dirName against a proper hex-MAC pattern (e.g. six hex octets
separated by colons) and skip entries that don't match. Update the conditional
that references dirName (in class LinuxBluetoothDevice / the directory
enumeration loop) to test against a regex or a byte-pair parsing routine
(pattern like two hex chars then : repeated 5 times) and continue when the
validation fails so malformed names like "GG:GG:..." are excluded.

---

Nitpick comments:
In
`@oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java`:
- Around line 26-27: Remove the Linux-only test gate by deleting the
`@EnabledOnOs`(OS.LINUX) annotation on the LinuxBluetoothDeviceTest class so the
temp-dir parsing tests in class LinuxBluetoothDeviceTest run on all OSes; ensure
no other OS-specific setup remains that would require Linux runtime APIs.

In `@oshi-common/src/test/java/oshi/util/FormatUtilTest.java`:
- Around line 167-173: Add a negative regression test to FormatUtilTest that
covers a 12-character non-hex input so the validation-sensitive path in
FormatUtil.formatMacAddress is pinned; specifically, in the
testFormatMacAddressFromString method add an assertion calling
FormatUtil.formatMacAddress with a 12-character non-hex string (e.g.,
"abcdefghijkl") and assert the method returns the uppercased input (e.g.,
"ABCDEFGHIJKL"), referencing the FormatUtil.formatMacAddress call in
FormatUtilTest.

In
`@oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java`:
- Around line 37-70: The getBluetoothDevices method can leak native handles if
an exception occurs while iterating properties; wrap use of IOIterator and the
per-iteration IORegistryEntry in try/finally blocks so both the current
IORegistryEntry (device) and the IOIterator (iter) are always released: after
obtaining iter = IOKitUtilFFM.getMatchingServices(IO_BLUETOOTH_DEVICE) check for
null as now, then use try { while (...) { IORegistryEntry device = iter.next();
try { ... devices.add(new MacBluetoothDeviceFFM(...)); } finally { if (device !=
null) device.release(); } } } finally { iter.release(); } to guarantee cleanup
in getBluetoothDevices.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ac790f30-ba36-4f6e-9350-2871b36bc246

📥 Commits

Reviewing files that changed from the base of the PR and between 7039753 and 30022b7.

📒 Files selected for processing (27)
  • CHANGELOG.md
  • README.md
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/main/java/oshi/util/SystemInfoHelper.java
  • oshi-common/src/test/java/oshi/hardware/common/AbstractBluetoothDeviceTest.java
  • oshi-common/src/test/java/oshi/hardware/common/platform/linux/LinuxBluetoothDeviceTest.java
  • oshi-common/src/test/java/oshi/nativefree/SystemInfoTest.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core-ffm/src/main/java/oshi/ffm/windows/BluetoothApisFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacHardwareAbstractionLayerFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerFFM.java
  • oshi-core-ffm/src/test/java/oshi/ffm/SystemInfoTest.java
  • oshi-core/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/mac/MacHardwareAbstractionLayerJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerJNA.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core/src/test/java/oshi/SystemInfoTest.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
  • src/site/markdown/index.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-04-12T19:22:09.716Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3149
File: oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacCentralProcessor.java:159-163
Timestamp: 2026-04-12T19:22:09.716Z
Learning: When reviewing OSHI hardware platform code that uses or implements `CentralProcessor`/`PhysicalProcessor.getEfficiency()`, remember the API’s counterintuitive semantics: a *higher* efficiency-class value indicates *greater performance* (lower efficiency). P-cores/“performance cores” should therefore have higher values (e.g., 1) than E-cores/“efficiency cores” (e.g., 0), as documented in the `CentralProcessor` Javadoc. Do not flag code as incorrect solely because ARM_P_CORES or Intel P-cores are assigned higher efficiency values.

Applied to files:

  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java
  • oshi-common/src/main/java/oshi/util/SystemInfoHelper.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).

Applied to files:

  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/mac/MacHardwareAbstractionLayerJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
🔇 Additional comments (26)
oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxHardwareAbstractionLayer.java (1)

11-11: LGTM!

Also applies to: 65-68

oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacHardwareAbstractionLayerFFM.java (1)

11-11: LGTM!

Also applies to: 82-85

oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerFFM.java (1)

10-10: LGTM!

Also applies to: 98-101

oshi-core/src/main/java/oshi/hardware/platform/mac/MacHardwareAbstractionLayerJNA.java (1)

10-10: LGTM!

Also applies to: 87-89

oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsHardwareAbstractionLayerJNA.java (1)

10-10: LGTM!

Also applies to: 98-100

oshi-common/src/main/java/oshi/util/SystemInfoHelper.java (1)

16-16: LGTM!

Also applies to: 37-37, 72-85, 481-496

oshi-common/src/test/java/oshi/hardware/common/AbstractBluetoothDeviceTest.java (1)

1-57: LGTM!

oshi-common/src/test/java/oshi/nativefree/SystemInfoTest.java (1)

10-10: LGTM!

Also applies to: 124-126

oshi-core-ffm/src/test/java/oshi/ffm/SystemInfoTest.java (1)

12-12: LGTM!

Also applies to: 143-145

oshi-core/src/test/java/oshi/SystemInfoTest.java (1)

10-31: LGTM!

Also applies to: 138-140

oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java (1)

1-38: LGTM!

CHANGELOG.md (1)

7-7: LGTM!

README.md (1)

33-33: LGTM!

src/site/markdown/index.md (1)

33-33: LGTM!

oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java (1)

10-81: LGTM!

oshi-common/src/main/java/oshi/hardware/HardwareAbstractionLayer.java (1)

165-173: LGTM!

oshi-common/src/main/java/oshi/hardware/common/AbstractBluetoothDevice.java (1)

35-123: LGTM!

oshi-common/src/main/java/oshi/util/FormatUtil.java (1)

225-262: LGTM!

oshi-common/src/test/java/oshi/util/FormatUtilTest.java (1)

160-165: LGTM!

oshi-core/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceJNA.java (2)

38-71: Same resource management consideration applies here.

The same try-finally pattern suggested for the FFM variant would benefit this JNA implementation for defensive native handle cleanup.


1-31: LGTM!

oshi-core-ffm/src/main/java/oshi/hardware/platform/mac/MacBluetoothDeviceFFM.java (1)

1-31: LGTM!

oshi-core-ffm/src/main/java/oshi/ffm/windows/BluetoothApisFFM.java (1)

1-103: LGTM!

oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java (1)

1-158: LGTM!

oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java (1)

1-202: LGTM!

oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java (1)

1-114: LGTM!

@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from 30022b7 to 7fcaa55 Compare May 17, 2026 19:49
dbwiddis added a commit to dbwiddis/oshi that referenced this pull request May 17, 2026
- MacBluetoothDevice in oshi-common: parses system_profiler
  SPBluetoothDataType output for connected/not-connected devices
- Shared by JNA/FFM HALs (no native calls needed)
- Replaces IOKit IOBluetoothDevice approach which only found
  kernel-level objects, not user-space paired devices
- CHANGELOG.md: add entry for oshi#3255
- README.md, site index: USB Devices -> Peripheral devices (USB, Bluetooth)
- Update parseMajorDeviceClass test for Miscellaneous/Uncategorized cases
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from 7fcaa55 to f3acf53 Compare May 17, 2026 20:07
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java`:
- Around line 60-70: When toggling section flags in MacBluetoothDevice (where
variables inConnected, inNotConnected, and inDevice are set), ensure the
currently accumulating device is persisted before clearing inDevice; i.e.,
before the blocks that handle trimmed.startsWith("Connected:") and
trimmed.startsWith("Not Connected:") (and their equals(...) variants), call the
same flush/add logic used when ending a device (the logic that stores the active
device into the device list) so the last device in the previous section is not
lost—update the code in MacBluetoothDevice.java to flush the active device prior
to setting inDevice = false and switching inConnected/inNotConnected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1fe9fcc7-1c9b-4572-b705-ead93ad6f213

📥 Commits

Reviewing files that changed from the base of the PR and between 7fcaa55 and f3acf53.

📒 Files selected for processing (10)
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
🚧 Files skipped from review as they are similar to previous changes (6)
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 21, macos-latest
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
  • GitHub Check: Analyze (java)
  • GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-04-12T19:22:09.716Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3149
File: oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacCentralProcessor.java:159-163
Timestamp: 2026-04-12T19:22:09.716Z
Learning: When reviewing OSHI hardware platform code that uses or implements `CentralProcessor`/`PhysicalProcessor.getEfficiency()`, remember the API’s counterintuitive semantics: a *higher* efficiency-class value indicates *greater performance* (lower efficiency). P-cores/“performance cores” should therefore have higher values (e.g., 1) than E-cores/“efficiency cores” (e.g., 0), as documented in the `CentralProcessor` Javadoc. Do not flag code as incorrect solely because ARM_P_CORES or Intel P-cores are assigned higher efficiency values.

Applied to files:

  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
🔇 Additional comments (3)
oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java (1)

31-113: LGTM!

oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java (1)

19-201: LGTM!

oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java (1)

37-40: LGTM!

dbwiddis added a commit to dbwiddis/oshi that referenced this pull request May 17, 2026
- MacBluetoothDevice in oshi-common: parses system_profiler
  SPBluetoothDataType output for connected/not-connected devices
- Shared by JNA/FFM HALs (no native calls needed)
- Replaces IOKit IOBluetoothDevice approach which only found
  kernel-level objects, not user-space paired devices
- CHANGELOG.md: add entry for oshi#3255
- README.md, site index: USB Devices -> Peripheral devices (USB, Bluetooth)
- Update parseMajorDeviceClass test for Miscellaneous/Uncategorized cases
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from f3acf53 to d1e4795 Compare May 17, 2026 20:38
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java`:
- Around line 58-63: The radio handle created inside the loop can leak if
getRadioName(...) or queryDevicesForRadio(...) throws; modify the loop in
WindowsBluetoothDeviceJNA (the block that constructs new
HANDLE(phRadio.getValue())) to wrap per-radio usage in a try/finally so
Kernel32.INSTANCE.CloseHandle(hRadio) always runs: create the HANDLE hRadio as
now, then in a try block call getRadioName(hRadio) and
queryDevicesForRadio(hRadio, adapterName, devices), and call CloseHandle(hRadio)
in the finally block; keep the BluetoothFindNextRadio(hFindRadio, phRadio) loop
condition unchanged so iteration continues while ensuring each HANDLE is closed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e04c17e8-73bc-40d7-90d3-529210e328c9

📥 Commits

Reviewing files that changed from the base of the PR and between f3acf53 and d1e4795.

📒 Files selected for processing (10)
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
🚧 Files skipped from review as they are similar to previous changes (9)
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: Analyze (java)
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).

Applied to files:

  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java

dbwiddis added a commit to dbwiddis/oshi that referenced this pull request May 17, 2026
- MacBluetoothDevice in oshi-common: parses system_profiler
  SPBluetoothDataType output for connected/not-connected devices
- Shared by JNA/FFM HALs (no native calls needed)
- Replaces IOKit IOBluetoothDevice approach which only found
  kernel-level objects, not user-space paired devices
- CHANGELOG.md: add entry for oshi#3255
- README.md, site index: USB Devices -> Peripheral devices (USB, Bluetooth)
- Update parseMajorDeviceClass test for Miscellaneous/Uncategorized cases
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from d1e4795 to 62ff37a Compare May 17, 2026 20:47
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java`:
- Around line 72-76: In WindowsBluetoothDeviceFFM's loop that iterates phRadio
(the code calling getRadioName(arena, hRadio) and queryDevicesForRadio(arena,
hRadio, adapterName, devices)), ensure each native radio handle (hRadio) is
closed in a per-iteration finally block so CloseHandle(hRadio) always runs even
if getRadioName or queryDevicesForRadio throws; refactor the loop body to
capture hRadio, call getRadioName and queryDevicesForRadio inside a try, and
invoke Kernel32FFM.CloseHandle(hRadio) in the corresponding finally to prevent
native handle leaks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1e56a092-03aa-4d87-b7f3-0982bf677a13

📥 Commits

Reviewing files that changed from the base of the PR and between d1e4795 and 62ff37a.

📒 Files selected for processing (10)
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-core-ffm/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceFFM.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
✅ Files skipped from review due to trivial changes (1)
  • oshi-core/src/test/java/oshi/hardware/platform/shared/BluetoothDeviceTest.java
🚧 Files skipped from review as they are similar to previous changes (8)
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacHardwareAbstractionLayer.java
  • oshi-core/src/main/java/oshi/hardware/platform/windows/WindowsBluetoothDeviceJNA.java
  • oshi-common/src/test/java/oshi/util/FormatUtilTest.java
  • oshi-common/src/main/java/oshi/util/FormatUtil.java
  • oshi-common/src/main/java/oshi/hardware/BluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/mac/MacBluetoothDevice.java
  • oshi-common/src/main/java/oshi/hardware/common/platform/linux/LinuxBluetoothDevice.java
  • oshi-core/src/main/java/oshi/jna/platform/windows/BluetoothApis.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
  • GitHub Check: Test JDK 21, macos-latest
  • GitHub Check: Test JDK 25, ubuntu-latest (+ JNA==FFM)
  • GitHub Check: Analyze (java)
  • GitHub Check: JMH Benchmarks, macos-latest
  • GitHub Check: JMH Benchmarks, ubuntu-latest
  • GitHub Check: JMH Benchmarks, windows-latest
  • GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)

- MacBluetoothDevice in oshi-common: parses system_profiler
  SPBluetoothDataType output for connected/not-connected devices
- Shared by JNA/FFM HALs (no native calls needed)
- Replaces IOKit IOBluetoothDevice approach which only found
  kernel-level objects, not user-space paired devices
- CHANGELOG.md: add entry for oshi#3255
- README.md, site index: USB Devices -> Peripheral devices (USB, Bluetooth)
- Update parseMajorDeviceClass test for Miscellaneous/Uncategorized cases
@dbwiddis dbwiddis force-pushed the feature/bluetooth-devices branch from 62ff37a to 3f335e3 Compare May 17, 2026 20:54
@dbwiddis dbwiddis merged commit 2a6905c into oshi:master May 17, 2026
20 checks passed
@dbwiddis dbwiddis deleted the feature/bluetooth-devices branch May 17, 2026 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Bluetooth device enumeration

1 participant