Skip to content

Commit 8eb6eba

Browse files
authored
android: multidevice capabilites and accessiblity features (and "liquid glass") (#202)
many thanks to @rithvikvibhu for help with the hearing aids feature adds: hearing aid two-device connection new UI transparency mode customization commits: * android: add accessibility stuff adds option for customizing transparency mode, amplification, tone, etc. * docs: update transparency mode format * android: don't 'start' service every time MainActivity is launched * android: add basic multidevice capabilities use at your own risk, may or may not work * android: clean up a bit of AI gen'd code * android: clean up main service and remove minimum API on head gestures * android: clean up a lot of stuff * android: implement the accessiblity settings page * android: add EQ settings for phone and media * android: add toggle for DID hook * docs: add 'has ownership' control cmd * android: fix balance NaN error when amplification L/R is both zero * android: bring back some accessiblity settings and add listeners for all config * android: add header to ATTManager * android: use device name sent by the connected device in island * android: fix track color in tone volume * android: remove unused composable * android: update eq sliders style * android: fix text color in selectors * android: add delay before starting head tracking again * android: add a few options ik not the right branch/pr but, eh, i am not merging this hook until i test further, and if i don't merge, conflicts, a lot of 'em * android: a small ui fix * docs: a few more control cmds * android: add microphone setting also, un-hardcoded strings, and updated text sizes * android: improve dropdowns ai generated * android: move attmanager to service to avoid trying to connect multiple times * android: add ui for hearing stuff mostly copied from the transparency settings, which are now updated to match ios <26 ui * android: add media assist options in hearing aid ui only * android: add hearing aid adjustments * android: liquidglass sliders * android: improve liquid glass sliders * android: little more liquid glass * android: fix hearing aid parsing * android: remove customdeviceactivity from manifest * android: remove unused strings * android: small ui tweaks * android: a very big commit refactoring ui, mostly * android: move padding to StyledScaffold's content because haze needs it * android: revert accidental capitalization on toggle label * android: update usages for toggle * android: liquidglass, maybe? the switch and icon button took quite a while. i forgot the order of modifiers matters! * remove bleonly mode, use CAPod instead * remove bleonly mode, use CAPod instead * android: fix switch styling * android: remove fade from transition * android: add A16's new bluetooth identifier for log collection just why... * android: fix crash in head gestures screen * android: show head gestures status in the navigation button * android: don't crash if att not available * android: use lazycolumn in airpods settings for better performance and navigation transitions * android: fix text color in troubshooting button and pressandhold settings * android: bring back original confirmation dialog too lazy to fix/implement properly the glassy one * android: prevent hearing aid turning off itself * android: hide media assist, not implemented * docs: update README with new features * docs: add demo video * docs: add new screenshots for android * docs: update demo video position * docs: app3 compatibility * docs: new control cmds '25 (again) * docs: change section title in control cmd doc Updated section title from 'Control Commands' to 'Identifiers and details'. * android: ui tweaks * android: update styled slider thumb * android: add accessiblity service for camera control * android: add camera control, finally i got too lazy to find out how to listen to app openings earlier, wasn't too hard * android: add option to change camera app id * android: not use relative paths for executing commands i hope it's the same across all skins * android: fix transparency and noise cancellation flags huh... was it always like this? * android: revert to using relative paths for su compatibility issues with magisk * android: bump version * android: don't crash if self MAC is not available * android: remove unused LOCAL_ADDRESS permission * android: add opensource licenses should've done this a long time ago! * android: move navigation button to activity level * android: update animation time on switch tap * android: implement setting hearing test results * android: update title in hearing test screen * docs: add screenshot for hearing test * android: fix haze for dialog when enabling hearing aid * android: parse device info * android: add support for various models still need to update images or find a way to fetch from apple's cdn * android: fix a2dp connection * android: remove stray eq config in accessibility settings * android: improve connection handling * android: add a (very important) support dialog to not be invasive, this only shows up once, and never again. * docs: add note for DID hook on android
1 parent e437572 commit 8eb6eba

File tree

152 files changed

+17544
-5672
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+17544
-5672
lines changed

AAP Definitions.md

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -279,50 +279,27 @@ duplicated thrice for some reason
279279
## Customize Transparency mode
280280

281281
```
282-
52 18 00
283-
For left bud
284-
[Enabled]
282+
12 18 00 [enabled]
283+
<left bud>
285284
[EQ1][EQ2][EQ3][EQ4][EQ5][EQ6][EQ7][EQ8]
286285
[Amplification]
287286
[Tone]
288287
[Conversation Boost]
289288
[Ambient Noise Reduction]
290-
00 0080 3F
291-
<same for the right bud>
289+
<repeat for right bud>
292290
```
293291

294-
<!-- demo packet
295-
52 18 00 00 00 00 00 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 00 00 80 3f 00 00 80 3f 00 00 80 3f 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 62 10 DA 41 00 00 80 3f 00 00 80 3f 00 00 80 3f
296-
297-
-->
298-
<!--
299-
5218 0000 0080 3F62 10DA 413D 0AF0 4160
300-
E50C 42AC 9C1E 421B 2F29 429E 6F33 4293
301-
1846 4293 1846 4206 9476 BF00 576E BB00
302-
0080 3F00 0080 3F62 10DA 413D 0AF0 4160
303-
E50C 42AC 9C1E 421B 2F29 429E 6F33 4293
304-
1846 4293 1846 4200 0080 BF00 576E BB00
305-
0080 3F00 0080 3F
306-
-->
307-
308-
<!--
309-
5218 0000 0000 0062 10DA 413D 0AF0 4160
310-
E50C 42AC 9C1E 421B 2F29 429E 6F33 4293
311-
1846 4293 1846 4206 9476 BF00 576E BB00
312-
0080 3F00 0080 3F62 10DA 413D 0AF0 4160
313-
E50C 42AC 9C1E 421B 2F29 429E 6F33 4293
314-
1846 4293 1846 4200 0080 BF00 576E BB00
315-
0080 3F00 0080 3F
316-
-->
317-
318-
All values are formatted as Little Endian from float values.
319-
| Data | Type | Value range |
320-
|---------------------|---------------|-------------|
321-
| Enabled | Little Endian | 0 or 1 |
322-
| EQ | Little Endian | 0 to 100 |
323-
| Amplification | Little Endian | -1 to 1 |
324-
| Tone | Little Endian | -1 to 1 |
325-
| Conversation Boost | Little Endian | 0 or 1 |
292+
293+
All values are formatted as IEEE 754 floats in little endian order.
294+
| Data | Type | Range |
295+
|-------------------------|---------------|-------|
296+
| Enabled | IEEE754 Float | 0/1 |
297+
| EQ | IEEE754 Float | 0-100 |
298+
| Amplification | IEEE754 Float | 0-2 |
299+
| Tone | IEEE754 Float | 0-2 |
300+
| Conversation Boost | IEEE754 Float | 0/1 |
301+
| Ambient Noise Reduction | IEEE754 Float | 0-1 |
302+
| Ambient Noise Reduction | IEEE754 Float | 0-1 |
326303

327304
> [!IMPORTANT]
328305
> Also send the [Headphone Accomodation](#headphone-accomodation) after this.

README.md

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@
1111

1212
## What is LibrePods?
1313

14-
LibrePods unlocks Apple's exclusive AirPods features on non-Apple devices. Get access to noise control modes, adaptive transparency, ear detection, battery status, and more - all the premium features you paid for but Apple locked to their ecosystem.
14+
LibrePods unlocks Apple's exclusive AirPods features on non-Apple devices. Get access to noise control modes, adaptive transparency, ear detection, hearing aid, customized transparency mode, battery status, and more - all the premium features you paid for but Apple locked to their ecosystem.
1515

1616
## Device Compatibility
1717

18-
| Status | Device | Features |
19-
|--------|--------|----------|
20-
|| AirPods Pro (2nd Gen) | Fully supported and tested |
21-
| ⚠️ | Other AirPods models | Basic features (battery status, ear detection) should work |
18+
| Status | Device | Features |
19+
| ------ | --------------------- | ---------------------------------------------------------- |
20+
|| AirPods Pro (2nd Gen) | Fully supported and tested |
21+
|| AirPods Pro (3rd Gen) | Fully supported (except heartrate monitoring) |
22+
| ⚠️ | Other AirPods models | Basic features (battery status, ear detection) should work |
2223

23-
Most features should work with any AirPods. Currently, testing is only performed with AirPods Pro 2.
24+
Most features should work with any AirPods. Currently, I've only got AirPods Pro 2 to test with.
2425

2526
## Key Features
2627

@@ -29,6 +30,9 @@ Most features should work with any AirPods. Currently, testing is only performed
2930
- **Battery Status**: Accurate battery levels
3031
- **Head Gestures**: Answer calls just by nodding your head
3132
- **Conversational Awareness**: Volume automatically lowers when you speak
33+
- **Hearing Aid\***
34+
- **Customize Transparency Mode\***
35+
- **Multi-device connectivity\*** (upto 2 devices)
3236
- **Other customizations**:
3337
- Rename your AirPods
3438
- Customize long-press actions
@@ -58,12 +62,18 @@ For installation and detailed info, see the [Linux README](/linux/README.md).
5862

5963
#### Screenshots
6064

61-
| | | |
62-
|-------------------|-------------------|-------------------|
63-
| ![Settings 1](/android/imgs/settings-1.png) | ![Settings 2](/android/imgs/settings-2.png) | ![Debug Screen](/android/imgs/debug.png) |
64-
| ![Battery Notification and QS Tile for NC Mode](/android/imgs/notification-and-qs.png) | ![Popup](/android/imgs/popup.png) | ![Head Tracking and Gestures](/android/imgs/head-tracking-and-gestures.png) |
65-
| ![Long Press Configuration](/android/imgs/long-press.png) | ![Widget](/android/imgs/widget.png) | ![Customizations 1](/android/imgs/customizations-1.png) |
66-
| ![Customizations 2](/android/imgs/customizations-2.png) | ![audio-popup](/android/imgs/audio-connected-island.png) | |
65+
| | | |
66+
| -------------------------------------------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------- |
67+
| ![Settings 1](/android/imgs/settings-1.png) | ![Settings 2](/android/imgs/settings-2.png) | ![Debug Screen](/android/imgs/debug.png) |
68+
| ![Battery Notification and QS Tile for NC Mode](/android/imgs/notification-and-qs.png) | ![Popup](/android/imgs/popup.png) | ![Head Tracking and Gestures](/android/imgs/head-tracking-and-gestures.png) |
69+
| ![Long Press Configuration](/android/imgs/long-press.png) | ![Widget](/android/imgs/widget.png) | ![Customizations 1](/android/imgs/customizations-1.png) |
70+
| ![Customizations 2](/android/imgs/customizations-2.png) | ![accessibility](/android/imgs/accessibility.png) | ![transparency](/android/imgs/transparency.png) |
71+
| ![hearing-aid](/android/imgs/hearing-aid.png) | ![hearing-test](/android/imgs/hearing-test.png) | ![hearing-aid-adjustments](/android/imgs/hearing-aid-adjustments.png) |
72+
73+
74+
here's a very unprofessional demo video
75+
76+
https://github.com/user-attachments/assets/43911243-0576-4093-8c55-89c1db5ea533
6777

6878
#### Root Requirement
6979

@@ -72,24 +82,44 @@ For installation and detailed info, see the [Linux README](/linux/README.md).
7282
>
7383
> There are **no exceptions** to the root requirement until Google merges the fix.
7484
85+
## Bluetooth DID (Device Identification) Hook
86+
87+
Turns out, if you change the manufacturerid to that of Apple, you get access to several special features!
88+
89+
### Multi-device Connectivity
90+
91+
Upto two devices can be simultaneously connected to AirPods, for audio and control both. Seamless connection switching. The same notification shows up on Apple device when Android takes over the AirPods as if it were an Apple device ("Move to iPhone"). Android also shows a popup when the other device takes over.
92+
93+
### Accessibility Settings and Hearing Aid
94+
95+
Accessibility settings like customizing transparency mode (amplification, balance, tone, conversation boost, and ambient noise reduction), and loud sound reduction can be configured.
96+
97+
The hearing aid feature can now also be used. Currently it can only be used to adjust the settings, not actually take a hearing test because it requires much more precision. It is much better to use an already available audiogram result.
98+
99+
>[!NOTE]
100+
> To enable these features, enable App Settings -> `act as Apple Device`.
101+
> This only works if you use the Xposed method or patch the library yourself. The root module method does not support this feature currently.
102+
75103
#### Installation Methods
76104

77105
##### Method 1: Xposed Module (Recommended)
78106
This method is less intrusive and should be tried first:
79107

80108
1. Install LSPosed, or another Xposed provider on your rooted device
81109
2. Download the LibrePods app from the releases section, and install it.
82-
3. Enable the Xposed module for the bluetooth app in your Xposed manager
83-
4. Follow the instructions in the app to set up the module.
84-
5. Open the app and connect your AirPods
110+
3. Enable the Xposed module for the bluetooth app in your Xposed manager.
111+
4. Disable unmount modules for the Bluetooth app if enabled.
112+
5. Follow the instructions in the app to set up the module.
113+
6. Open the app and connect your AirPods
85114

86115
##### Method 2: Root Module (Backup Option)
87116
If the Xposed method doesn't work for you:
88117

89118
1. Download the `btl2capfix.zip` module from the releases section
90119
2. Install it using your preferred root manager (KernelSU, Apatch, or Magisk).
91-
3. Reboot your device
92-
4. Connect your AirPods
120+
3. Disable Unmount modules for the Bluetooth aop if enabled.
121+
4. Reboot your device
122+
5. Connect your AirPods
93123

94124
##### Method 3: Patching it yourself
95125
If you prefer to patch the Bluetooth stack yourself, follow these steps:
@@ -111,25 +141,6 @@ If you're unfamiliar with these steps, search for tutorials online or ask in And
111141

112142
- When renaming your AirPods through the app, you'll need to re-pair them with your phone for the name change to take effect. This is a limitation of how Bluetooth device naming works on Android.
113143

114-
## Development Resources
115-
116-
For developers interested in the protocol details, check out the [AAP Definitions](/AAP%20Definitions.md) documentation.
117-
118-
## CrossDevice Stuff
119-
120-
> [!IMPORTANT]
121-
> This feature is still in early development and might not work as expected. No support is provided for this feature yet.
122-
123-
### Features in Development
124-
125-
- **Battery Status Sync**: Get battery status on any device when you connect your AirPods to one of them
126-
- **Cross-device Controls**: Control your AirPods from either device when connected to one
127-
- **Automatic Device Switching**: Seamlessly switch between Linux and Android devices based on active audio sources
128-
129-
Check out the demo below:
130-
131-
https://github.com/user-attachments/assets/d08f8a51-cd52-458b-8e55-9b44f4d5f3ab
132-
133144
## Star History
134145

135146
[![Star History Chart](https://api.star-history.com/svg?repos=kavishdevar/librepods&type=Date)](https://star-history.com/#kavishdevar/librepods&Date)

android/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
crowdin.yml
12
*.iml
23
.gradle
34
/local.properties

android/app/build.gradle.kts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@ plugins {
22
alias(libs.plugins.android.application)
33
alias(libs.plugins.kotlin.android)
44
alias(libs.plugins.kotlin.compose)
5+
alias(libs.plugins.aboutLibraries)
56
id("kotlin-parcelize")
67
}
78

89
android {
910
namespace = "me.kavishdevar.librepods"
10-
compileSdk = 35
11+
compileSdk = 36
1112

1213
defaultConfig {
1314
applicationId = "me.kavishdevar.librepods"
1415
minSdk = 28
15-
targetSdk = 35
16-
versionCode = 7
17-
versionName = "0.1.0-rc.4"
16+
targetSdk = 36
17+
versionCode = 8
18+
versionName = "0.2.0-beta.1"
1819
}
1920

2021
buildTypes {
@@ -43,6 +44,11 @@ android {
4344
version = "3.22.1"
4445
}
4546
}
47+
sourceSets {
48+
getByName("main") {
49+
res.srcDirs("src/main/res", "src/main/res-apple")
50+
}
51+
}
4652
}
4753

4854
dependencies {
@@ -62,5 +68,22 @@ dependencies {
6268
implementation(libs.haze)
6369
implementation(libs.haze.materials)
6470
implementation(libs.androidx.dynamicanimation)
65-
compileOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
71+
implementation(libs.androidx.compose.ui)
72+
debugImplementation(libs.androidx.compose.ui.tooling)
73+
implementation(libs.androidx.compose.foundation.layout)
74+
implementation(libs.aboutlibraries)
75+
implementation(libs.aboutlibraries.compose.m3)
76+
// compileOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
77+
// implementation(fileTree(mapOf("dir" to "lib", "include" to listOf("*.aar"))))
78+
compileOnly(files("libs/libxposed-api-100.aar"))
79+
debugImplementation(files("libs/backdrop-debug.aar"))
80+
releaseImplementation(files("libs/backdrop-release.aar"))
81+
}
82+
83+
aboutLibraries {
84+
export{
85+
prettyPrint = true
86+
excludeFields = listOf("generated")
87+
outputFile = file("src/main/res/raw/aboutlibraries.json")
88+
}
6689
}
125 KB
Binary file not shown.
119 KB
Binary file not shown.

android/app/src/main/AndroidManifest.xml

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
android:required="false" />
88

99
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
10-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
10+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"
11+
tools:ignore="ForegroundServicesPolicy" />
1112
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
1213
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"
1314
tools:ignore="ProtectedPermissions" />
@@ -30,11 +31,10 @@
3031
<uses-permission android:name="android.permission.INTERNET" />
3132
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
3233
tools:ignore="ScopedStorage" />
33-
3434
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
3535
android:maxSdkVersion="30" />
36-
37-
<protected-broadcast android:name="batterywidget.impl.action.update_bluetooth_data" />
36+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
37+
android:maxSdkVersion="30" />
3838

3939
<application
4040
android:allowBackup="true"
@@ -60,6 +60,7 @@
6060
android:name="android.appwidget.provider"
6161
android:resource="@xml/noise_control_widget_info" />
6262
</receiver>
63+
6364
<receiver
6465
android:name=".widgets.BatteryWidget"
6566
android:exported="false">
@@ -72,15 +73,6 @@
7273
android:resource="@xml/battery_widget_info" />
7374
</receiver>
7475

75-
<activity
76-
android:name=".CustomDevice"
77-
android:exported="true"
78-
android:label="@string/title_activity_custom_device"
79-
android:theme="@style/Theme.LibrePods">
80-
<intent-filter>
81-
<category android:name="android.intent.category.LAUNCHER" />
82-
</intent-filter>
83-
</activity>
8476
<activity
8577
android:name=".MainActivity"
8678
android:exported="true"
@@ -90,13 +82,13 @@
9082

9183
<category android:name="android.intent.category.LAUNCHER" />
9284
</intent-filter>
93-
<intent-filter android:autoVerify="true">
85+
<!-- <intent-filter android:autoVerify="true">
9486
<action android:name="android.intent.action.VIEW" />
9587
<category android:name="android.intent.category.DEFAULT" />
9688
<category android:name="android.intent.category.BROWSABLE" />
97-
<data android:scheme="librepods"
89+
<data android:scheme="librepods"
9890
android:host="add-magic-keys" />
99-
</intent-filter>
91+
</intent-filter> -->
10092
</activity>
10193

10294
<activity
@@ -124,7 +116,17 @@
124116
<action android:name="android.service.quicksettings.action.QS_TILE" />
125117
</intent-filter>
126118
</service>
127-
119+
<service
120+
android:name=".services.AppListenerService"
121+
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
122+
android:exported="true">
123+
<intent-filter>
124+
<action android:name="android.accessibilityservice.AccessibilityService" />
125+
</intent-filter>
126+
<meta-data
127+
android:name="android.accessibilityservice"
128+
android:resource="@xml/app_listener_service_config" />
129+
</service>
128130
<receiver
129131
android:name=".receivers.BootReceiver"
130132
android:enabled="true"

0 commit comments

Comments
 (0)