Fix edge case where removing a pod while both were in ears didn't trigger pause in one-pod mode. The aggregate boolean (isEitherPodInEar) stayed true, masking the individual pod removal.
See thread by `ZV`:
https://discord.com/channels/548521543039189022/1437499888068726814
Add color presets, custom color picker, transparency slider, and device
label toggle to the widget configuration screen. Widget preview updates
in real-time. Use profile label as device name in both preview and
actual widget.
Move startForeground() before super.onCreate() in MonitorService to
avoid ForegroundServiceDidNotStartInTimeException when Hilt DI is slow
on backgrounded cold starts. An early minimal notification is shown
immediately, then replaced with the full one after DI completes.
- Fix BleScanResultReceiver package name in manifest (.bluetooth → .common.bluetooth)
- Fix HandlerThread leak in BluetoothManager2 when registerReceiver() throws
- Cache battery values in MonitorNotifications to match hardening pattern
- Remove duplicate fragment-ktx dependency and align fragment-testing version
- Remove deprecated lifecycle-extensions dependency
EdgeToEdgeHelper now considers both systemBars() and displayCutout()
insets when applying padding. This prevents camera cutouts from
obscuring UI content when the device is in landscape orientation.
Use the widget ID as the request code for `PendingIntent`. This ensures that each widget instance has a distinct `PendingIntent`, preventing them from overwriting each other and allowing clicks on multiple widgets to work correctly.
Uses the application context instead of the activity context when updating the widget. This avoids leaking the activity instance if the update operation outlives the configuration screen.
Enhances robustness by adding extensive error handling around broadcast receiver registration, profile event processing, and service disconnections to prevent crashes. Also ensures device flow is cleared when Bluetooth is disabled.
Convert `connectedDevices()` from a function returning a cold Flow to a property that is a hot `StateFlow`. This simplifies call sites and improves efficiency by sharing the underlying subscription.
Switched from monitoring generic ACL events to specific Headset profile state changes for more reliable device connection and disconnection detection.
This fixes a race condition where CAPod thinks no device is connected because we triggered too early, before "connectedDevices" on the HEADSET profile contains our target device.
This fixes#313
This commit updates translations for German, Spanish, and Catalan. It also adds a comprehensive set of new strings for the Chinese (Simplified) localization.
Explains that single-pod detection is an Apple limitation, not an app bug.
Users experiencing this issue will now understand it only affects the
"primary pod" (microphone pod) and can be configured in iOS settings.
Closes#38, Closes#329
- Migrate ProjectConfig from static object to proper Gradle plugin
- Add version type support (beta/rc) to version.properties
- Clean up legacy fastlane changelogs
- Update release script to support version types
- Remove automatic fastlane changelog generation from release script
- Add BuildConfig field injection for version info
The navigation graph had a duplicate entry for DeviceManagerFragment.
This commit removes the duplicate and ensures the correct navigation action to DeviceProfileCreationFragment is present.
The lid state for AirPods Gen 4 was incorrectly reported as UNKNOWN when it should have been NOT_IN_CASE. This commit fixes the issue in both the ANC and non-ANC tests.
This commit replaces the direct usage of GeneralSettings for fetching identity and encryption keys with the DeviceProfilesRepo. BaseAirPodsTest is updated to reflect this change, mocking DeviceProfilesRepo instead of GeneralSettings.
This commit introduces a new card to the Overview screen that informs the user that the app is actively monitoring for devices when there are profiles configured but no devices are currently connected.
- Replace multiple StateFlows with single ProfileEditorState data class
- Store ByteArray keys as hex strings to enable proper equality comparison
- Fix race conditions in state initialization by setting initial and current state atomically
- Simplify change detection logic to simple data class comparison
The issue was caused by:
1. ByteArray types not implementing proper equals() (compared by reference)
2. Race conditions between multiple StateFlow updates
3. Complex change detection logic with timing issues
Now uses atomic state management with proper value-based equality.
- Shows hint when 2+ profiles exist explaining order determines priority
- Appears as flat list item at bottom, less intrusive than card
- Prevents dragging hint item, keeps it at bottom
- Uses book icon for informational guidance