Compare commits

...
12 Commits
Author SHA1 Message Date
darken 513bd891af Release: 2.13.0-rc0 2024-02-25 13:30:10 +01:00
darken 37cd753ab8 Update README 2024-02-25 13:29:13 +01:00
darken 34bf2311b4 Add support for PowerBeats4
Thanks to @docgalaxyblock
2024-02-25 13:29:13 +01:00
darken a86093f617 Update translations 2024-02-25 13:16:19 +01:00
Matthias Urhahn 71f66e6004 Merge pull request #182 from JerretQueen/main
Onboarding typo fixed, dual pods layout realigned.
2024-02-25 13:12:31 +01:00
Matthias Urhahn 2d1ab85e01 Update README.md 2024-02-25 13:11:46 +01:00
Matthias Urhahn f029eb9102 Merge pull request #179 from hwlnx/patch-1
Update strings.xml
2024-02-25 13:06:15 +01:00
Matthias Urhahn 471837ab88 Update gradle-wrapper.properties 2024-02-25 13:05:05 +01:00
Matthias Urhahn 1e80d742cc Update build.gradle.kts 2024-02-25 13:04:38 +01:00
Matthias Urhahn 16b6273938 Update build.gradle.kts 2024-02-25 13:04:08 +01:00
JerretQueen 3407370563 1. Fixed a typo in @string/onboarding_body2. The message now correctly says "implementation" instead of "implemtation".
2. Changed layout of overview_pods_dual_item.xml so that the left and right pod status are properly lined up with each other.
2023-12-30 00:14:24 -06:00
hwlnx 3cda73a36c Update strings.xml 2023-11-19 20:05:42 +01:00
19 changed files with 209 additions and 39 deletions
+3 -1
View File
@@ -4,7 +4,8 @@
[![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/d4rken-org/capod?include_prereleases)](https://github.com/d4rken-org/capod/releases/latest)
[![Code tests & eval](https://github.com/d4rken-org/capod/actions/workflows/code-checks.yml/badge.svg)](https://github.com/d4rken/capod/actions/workflows/code-checks.yml)
[![Crowdin](https://badges.crowdin.net/capod/localized.svg)](https://crowdin.com/project/capod)
[![Github All Releases](https://img.shields.io/github/downloads/d4rken-org/capod/total.svg)](https://github.com/d4rken-org/capod/releases/latest)
[![Github Downloads](https://img.shields.io/github/downloads/d4rken-org/capod/total.svg?label=GitHub%20Downloads&logo=github)](https://github.com/d4rken-org/capod/edit/main/README.md#download)
[![Google Play Downloads](https://img.shields.io/endpoint?color=green&logo=google-play&logoColor=green&url=https%3A%2F%2Fplay.cuzi.workers.dev%2Fplay%3Fi%3Deu.darken.capod%26l%3DGoogle%2520Play%26m%3D%24totalinstalls)](https://github.com/d4rken-org/capod/edit/main/README.md#download)
A companion app that adds support for AirPod specific features to Android:
@@ -31,6 +32,7 @@ Currently supported models:
* AirPods Max
* Power Beats Pro
* Power Beats 3
* Power Beats 4
* Beats Solo 3
* Beats Studio 3
* Beats X
+1 -1
View File
@@ -1 +1 @@
2.12.1-rc0 21201000
2.13.0-rc0 21300000
@@ -114,6 +114,9 @@ interface PodDevice {
@Json(name = "beats.powerbeats.3") POWERBEATS_3(
"Power Beats 3"
),
@Json(name = "beats.powerbeats.4") POWERBEATS_4(
"Power Beats 4"
),
@Json(name = "beats.powerbeats.pro") POWERBEATS_PRO(
"Power Beats Pro"
),
@@ -27,6 +27,7 @@ abstract class AppleFactoryModule {
@Binds @IntoSet abstract fun beatsStudio3(factory: BeatsStudio3.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun beatsX(factory: BeatsX.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun powerBeats3(factory: PowerBeats3.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun powerBeats4(factory: PowerBeats4.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun powerBeatsPro(factory: PowerBeatsPro.Factory): ApplePodsFactory<out ApplePods>
@Binds @IntoSet abstract fun beatsFitPro(factory: BeatsFitPro.Factory): ApplePodsFactory<out ApplePods>
@@ -0,0 +1,60 @@
package eu.darken.capod.pods.core.apple.beats
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.SingleApplePods
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
import eu.darken.capod.pods.core.apple.airpods.HasStateDetectionAirPods
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
import java.time.Instant
import javax.inject.Inject
data class PowerBeats4(
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, HasStateDetectionAirPods {
override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_4
override val rssi: Int
get() = rssiAverage ?: super<SingleApplePods>.rssi
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 = PowerBeats4(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 = 0x0D20.toUShort()
private val TAG = logTag("PodDevice", "Beats", "PowerBeats", "4")
}
}
@@ -59,4 +59,5 @@
<string name="last_seen_x">آخر ظهور: %s</string>
<string name="first_seen_x">أول ظهور:%s</string>
<string name="permission_post_notifications_label"></string>
<string name="permission_post_notifications_description">"اسمح لـلتطبيق بإظهار الإشعارات المتعلقة بسماعات الأذن الخاصة بك، على سبيل المثال. حالتهم الحالية خلال الاتصال."</string>
</resources>
@@ -2,6 +2,7 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_name">CAPod</string>
<string name="app_name_pro">CAPod Pro</string>
<string name="app_name_foss">CAPod FOSS</string>
<string name="general_grant_permission_action">Conceder permiso</string>
<string name="permission_bluetooth_connect_label">Conexión Bluetooth</string>
<string name="permission_bluetooth_connect_description">Esta aplicacion requiere el permiso \"Conexión Bluetooth\" para interactuar con los dispositivos vinculados e iniciar las conexiones.</string>
@@ -33,14 +33,14 @@
<string name="settings_monitor_mode_always_label">Sempre</string>
<string name="settings_reaction_autoconnect_whenseen_label">Quando rilevato</string>
<string name="settings_reaction_autoconnect_caseopen_label">La custodia é aperta</string>
<string name="settings_reaction_autoconnect_inear_label">Nell\'orecchio</string>
<string name="pods_dual_left_label">Pod sinistro</string>
<string name="pods_dual_right_label">Pod destro</string>
<string name="settings_reaction_autoconnect_inear_label">Indossato</string>
<string name="pods_dual_left_label">Pod SX</string>
<string name="pods_dual_right_label">Pod DX</string>
<string name="pods_case_label">Custodia</string>
<string name="pods_case_status_open_label">Aperto</string>
<string name="pods_case_status_closed_label">Chiuso</string>
<string name="pods_connection_state_disconnected_label">Non connesso</string>
<string name="pods_connection_state_idle_label">Connesso ad un device, ma inattivo</string>
<string name="pods_connection_state_idle_label">Connesso al dispositivo, ma inattivo</string>
<string name="pods_connection_state_music_label">In modalità musica</string>
<string name="pods_connection_state_call_label">In modalità chiamata</string>
<string name="pods_connection_state_ringing_label">Squilla</string>
@@ -51,7 +51,7 @@
<string name="pods_unknown_contact_dev">Questo è un dispositivo sconosciuto, ma sta utilizzando un formato di comunicazione noto. Aggiungiamo il supporto per questo dispositivo, contattami :)</string>
<string name="pods_none_label_short">Nessun dispositivo</string>
<string name="pods_charging_label">In ricarica</string>
<string name="pods_inear_label">Nell\'orecchio</string>
<string name="pods_inear_label">Indossato</string>
<string name="pods_microphone_label">Microfono</string>
<string name="pods_yours">Tuoi</string>
<string name="headset_being_worn_label">Indossato</string>
@@ -40,4 +40,33 @@ class BeatsFitProTest : BaseAirPodsTest() {
model shouldBe PodDevice.Model.BEATS_FIT_PRO
}
}
@Test
fun `extra rl test case`() = runTest {
create<BeatsFitPro>("07 19 01 12 20 04 FA 92 54 11 24 CE B1 DF 9D 8D F5 E3 37 60 B1 23 8B 90 3B 63 3F") {
rawPrefix shouldBe 0x01.toUByte()
rawDeviceModel shouldBe 0x1220.toUShort()
rawStatus shouldBe 0x04.toUByte()
rawPodsBattery shouldBe 0xFA.toUByte()
rawFlags shouldBe 0x9.toUShort()
rawCaseBattery shouldBe 0x2.toUShort()
rawCaseLidState shouldBe 0x54.toUByte()
rawDeviceColor shouldBe 0x11.toUByte()
rawSuffix shouldBe 0x24.toUByte()
isLeftPodMicrophone shouldBe false
isRightPodMicrophone shouldBe true
batteryLeftPodPercent shouldBe null
batteryRightPodPercent shouldBe 1.0f
isCaseCharging shouldBe false
isRightPodCharging shouldBe true
isLeftPodCharging shouldBe false
batteryCasePercent shouldBe 0.2f
podStyle.identifier shouldBe HasAppleColor.DeviceColor.UNKNOWN.name
model shouldBe PodDevice.Model.BEATS_FIT_PRO
}
}
}
@@ -0,0 +1,75 @@
package eu.darken.capod.pods.core.apple.beats
import eu.darken.capod.pods.core.PodDevice
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
import eu.darken.capod.pods.core.apple.airpods.HasStateDetectionAirPods
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
class PowerBeats4Test : BaseAirPodsTest() {
@Test
fun `playing music`() = runTest {
create<PowerBeats4>("07 19 01 0D 20 00 02 80 01 00 05 07 C5 E1 9C BD 9A 05 0E AE 9E 56 53 2F F9 75 4A") {
rawPrefix shouldBe 0x01.toUByte()
rawDeviceModel shouldBe 0x0D20.toUShort()
rawStatus shouldBe 0x0.toUByte()
rawPodsBattery shouldBe 0x02.toUByte()
rawFlags shouldBe 0x8.toUShort()
rawCaseBattery shouldBe 0x0.toUShort()
rawCaseLidState shouldBe 0x01.toUByte()
rawDeviceColor shouldBe 0x00.toUByte()
rawSuffix shouldBe 0x05.toUByte()
batteryHeadsetPercent shouldBe 0.2f
model shouldBe PodDevice.Model.POWERBEATS_4
state shouldBe HasStateDetectionAirPods.ConnectionState.MUSIC
}
}
@Test
fun `extra test case`() = runTest {
create<PowerBeats4>("07 19 01 0D 20 00 02 80 02 00 04 80 90 60 77 32 C2 0C 75 7A 3D 7E D7 1C 0E B8 43") {
rawPrefix shouldBe 0x01.toUByte()
rawDeviceModel shouldBe 0x0D20.toUShort()
rawStatus shouldBe 0x0.toUByte()
rawPodsBattery shouldBe 0x02.toUByte()
rawFlags shouldBe 0x8.toUShort()
rawCaseBattery shouldBe 0x0.toUShort()
rawCaseLidState shouldBe 0x02.toUByte()
rawDeviceColor shouldBe 0x00.toUByte()
rawSuffix shouldBe 0x04.toUByte()
batteryHeadsetPercent shouldBe 0.2f
model shouldBe PodDevice.Model.POWERBEATS_4
state shouldBe HasStateDetectionAirPods.ConnectionState.IDLE
}
}
@Test
fun `disconnected state`() = runTest {
create<PowerBeats4>("07 19 01 0D 20 00 02 80 01 00 00 25 DF 66 40 AF 44 7B 77 95 8F D1 92 50 26 11 74") {
rawPrefix shouldBe 0x01.toUByte()
rawDeviceModel shouldBe 0x0D20.toUShort()
rawStatus shouldBe 0x0.toUByte()
rawPodsBattery shouldBe 0x02.toUByte()
rawFlags shouldBe 0x8.toUShort()
rawCaseBattery shouldBe 0x0.toUShort()
rawCaseLidState shouldBe 0x01.toUByte()
rawDeviceColor shouldBe 0x00.toUByte()
rawSuffix shouldBe 0x00.toUByte()
batteryHeadsetPercent shouldBe 0.2f
model shouldBe PodDevice.Model.POWERBEATS_4
state shouldBe HasStateDetectionAirPods.ConnectionState.DISCONNECTED
}
}
}
@@ -69,11 +69,9 @@
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
app:layout_constraintEnd_toStartOf="@id/pod_case_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier_top"
app:layout_constraintVertical_bias="0.2">
app:layout_constraintTop_toTopOf="@+id/pod_right_container">
<ImageView
android:id="@+id/pod_left_icon"
@@ -199,8 +197,7 @@
android:layout_marginEnd="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/pod_case_container"
app:layout_constraintTop_toBottomOf="@id/barrier_top"
app:layout_constraintVertical_bias="0.2">
app:layout_constraintTop_toBottomOf="@id/barrier_top">
<ImageView
android:id="@+id/pod_right_icon"
+3 -3
View File
@@ -70,10 +70,10 @@
<string name="settings_licenses_label">Lizenzen</string>
<string name="settings_category_other_label">Andere</string>
<string name="settings_general_label">Einstellungen</string>
<string name="settings_general_description">Allgemeine Optimierungen, die die gesamte App betreffen.</string>
<string name="settings_general_description">Allgemeine Optimierungen, welche die gesamte App betreffen.</string>
<string name="settings_acknowledgements_label">Danksagungen</string>
<string name="settings_debug_autoreports_label">Automatische Fehlerberichte</string>
<string name="settings_debug_autoreports_description">Meldet Probleme automatisch, z.B. Details zu einem App-Absturz, damit ich herausfinden kann, wie ich ihn beheben kann.</string>
<string name="settings_debug_autoreports_description">Meldet Probleme automatisch, z.B. Details zu einem App-Absturz, welche dem Entwickler bei der Behebung unterstützen.</string>
<string name="settings_debug_mode_label">Debug-Modus</string>
<string name="settings_debug_mode_description">Zeige zusätzliche Informationen an, um Probleme zu beheben.</string>
<string name="settings_blescanner_unfiltered_label">Ungefilterte BLE-Daten</string>
@@ -101,7 +101,7 @@
<string name="troubleshooter_ble_result_failure_phone_headphones">Ihr Telefon hat BLE-Daten empfangen, aber die Daten stammen von keinem unterstützten Gerät. Sind Ihre Kopfhörer eingeschaltet? Unterstützt CAPod Ihren Kopfhörer?</string>
<string name="troubleshooter_ble_result_failure_action">Versuchen Sie es erneut</string>
<string name="troubleshoot_action">Fehlerbehebung</string>
<string name="onboarding_body1">Diese App fügt Support für AirPod-Spezifische funkionen zu Android hinzu.</string>
<string name="onboarding_body1">Diese App fügt Support für AirPod-spezifische Funktionen zu Android hinzu.</string>
<string name="onboarding_body2">Nicht alle Android-Geräte unterstützen die zusätzlichen AirPod-Funktionen vollständig. Ihr Betriebssystem erfordert eine korrekt funktionierende Bluetooth-Low-Energy-Implementierung.</string>
<string name="onboarding_body3">CAPod hat keine Werbung und sammelt Ihre Daten nicht.</string>
<string name="onboarding_body4">Sie können auf CAPod Pro upgraden, um zusätzliche Funktionen zu erhalten und die Entwicklung zu unterstützen.</string>
+9 -10
View File
@@ -7,24 +7,24 @@
<string name="general_upgrade_action">Aggiorna</string>
<string name="general_check_action">Controlla</string>
<string name="general_close_action">Chiudi</string>
<string name="upgrade_capod_label">Aggiorna CAPod</string>
<string name="upgrade_capod_label">Passa a CAPod PRO</string>
<string name="upgrade_capod_description">Ottieni funzionalità aggiuntive e supporta lo sviluppatore.</string>
<string name="settings_monitor_mode_label">Modalità monitoraggio</string>
<string name="settings_monitor_mode_description">Sotto quali circostanze questa applicazione monitora i dati Bluetooth.</string>
<string name="settings_monitor_mode_label">Modalità di monitoraggio</string>
<string name="settings_monitor_mode_description">Circostanze in cui questa applicazione monitora i dati Bluetooth.</string>
<string name="settings_scanner_mode_label">Modalità di scansione</string>
<string name="settings_scanner_mode_description">Il Bluetooth a basso consumo energetico dovrebbe dare priorità alle performance o risparmiare batteria?</string>
<string name="settings_scanner_mode_description">La scansione dei dati BLE deve dare priorità alle performance o al risparmio di batteria?</string>
<string name="settings_autopause_label">Pausa automatica</string>
<string name="settings_autopause_description">Metti in pausa l\'audio quando viene rimossa la cuffia da un orecchio.</string>
<string name="settings_showall_label">Mostra tutti i dispositivi</string>
<string name="settings_showall_description">Mostra i dispositivi delle altre persone vicine a te.</string>
<string name="settings_autopplay_label">Riproduzione automatica</string>
<string name="settings_autoplay_description">Avvia riproduzione audio quando il dispositivo è indossato.</string>
<string name="settings_fake_data_label">Dati immaginari</string>
<string name="settings_fake_data_label">Dati fittizzi</string>
<string name="settings_fake_data_description">Mostra dati fittizi, ovvero simula dispositivi che in realtà non esistono.</string>
<string name="settings_debug_label">Impostazioni di debug</string>
<string name="settings_debug_description">Impostazioni aggiuntive che possono aiutare a risolvere i problemi con l\'applicazione.</string>
<string name="settings_signal_minimum_label">Qualità del segnale minima</string>
<string name="settings_signal_minimum_description">La minima qualità del segnale che il dispositivo necessità per poter essere considerato tuo.</string>
<string name="settings_debug_description">Impostazioni aggiuntive che possono aiutare a risolvere i problemi dell\'app.</string>
<string name="settings_signal_minimum_label">Qualità minima di segnale</string>
<string name="settings_signal_minimum_description">La qualità minima di segnale che il dispositivo necessita per essere considerato tuo.</string>
<string name="settings_autoconnect_label">Connessione automatica</string>
<string name="settings_autoconnect_description">Se Android non si connette automaticamente, possiamo chiedergli di farlo. Questo imposterà la modalità di monitoraggio su \'Sempre\'.</string>
<string name="settings_autoconnect_condition_label">Condizione per la connessione automatica</string>
@@ -83,8 +83,7 @@
<string name="help_translate_label">Traduzione</string>
<string name="help_translate_description">Aiuta a tradurre l\'applicazione nella tua lingua preferita.</string>
<string name="translators_thanks_title">Traduttori</string>
<string name="translators_thanks_description">darken
Filippo Lolli</string>
<string name="translators_thanks_description">Filippo Lolli (IG: @lolli_filippo)</string>
<string name="widget_description">Un widget che mostra l\'ultimo stato del dispositivo.</string>
<string name="settings_compat_indirectcallback_title">Consegna indiretta dei dati</string>
<string name="settings_compat_indirectcallback_summary">Utilizza un metodo alternativo per ricevere dati BLE dal sistema (broadcast invece di callback).</string>
+1 -1
View File
@@ -122,7 +122,7 @@
<string name="onboarding_body1">This app adds support for AirPod specific features to Android.</string>
<string name="onboarding_body2">Not all Android devices fully support the extra AirPod features. Your operating system requires a correctly working Bluetooth-Low-Energy implemtation.</string>
<string name="onboarding_body2">Not all Android devices fully support the extra AirPod features. Your operating system requires a correctly working Bluetooth-Low-Energy implementation.</string>
<string name="onboarding_body3">CAPod has no ads and does not collect your data.</string>
<string name="onboarding_body4">You can upgrade to CAPod Pro to gain extra features and support development.</string>
+1 -1
View File
@@ -20,4 +20,4 @@ allprojects {
tasks.register("clean").configure {
delete("build")
}
}
+1 -1
View File
@@ -11,4 +11,4 @@ dependencies {
implementation("com.android.tools.build:gradle:8.1.2")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
implementation("com.squareup:javapoet:1.13.0")
}
}
@@ -0,0 +1,2 @@
Bugfixes, performance improvements and maybe new features.
¯\_(ツ)_/¯
@@ -1,14 +1,14 @@
CAPod 是为 AirPods 提供配套功能的一个应用
CAPod 是一款为 AirPods 提供配套功能的应用
功能:
功能包括
* 耳机和充电仓的电量显示
* 耳机和充电仓的充电状态
* 有关连接、麦克风和充电仓的附加信息
* 能够接收和显示位于附近的全部设备
* 佩戴/取下时自动开始/暂停音乐播放。
* 自动连接手机与 AirPods
* 充电仓打开时显示弹窗
* 耳机和充电仓的电量显示
* 耳机和充电仓的充电状态
* 有关连接、麦克风和充电仓的附加信息
* 能够接收和显示所有附近的设备
* 佩戴/取下耳机时自动播放/暂停
* 自动连接手机与 AirPods
* 充电仓打开时显示弹窗
CAPod 是一款免费共享软件。 某些功能需在应用内购买。
+2 -2
View File
@@ -1,6 +1,6 @@
### Updated by release.sh ###
project.versioning.major=2
project.versioning.minor=12
project.versioning.patch=1
project.versioning.minor=13
project.versioning.patch=0
project.versioning.build=0
#############################