Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: d4rken-org/capod
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.13.0-rc0
Choose a base ref
...
head repository: d4rken-org/capod
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Mar 11, 2024

  1. Update strings.xml

    aga1314 authored and d4rken committed Mar 11, 2024
    Copy the full SHA
    68f81f9 View commit details
  2. Update preferences_support.xml

    aga1314 authored and d4rken committed Mar 11, 2024
    Copy the full SHA
    89049ee View commit details

Commits on Apr 5, 2024

  1. Copy the full SHA
    26fbfc0 View commit details

Commits on Apr 30, 2024

  1. Update translations

    d4rken committed Apr 30, 2024
    Copy the full SHA
    fdfc7f4 View commit details
  2. Thank the MagicPods project

    d4rken committed Apr 30, 2024
    Copy the full SHA
    d80a110 View commit details

Commits on Jun 26, 2024

  1. Switch to everything Material3 components

    This commit modifies all major elements of the UI for phones to use Material3 elements, including the toolbar.
    
    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    a9215fc View commit details
  2. Make the status bar transparent

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    1afb77e View commit details
  3. Make widgets consistent with each other

    Going by 2f9185e, it appears the label is preferred to be at the bottom
    
    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    d46fe35 View commit details
  4. Add wide variant of dual pod widget

    * Wide variant activates when the widget is larger than 3 columns in length
    
    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    9087be6 View commit details
  5. Switch all MaterialComponents for Material3 for Wear

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    08c095e View commit details
  6. Fix status bar icons in light theme

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    6f7b6e3 View commit details
  7. Annotate layout argument as LayoutRes

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    60a3039 View commit details
  8. Add more notes for the wide widgets

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    148cdf5 View commit details
  9. Log layout ID in createDualPodLayout

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    c6524d7 View commit details
  10. Fix up comment

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    7b474fb View commit details
  11. Enlarge the icons on wide widgets

    * Also move the case details to the centre and separate the text a little
    
    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 26, 2024
    Copy the full SHA
    bbfb735 View commit details
  12. Add PUSH_NOTIFICATIONS permission to AndroidManifest.xml for wearos (#…

    …203)
    
    * Add PUSH_NOTIFICATIONS permissions to AndroidManifest.xml for wearos
    
    Fixes #154
    
    * Fix typo in AndroidManifest.xml for wearos app
    kavishdevar authored Jun 26, 2024
    Copy the full SHA
    65a7b19 View commit details

Commits on Jun 27, 2024

  1. Implement support for different states in notification text

    Fixes #198
    
    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jun 27, 2024
    Copy the full SHA
    07a1179 View commit details

Commits on Jul 12, 2024

  1. Update com.google.android.material to 1.12.0

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jul 12, 2024
    Copy the full SHA
    8544983 View commit details
  2. Update all checkbox preferences to SUW switches

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jul 12, 2024
    Copy the full SHA
    a3b01a0 View commit details
  3. setCustomContentView() -> setCustomBigContentView()

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jul 12, 2024
    Copy the full SHA
    aa38f58 View commit details
  4. Add more spacing around the wide variant of dual pods widgets

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jul 12, 2024
    Copy the full SHA
    fbcd595 View commit details
  5. Prevent return@apply duplicates

    Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
    Ricky Cheung authored and d4rken committed Jul 12, 2024
    Copy the full SHA
    051677e View commit details
  6. Fix up-navigation behavior when doing onboarding

    Back button shouldn't take you dashboard -> onboarding or onboarding -> dashboard
    d4rken committed Jul 12, 2024
    Copy the full SHA
    2fca909 View commit details
  7. Fix app crash on launch if permission are not granted

    ```java
    12:49:29.433 AndroidRuntime                       E  FATAL EXCEPTION: main
                                                         Process: eu.darken.capod, PID: 15164
                                                         java.lang.SecurityException: Starting FGS with type connectedDevice callerApp=ProcessRecord{cb03698 15164:eu.darken.capod/u0a352} targetSDK=34 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE] any of the permissions allOf=false [android.permission.BLUETOOTH_ADVERTISE, android.permission.BLUETOOTH_CONNECT, android.permission.BLUETOOTH_SCAN, android.permission.CHANGE_NETWORK_STATE, android.permission.CHANGE_WIFI_STATE, android.permission.CHANGE_WIFI_MULTICAST_STATE, android.permission.NFC, android.permission.TRANSMIT_IR, android.permission.UWB_RANGING, USB Device, USB Accessory]
                                                         	at android.os.Parcel.createExceptionOrNull(Parcel.java:3242)
                                                         	at android.os.Parcel.createException(Parcel.java:3226)
                                                         	at android.os.Parcel.readException(Parcel.java:3209)
                                                         	at android.os.Parcel.readException(Parcel.java:3151)
                                                         	at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:7167)
                                                         	at android.app.Service.startForeground(Service.java:863)
                                                         	at androidx.work.impl.foreground.SystemForegroundService$Api31Impl.startForeground(SystemForegroundService.java:194)
                                                         	at androidx.work.impl.foreground.SystemForegroundService$1.run(SystemForegroundService.java:130)
                                                         	at android.os.Handler.handleCallback(Handler.java:959)
                                                         	at android.os.Handler.dispatchMessage(Handler.java:100)
                                                         	at android.os.Looper.loopOnce(Looper.java:232)
                                                         	at android.os.Looper.loop(Looper.java:317)
                                                         	at android.app.ActivityThread.main(ActivityThread.java:8699)
                                                         	at java.lang.reflect.Method.invoke(Native Method)
                                                         	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
                                                         	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
    d4rken committed Jul 12, 2024
    Copy the full SHA
    f2eb45d View commit details
  8. Copy the full SHA
    62886f0 View commit details
  9. Release: 2.14.0-rc0

    d4rken committed Jul 12, 2024
    Copy the full SHA
    02f6882 View commit details
  10. Fix crashes when entering settings

    Likely from #209
    d4rken committed Jul 12, 2024
    Copy the full SHA
    18ac05e View commit details
  11. Release: 2.14.1-rc0

    d4rken committed Jul 12, 2024
    Copy the full SHA
    788038b View commit details

Commits on Jul 26, 2024

  1. Improve BLE scanning

    The default "balanced" mode was reporting data too infrequently.
    d4rken committed Jul 26, 2024
    Copy the full SHA
    6708901 View commit details

Commits on Sep 23, 2024

  1. Add support for AirPods (Gen 4)

    Closes #225
    d4rken committed Sep 23, 2024
    Copy the full SHA
    42f2f5b View commit details
  2. Merge pull request #227 from d4rken-org/airpods-gen4

    Add support for AirPods (Gen 4 - no ANC)
    d4rken authored Sep 23, 2024
    Copy the full SHA
    5d953ee View commit details
  3. Add support for AirPods (Gen 4 with ANC)

    Closes #226
    d4rken committed Sep 23, 2024
    Copy the full SHA
    21b6cfc View commit details
  4. Merge pull request #228 from d4rken-org/airpods-gen4-ANC

    Add support for AirPods (Gen 4 with ANC)
    d4rken authored Sep 23, 2024
    Copy the full SHA
    77dc13d View commit details
  5. Update README.md

    d4rken authored Sep 23, 2024
    Copy the full SHA
    b1bf658 View commit details
  6. Copy the full SHA
    10c880a View commit details
  7. Fix WorkManager init crash

    ```
    Caused by java.lang.IllegalStateException: WorkManager is not initialized properly.  You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider.
      at androidx.work.impl.WorkManagerImpl.getInstance (WorkManagerImpl.java)
      at androidx.work.impl.foreground.SystemForegroundDispatcher.<init> (SystemForegroundDispatcher.java)
      at androidx.work.impl.foreground.SystemForegroundService.initializeDispatcher (SystemForegroundService.java)
      at androidx.work.impl.foreground.SystemForegroundService.onCreate (SystemForegroundService.java)
      at android.app.ActivityThread.handleCreateService (ActivityThread.java:4726)
    ```
    d4rken committed Sep 23, 2024
    Copy the full SHA
    0ee7915 View commit details
  8. Record debug logs without foreground service

    Some overhaul of log recording to get rid of the `FOREGROUND_SERVICE_SPECIAL_USE` which is a headache with Google
    d4rken committed Sep 23, 2024
    Copy the full SHA
    3eaf993 View commit details
  9. Release: 2.15.0-rc0

    d4rken committed Sep 23, 2024
    Copy the full SHA
    647300f View commit details

Commits on Sep 30, 2024

  1. Copy the full SHA
    858b86a View commit details

Commits on Nov 8, 2024

  1. Copy the full SHA
    663e2d3 View commit details
  2. Copy the full SHA
    6b922e8 View commit details
  3. Release: 2.16.0-rc0

    d4rken committed Nov 8, 2024
    Copy the full SHA
    fb0527b View commit details

Commits on Dec 5, 2024

  1. Update CLI tool

    d4rken committed Dec 5, 2024
    Copy the full SHA
    9c2ebd9 View commit details
  2. Update translations

    d4rken committed Dec 5, 2024
    Copy the full SHA
    f956625 View commit details
  3. Add thanks note

    d4rken committed Dec 5, 2024
    Copy the full SHA
    1ebb231 View commit details
Showing with 1,389 additions and 701 deletions.
  1. +4 −0 README.md
  2. +1 −1 VERSION
  3. +10 −4 app-common/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt
  4. +14 −0 app-common/src/main/java/eu/darken/capod/common/preferences/MaterialSwitchPreference.kt
  5. +12 −0 app-common/src/main/java/eu/darken/capod/pods/core/PodDevice.kt
  6. +26 −3 app-common/src/main/java/eu/darken/capod/pods/core/apple/AppleFactoryModule.kt
  7. +70 −0 app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen4.kt
  8. +70 −0 app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen4Anc.kt
  9. +2 −2 app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt
  10. +69 −0 app-common/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMaxUsbc.kt
  11. +8 −0 app-common/src/main/res/layout/preference_material_switch.xml
  12. +0 −4 app-common/src/main/res/values-ar/strings.xml
  13. +0 −4 app-common/src/main/res/values-be/strings.xml
  14. +0 −5 app-common/src/main/res/values-ca/strings.xml
  15. +0 −5 app-common/src/main/res/values-cs/strings.xml
  16. +0 −4 app-common/src/main/res/values-de/strings.xml
  17. +0 −4 app-common/src/main/res/values-el/strings.xml
  18. +0 −4 app-common/src/main/res/values-es-rAR/strings.xml
  19. +0 −3 app-common/src/main/res/values-es-rMX/strings.xml
  20. +0 −4 app-common/src/main/res/values-es/strings.xml
  21. +0 −2 app-common/src/main/res/values-et-rEE/strings.xml
  22. +0 −4 app-common/src/main/res/values-fr/strings.xml
  23. +0 −2 app-common/src/main/res/values-hi-rIN/strings.xml
  24. +0 −5 app-common/src/main/res/values-in/strings.xml
  25. +0 −5 app-common/src/main/res/values-it/strings.xml
  26. +0 −2 app-common/src/main/res/values-iw/strings.xml
  27. +0 −4 app-common/src/main/res/values-ja/strings.xml
  28. +0 −4 app-common/src/main/res/values-ko/strings.xml
  29. +0 −4 app-common/src/main/res/values-ms/strings.xml
  30. +0 −6 app-common/src/main/res/values-nl/strings.xml
  31. +0 −5 app-common/src/main/res/values-no/strings.xml
  32. +0 −4 app-common/src/main/res/values-pl/strings.xml
  33. +0 −4 app-common/src/main/res/values-pt-rBR/strings.xml
  34. +0 −5 app-common/src/main/res/values-pt/strings.xml
  35. +57 −1 app-common/src/main/res/values-ro/strings.xml
  36. +0 −4 app-common/src/main/res/values-ru/strings.xml
  37. +0 −4 app-common/src/main/res/values-sk/strings.xml
  38. +0 −4 app-common/src/main/res/values-tr/strings.xml
  39. +0 −4 app-common/src/main/res/values-uk/strings.xml
  40. +0 −3 app-common/src/main/res/values-zh-rCN/strings.xml
  41. +0 −3 app-common/src/main/res/values-zh-rHK/strings.xml
  42. +0 −3 app-common/src/main/res/values-zh-rTW/strings.xml
  43. +1 −0 app-common/src/main/res/values/strings.xml
  44. +46 −0 app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen4AncTest.kt
  45. +46 −0 app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen4Test.kt
  46. +32 −0 app-common/src/test/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMaxUsbcTest.kt
  47. +3 −2 app-wear/src/main/AndroidManifest.xml
  48. +2 −2 app-wear/src/main/res/layout/overview_bluetooth_disabled_item.xml
  49. +2 −2 app-wear/src/main/res/layout/overview_nomaindevice_item.xml
  50. +5 −4 app-wear/src/main/res/layout/overview_permission_item.xml
  51. +4 −2 app-wear/src/main/res/values-af-rZA/strings.xml
  52. +4 −2 app-wear/src/main/res/values-am/strings.xml
  53. +4 −2 app-wear/src/main/res/values-ar/strings.xml
  54. +4 −2 app-wear/src/main/res/values-az/strings.xml
  55. +4 −2 app-wear/src/main/res/values-be/strings.xml
  56. +4 −2 app-wear/src/main/res/values-bg/strings.xml
  57. +4 −2 app-wear/src/main/res/values-bn-rBD/strings.xml
  58. +4 −2 app-wear/src/main/res/values-ca/strings.xml
  59. +4 −2 app-wear/src/main/res/values-cs/strings.xml
  60. +4 −2 app-wear/src/main/res/values-da/strings.xml
  61. +4 −2 app-wear/src/main/res/values-de/strings.xml
  62. +4 −2 app-wear/src/main/res/values-el/strings.xml
  63. +4 −2 app-wear/src/main/res/values-es-rAR/strings.xml
  64. +4 −2 app-wear/src/main/res/values-es-rMX/strings.xml
  65. +4 −2 app-wear/src/main/res/values-es/strings.xml
  66. +4 −2 app-wear/src/main/res/values-et-rEE/strings.xml
  67. +4 −2 app-wear/src/main/res/values-eu-rES/strings.xml
  68. +4 −2 app-wear/src/main/res/values-fa/strings.xml
  69. +4 −2 app-wear/src/main/res/values-fi/strings.xml
  70. +4 −2 app-wear/src/main/res/values-fil/strings.xml
  71. +4 −2 app-wear/src/main/res/values-fr/strings.xml
  72. +4 −2 app-wear/src/main/res/values-gl-rES/strings.xml
  73. +4 −2 app-wear/src/main/res/values-hi-rIN/strings.xml
  74. +4 −2 app-wear/src/main/res/values-hr/strings.xml
  75. +4 −2 app-wear/src/main/res/values-hu/strings.xml
  76. +4 −2 app-wear/src/main/res/values-hy-rAM/strings.xml
  77. +4 −2 app-wear/src/main/res/values-in/strings.xml
  78. +4 −2 app-wear/src/main/res/values-is/strings.xml
  79. +4 −2 app-wear/src/main/res/values-it/strings.xml
  80. +4 −2 app-wear/src/main/res/values-iw/strings.xml
  81. +4 −2 app-wear/src/main/res/values-ja/strings.xml
  82. +4 −2 app-wear/src/main/res/values-ka-rGE/strings.xml
  83. +4 −2 app-wear/src/main/res/values-km-rKH/strings.xml
  84. +4 −2 app-wear/src/main/res/values-kmr-rTR/strings.xml
  85. +4 −2 app-wear/src/main/res/values-kn-rIN/strings.xml
  86. +4 −2 app-wear/src/main/res/values-ko/strings.xml
  87. +4 −2 app-wear/src/main/res/values-ky-rKG/strings.xml
  88. +4 −2 app-wear/src/main/res/values-lo-rLA/strings.xml
  89. +4 −2 app-wear/src/main/res/values-lt/strings.xml
  90. +4 −2 app-wear/src/main/res/values-lv/strings.xml
  91. +4 −2 app-wear/src/main/res/values-mk-rMK/strings.xml
  92. +4 −2 app-wear/src/main/res/values-ml-rIN/strings.xml
  93. +4 −2 app-wear/src/main/res/values-mn-rMN/strings.xml
  94. +4 −2 app-wear/src/main/res/values-mr-rIN/strings.xml
  95. +4 −2 app-wear/src/main/res/values-ms/strings.xml
  96. +4 −2 app-wear/src/main/res/values-my-rMM/strings.xml
  97. +4 −2 app-wear/src/main/res/values-ne-rNP/strings.xml
  98. +4 −2 app-wear/src/main/res/values-nl/strings.xml
  99. +4 −2 app-wear/src/main/res/values-no/strings.xml
  100. +4 −2 app-wear/src/main/res/values-pl/strings.xml
  101. +4 −2 app-wear/src/main/res/values-pt-rBR/strings.xml
  102. +4 −2 app-wear/src/main/res/values-pt/strings.xml
  103. +4 −2 app-wear/src/main/res/values-rm/strings.xml
  104. +4 −2 app-wear/src/main/res/values-ro/strings.xml
  105. +4 −2 app-wear/src/main/res/values-ru/strings.xml
  106. +4 −2 app-wear/src/main/res/values-sc-rIT/strings.xml
  107. +4 −2 app-wear/src/main/res/values-si-rLK/strings.xml
  108. +4 −2 app-wear/src/main/res/values-sk/strings.xml
  109. +4 −2 app-wear/src/main/res/values-sl/strings.xml
  110. +4 −2 app-wear/src/main/res/values-sr/strings.xml
  111. +4 −2 app-wear/src/main/res/values-sv/strings.xml
  112. +4 −2 app-wear/src/main/res/values-sw/strings.xml
  113. +4 −2 app-wear/src/main/res/values-ta-rIN/strings.xml
  114. +4 −2 app-wear/src/main/res/values-te-rIN/strings.xml
  115. +4 −2 app-wear/src/main/res/values-th/strings.xml
  116. +4 −2 app-wear/src/main/res/values-tr/strings.xml
  117. +4 −2 app-wear/src/main/res/values-uk/strings.xml
  118. +4 −2 app-wear/src/main/res/values-ur-rIN/strings.xml
  119. +4 −2 app-wear/src/main/res/values-uz/strings.xml
  120. +4 −2 app-wear/src/main/res/values-vi/strings.xml
  121. +4 −2 app-wear/src/main/res/values-zh-rCN/strings.xml
  122. +4 −2 app-wear/src/main/res/values-zh-rHK/strings.xml
  123. +4 −2 app-wear/src/main/res/values-zh-rTW/strings.xml
  124. +4 −2 app-wear/src/main/res/values-zu/strings.xml
  125. +5 −0 app/build.gradle.kts
  126. +5 −1 app/src/foss/res/values-ro/strings.xml
  127. +4 −1 app/src/gplay/res/values-ro/strings.xml
  128. +9 −10 app/src/main/AndroidManifest.xml
  129. +5 −4 app/src/main/java/eu/darken/capod/common/debug/recording/core/RecorderModule.kt
  130. +0 −115 app/src/main/java/eu/darken/capod/common/debug/recording/core/RecorderService.kt
  131. +1 −1 app/src/main/java/eu/darken/capod/common/debug/recording/ui/RecorderActivityVM.kt
  132. +24 −0 app/src/main/java/eu/darken/capod/common/debug/recording/ui/RecorderConsentDialog.kt
  133. +0 −17 app/src/main/java/eu/darken/capod/main/ui/settings/general/debug/DebugSettingsFragment.kt
  134. +0 −12 app/src/main/java/eu/darken/capod/main/ui/settings/general/debug/DebugSettingsFragmentVM.kt
  135. +27 −19 app/src/main/java/eu/darken/capod/main/ui/settings/support/SupportFragment.kt
  136. +12 −8 app/src/main/java/eu/darken/capod/main/ui/settings/support/SupportFragmentVM.kt
  137. +43 −3 app/src/main/java/eu/darken/capod/main/ui/widget/WidgetProvider.kt
  138. +2 −2 app/src/main/java/eu/darken/capod/monitor/core/worker/MonitorWorker.kt
  139. +66 −1 app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt
  140. +6 −6 app/src/main/java/eu/darken/capod/reaction/ui/ReactionSettingsFragment.kt
  141. +10 −0 app/src/main/res/drawable/ic_cancel.xml
  142. +6 −6 app/src/main/res/layout/debug_recording_activity.xml
  143. +1 −1 app/src/main/res/layout/main_fragment.xml
  144. +5 −4 app/src/main/res/layout/onboarding_fragment.xml
  145. +2 −2 app/src/main/res/layout/overview_bluetooth_disabled_item.xml
  146. +2 −2 app/src/main/res/layout/overview_nomaindevice_item.xml
  147. +5 −5 app/src/main/res/layout/overview_permission_item.xml
  148. +6 −6 app/src/main/res/layout/overview_pods_dual_item.xml
  149. +5 −5 app/src/main/res/layout/overview_pods_single_item.xml
  150. +7 −7 app/src/main/res/layout/overview_pods_unknown_item.xml
  151. +5 −5 app/src/main/res/layout/popup_notification_dual_pods.xml
  152. +3 −3 app/src/main/res/layout/popup_notification_single_pods.xml
  153. +1 −1 app/src/main/res/layout/settings_fragment.xml
  154. +1 −1 app/src/main/res/layout/troubleshooter_fragment.xml
  155. 0 app/src/main/res/layout/{widget_pod_dual_layout.xml → widget_pod_dual_compact_layout.xml}
  156. +130 −0 app/src/main/res/layout/widget_pod_dual_wide_layout.xml
  157. +10 −10 app/src/main/res/layout/widget_pod_single_layout.xml
  158. +5 −1 app/src/main/res/navigation/nav_graph.xml
  159. +0 −3 app/src/main/res/values-ar/strings.xml
  160. +0 −2 app/src/main/res/values-az/strings.xml
  161. +0 −3 app/src/main/res/values-be/strings.xml
  162. +0 −3 app/src/main/res/values-ca/strings.xml
  163. +0 −3 app/src/main/res/values-cs/strings.xml
  164. +3 −7 app/src/main/res/values-de/strings.xml
  165. +0 −3 app/src/main/res/values-el/strings.xml
  166. +0 −2 app/src/main/res/values-es-rMX/strings.xml
  167. +0 −3 app/src/main/res/values-es/strings.xml
  168. +1 −3 app/src/main/res/values-fa/strings.xml
  169. +0 −3 app/src/main/res/values-fr/strings.xml
  170. +0 −2 app/src/main/res/values-hu/strings.xml
  171. +0 −3 app/src/main/res/values-in/strings.xml
  172. +0 −4 app/src/main/res/values-it/strings.xml
  173. +0 −2 app/src/main/res/values-iw/strings.xml
  174. +0 −3 app/src/main/res/values-ja/strings.xml
  175. +0 −2 app/src/main/res/values-ko/strings.xml
  176. +0 −2 app/src/main/res/values-ms/strings.xml
  177. +1 −0 app/src/main/res/values-night/themes.xml
  178. +0 −3 app/src/main/res/values-nl/strings.xml
  179. +0 −3 app/src/main/res/values-no/strings.xml
  180. +4 −7 app/src/main/res/values-pl/strings.xml
  181. +0 −3 app/src/main/res/values-pt-rBR/strings.xml
  182. +0 −4 app/src/main/res/values-pt/strings.xml
  183. +105 −1 app/src/main/res/values-ro/strings.xml
  184. +0 −2 app/src/main/res/values-ru/strings.xml
  185. +0 −3 app/src/main/res/values-sk/strings.xml
  186. +1 −5 app/src/main/res/values-tr/strings.xml
  187. +0 −3 app/src/main/res/values-uk/strings.xml
  188. +0 −2 app/src/main/res/values-vi/strings.xml
  189. +0 −3 app/src/main/res/values-zh-rCN/strings.xml
  190. +0 −3 app/src/main/res/values-zh-rHK/strings.xml
  191. +0 −3 app/src/main/res/values-zh-rTW/strings.xml
  192. +7 −2 app/src/main/res/values/strings.xml
  193. +9 −4 app/src/main/res/values/styles.xml
  194. +2 −1 app/src/main/res/values/themes.xml
  195. +18 −0 app/src/main/res/xml/preferences_acknowledgements.xml
  196. +3 −8 app/src/main/res/xml/preferences_debug.xml
  197. +4 −4 app/src/main/res/xml/preferences_general.xml
  198. +8 −8 app/src/main/res/xml/preferences_reactions.xml
  199. +5 −13 app/src/main/res/xml/preferences_support.xml
  200. +1 −1 buildSrc/src/main/java/Dependencies.kt
  201. BIN crowdin-cli.jar
  202. +4 −0 fastlane/Fastfile
  203. +2 −0 fastlane/metadata/android/en-US/changelogs/21400000.txt
  204. +2 −0 fastlane/metadata/android/en-US/changelogs/21401000.txt
  205. +2 −0 fastlane/metadata/android/en-US/changelogs/21500000.txt
  206. +2 −0 fastlane/metadata/android/en-US/changelogs/21600000.txt
  207. +13 −13 fastlane/metadata/android/ro/full_description.txt
  208. +1 −1 fastlane/metadata/android/ro/short_description.txt
  209. +1 −1 fastlane/metadata/android/ro/title.txt
  210. +1 −1 version.properties
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -26,6 +26,8 @@ Currently supported models:
* AirPods 1. Generation
* AirPods 2. Generation
* AirPods 3. Generation
* AirPods 4. Generation
* AirPods 4. Generation with ANC
* AirPods Pro 1. Generation
* AirPods Pro 2. Generation
* AirPods Pro 2. Generation (USB-C)
@@ -78,6 +80,8 @@ Currently supported models:
Travis & Rye, Erik & Sipes, Brandon & Teplov, Sam. (2019). Handoff All Your Privacy – A Review of Apple’s Bluetooth
Low Energy Continuity Protocol. Proceedings on Privacy Enhancing Technologies. 2019. 34-53. 10.2478/popets-2019-0057.
* Celosia, Guillaume. (2020). Privacy Challenges in Wireless Communications of the Internet of Things.
* The [MagicPods](https://github.com/steam3d/MagicPods-Windows) project. If you are looking for "CAPod for Windows",
check it out.

## License

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.13.0-rc0 21300000
2.16.0-rc0 21600000
Original file line number Diff line number Diff line change
@@ -9,13 +9,19 @@ import android.bluetooth.le.ScanSettings
import android.content.Context
import android.content.Intent
import dagger.hilt.android.qualifiers.ApplicationContext
import eu.darken.capod.common.debug.logging.Logging.Priority.*
import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.notifications.PendingIntentCompat
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -132,12 +138,12 @@ class BleScanner @Inject constructor(
ScannerMode.LOW_POWER -> {
setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
setMatchMode(ScanSettings.MATCH_MODE_STICKY)
setNumOfMatches(ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT)
setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
}
ScannerMode.BALANCED -> {
setScanMode(ScanSettings.SCAN_MODE_BALANCED)
setMatchMode(ScanSettings.MATCH_MODE_STICKY)
setNumOfMatches(ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT)
setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
}
ScannerMode.LOW_LATENCY -> {
setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package eu.darken.capod.common.preferences

import android.content.Context
import android.util.AttributeSet
import androidx.preference.SwitchPreferenceCompat

class MaterialSwitchPreference(context: Context, attrs: AttributeSet?) :
SwitchPreferenceCompat(context, attrs) {

init {
// Use material switch
widgetLayoutResource = eu.darken.capod.common.R.layout.preference_material_switch
}
}
12 changes: 12 additions & 0 deletions app-common/src/main/java/eu/darken/capod/pods/core/PodDevice.kt
Original file line number Diff line number Diff line change
@@ -83,6 +83,14 @@ interface PodDevice {
"AirPods (Gen 3)",
R.drawable.devic_airpods_gen2_both,
),
@Json(name = "airpods.gen4") AIRPODS_GEN4(
"AirPods (Gen 4)",
R.drawable.devic_airpods_gen2_both,
),
@Json(name = "airpods.gen4.anc") AIRPODS_GEN4_ANC(
"AirPods (Gen 4 ANC)",
R.drawable.devic_airpods_gen2_both,
),
@Json(name = "airpods.pro") AIRPODS_PRO(
"AirPods Pro",
R.drawable.devic_airpods_pro2_both
@@ -99,6 +107,10 @@ interface PodDevice {
"AirPods Max",
R.drawable.devic_headphones_generic
),
@Json(name = "airpods.max.usbc") AIRPODS_MAX_USBC(
"AirPods Max USB-C",
R.drawable.devic_headphones_generic
),
@Json(name = "beats.flex") BEATS_FLEX(
"Beats Flex"
),
Original file line number Diff line number Diff line change
@@ -5,9 +5,29 @@ import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import eu.darken.capod.pods.core.apple.airpods.*
import eu.darken.capod.pods.core.apple.beats.*
import eu.darken.capod.pods.core.apple.misc.*
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen1
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen2
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen3
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen4
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen4Anc
import eu.darken.capod.pods.core.apple.airpods.AirPodsMax
import eu.darken.capod.pods.core.apple.airpods.AirPodsMaxUsbc
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro2
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro2Usbc
import eu.darken.capod.pods.core.apple.beats.BeatsFitPro
import eu.darken.capod.pods.core.apple.beats.BeatsFlex
import eu.darken.capod.pods.core.apple.beats.BeatsSolo3
import eu.darken.capod.pods.core.apple.beats.BeatsStudio3
import eu.darken.capod.pods.core.apple.beats.BeatsX
import eu.darken.capod.pods.core.apple.beats.PowerBeats3
import eu.darken.capod.pods.core.apple.beats.PowerBeats4
import eu.darken.capod.pods.core.apple.beats.PowerBeatsPro
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen1
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen2
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen3
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsPro
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsPro2

@InstallIn(SingletonComponent::class)
@Module
@@ -16,11 +36,14 @@ abstract class AppleFactoryModule {
@Binds @IntoSet abstract fun airPodsGen1(factory: AirPodsGen1.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsGen2(factory: AirPodsGen2.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsGen3(factory: AirPodsGen3.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsGen4(factory: AirPodsGen4.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsGen4Anc(factory: AirPodsGen4Anc.Factory): ApplePodsFactory<out ApplePods>

@Binds @IntoSet abstract fun airPodsPro(factory: AirPodsPro.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsPro2(factory: AirPodsPro2.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsPro2Usbc(factory: AirPodsPro2Usbc.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsMax(factory: AirPodsMax.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun airPodsMax2(factory: AirPodsMaxUsbc.Factory): ApplePodsFactory<out ApplePods>

@Binds @IntoSet abstract fun beatsFlex(factory: BeatsFlex.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun beatsSolo3(factory: BeatsSolo3.Factory): ApplePodsFactory<out ApplePods>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package eu.darken.capod.pods.core.apple.airpods

import eu.darken.capod.common.bluetooth.BleScanResult
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.pods.core.PodDevice
import eu.darken.capod.pods.core.apple.ApplePods
import eu.darken.capod.pods.core.apple.DualApplePods
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
import java.time.Instant
import javax.inject.Inject

data class AirPodsGen4(
override val identifier: PodDevice.Id = PodDevice.Id(),
override val seenLastAt: Instant = Instant.now(),
override val seenFirstAt: Instant = Instant.now(),
override val seenCounter: Int = 1,
override val scanResult: BleScanResult,
override val proximityMessage: ProximityPairing.Message,
override val reliability: Float = PodDevice.BASE_CONFIDENCE,
private val rssiAverage: Int? = null,
private val cachedBatteryPercentage: Float? = null,
private val cachedCaseState: DualApplePods.LidState? = null
) : DualApplePods, HasStateDetectionAirPods {

override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN4

override val batteryCasePercent: Float?
get() = super.batteryCasePercent ?: cachedBatteryPercentage

override val caseLidState: DualApplePods.LidState
get() = cachedCaseState ?: super.caseLidState

override val rssi: Int
get() = rssiAverage ?: super<DualApplePods>.rssi

class Factory @Inject constructor() : DualApplePodsFactory(TAG) {

override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
}

override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
var basic = AirPodsGen4(scanResult = scanResult, proximityMessage = message)
val result = searchHistory(basic)

if (result != null) basic = basic.copy(identifier = result.id)
updateHistory(basic)

if (result == null) return basic

return basic.copy(
identifier = result.id,
seenFirstAt = result.seenFirstAt,
seenLastAt = scanResult.receivedAt,
seenCounter = result.seenCounter,
reliability = result.reliability,
cachedBatteryPercentage = result.getLatestCaseBattery(),
rssiAverage = result.rssiSmoothed(basic.rssi),
cachedCaseState = result.getLatestCaseLidState(basic)
)
}

}

companion object {
private val DEVICE_CODE = 0x1920.toUShort()
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Gen4")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package eu.darken.capod.pods.core.apple.airpods

import eu.darken.capod.common.bluetooth.BleScanResult
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.pods.core.PodDevice
import eu.darken.capod.pods.core.apple.ApplePods
import eu.darken.capod.pods.core.apple.DualApplePods
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
import java.time.Instant
import javax.inject.Inject

data class AirPodsGen4Anc(
override val identifier: PodDevice.Id = PodDevice.Id(),
override val seenLastAt: Instant = Instant.now(),
override val seenFirstAt: Instant = Instant.now(),
override val seenCounter: Int = 1,
override val scanResult: BleScanResult,
override val proximityMessage: ProximityPairing.Message,
override val reliability: Float = PodDevice.BASE_CONFIDENCE,
private val rssiAverage: Int? = null,
private val cachedBatteryPercentage: Float? = null,
private val cachedCaseState: DualApplePods.LidState? = null
) : DualApplePods, HasStateDetectionAirPods {

override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN4_ANC

override val batteryCasePercent: Float?
get() = super.batteryCasePercent ?: cachedBatteryPercentage

override val caseLidState: DualApplePods.LidState
get() = cachedCaseState ?: super.caseLidState

override val rssi: Int
get() = rssiAverage ?: super<DualApplePods>.rssi

class Factory @Inject constructor() : DualApplePodsFactory(TAG) {

override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
}

override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
var basic = AirPodsGen4Anc(scanResult = scanResult, proximityMessage = message)
val result = searchHistory(basic)

if (result != null) basic = basic.copy(identifier = result.id)
updateHistory(basic)

if (result == null) return basic

return basic.copy(
identifier = result.id,
seenFirstAt = result.seenFirstAt,
seenLastAt = scanResult.receivedAt,
seenCounter = result.seenCounter,
reliability = result.reliability,
cachedBatteryPercentage = result.getLatestCaseBattery(),
rssiAverage = result.rssiSmoothed(basic.rssi),
cachedCaseState = result.getLatestCaseLidState(basic)
)
}

}

companion object {
private val DEVICE_CODE = 0x1B20.toUShort()
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Gen4-ANC")
}
}
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ data class AirPodsMax(
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {

override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
getModelInfo().dirty == DEVICE_CODE_DIRTY && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
}

override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
@@ -63,7 +63,7 @@ data class AirPodsMax(
}

companion object {
private val DEVICE_CODE_DIRTY = 10.toUByte()
private val DEVICE_CODE = 0x0A20.toUShort()
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Max")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package eu.darken.capod.pods.core.apple.airpods

import eu.darken.capod.common.bluetooth.BleScanResult
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.isBitSet
import eu.darken.capod.pods.core.HasChargeDetection
import eu.darken.capod.pods.core.HasEarDetection
import eu.darken.capod.pods.core.PodDevice
import eu.darken.capod.pods.core.apple.ApplePods
import eu.darken.capod.pods.core.apple.HasAppleColor
import eu.darken.capod.pods.core.apple.SingleApplePods
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
import java.time.Instant
import javax.inject.Inject

data class AirPodsMaxUsbc(
override val identifier: PodDevice.Id = PodDevice.Id(),
override val seenLastAt: Instant = Instant.now(),
override val seenFirstAt: Instant = Instant.now(),
override val seenCounter: Int = 1,
override val scanResult: BleScanResult,
override val proximityMessage: ProximityPairing.Message,
override val reliability: Float = PodDevice.BASE_CONFIDENCE,
private val rssiAverage: Int? = null,
) : SingleApplePods, HasEarDetection, HasChargeDetection, HasAppleColor {

override val model: PodDevice.Model = PodDevice.Model.AIRPODS_MAX_USBC

override val rssi: Int
get() = rssiAverage ?: super<SingleApplePods>.rssi

override val isHeadsetBeingCharged: Boolean
get() = rawFlags.isBitSet(0)

override val isBeingWorn: Boolean
get() = rawStatus.isBitSet(5)

class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {

override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
}

override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
var basic = AirPodsMaxUsbc(scanResult = scanResult, proximityMessage = message)
val result = searchHistory(basic)

if (result != null) basic = basic.copy(identifier = result.id)
updateHistory(basic)

if (result == null) return basic

return basic.copy(
identifier = result.id,
seenFirstAt = result.seenFirstAt,
seenLastAt = scanResult.receivedAt,
seenCounter = result.seenCounter,
reliability = result.reliability,
rssiAverage = result.rssiSmoothed(basic.rssi),
)
}
}

companion object {
private val DEVICE_CODE = 0x1F20.toUShort()
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Max", "USBC")
}
}
8 changes: 8 additions & 0 deletions app-common/src/main/res/layout/preference_material_switch.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:focusable="false" />
Loading