mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Compare commits
54
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02f68821d2 | ||
|
|
62886f00f1 | ||
|
|
f2eb45d00b | ||
|
|
2fca9097c2 | ||
|
|
051677e7dd | ||
|
|
fbcd595b45 | ||
|
|
aa38f58f62 | ||
|
|
a3b01a02ee | ||
|
|
8544983984 | ||
|
|
07a11799b1 | ||
|
|
65a7b1933a | ||
|
|
bbfb735124 | ||
|
|
7b474fb0e1 | ||
|
|
c6524d7cee | ||
|
|
148cdf5109 | ||
|
|
60a3039415 | ||
|
|
6f7b6e30c9 | ||
|
|
08c095eae4 | ||
|
|
9087be6282 | ||
|
|
d46fe35eab | ||
|
|
1afb77ee33 | ||
|
|
a9215fc11c | ||
|
|
d80a110280 | ||
|
|
fdfc7f44fb | ||
|
|
26fbfc08f7 | ||
|
|
89049ee3ab | ||
|
|
68f81f900b | ||
|
|
513bd891af | ||
|
|
37cd753ab8 | ||
|
|
34bf2311b4 | ||
|
|
a86093f617 | ||
|
|
71f66e6004 | ||
|
|
2d1ab85e01 | ||
|
|
f029eb9102 | ||
|
|
471837ab88 | ||
|
|
1e80d742cc | ||
|
|
16b6273938 | ||
|
|
3407370563 | ||
|
|
3cda73a36c | ||
|
|
b604c423ad | ||
|
|
0c8b121c2c | ||
|
|
da11961611 | ||
|
|
48b9952fc0 | ||
|
|
99fa99eba5 | ||
|
|
06e67e04ac | ||
|
|
4a2f7c20a2 | ||
|
|
82e8769407 | ||
|
|
ad38702df1 | ||
|
|
3f98c62a8f | ||
|
|
ec7447992f | ||
|
|
99958e13eb | ||
|
|
b9fe5d4a14 | ||
|
|
1443fd5714 | ||
|
|
798083b235 |
@@ -4,7 +4,8 @@
|
||||
[](https://github.com/d4rken-org/capod/releases/latest)
|
||||
[](https://github.com/d4rken/capod/actions/workflows/code-checks.yml)
|
||||
[](https://crowdin.com/project/capod)
|
||||
[](https://github.com/d4rken-org/capod/releases/latest)
|
||||
[](https://github.com/d4rken-org/capod/edit/main/README.md#download)
|
||||
[](https://github.com/d4rken-org/capod/edit/main/README.md#download)
|
||||
|
||||
A companion app that adds support for AirPod specific features to Android:
|
||||
|
||||
@@ -27,9 +28,11 @@ Currently supported models:
|
||||
* AirPods 3. Generation
|
||||
* AirPods Pro 1. Generation
|
||||
* AirPods Pro 2. Generation
|
||||
* AirPods Pro 2. Generation (USB-C)
|
||||
* AirPods Max
|
||||
* Power Beats Pro
|
||||
* Power Beats 3
|
||||
* Power Beats 4
|
||||
* Beats Solo 3
|
||||
* Beats Studio 3
|
||||
* Beats X
|
||||
@@ -75,6 +78,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
|
||||
|
||||
|
||||
+14
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
@@ -91,6 +91,10 @@ interface PodDevice {
|
||||
"AirPods Pro 2",
|
||||
R.drawable.devic_airpods_pro2_both
|
||||
),
|
||||
@Json(name = "airpods.pro2.usbc") AIRPODS_PRO2_USBC(
|
||||
"AirPods Pro 2 USB-C",
|
||||
R.drawable.devic_airpods_pro2_both
|
||||
),
|
||||
@Json(name = "airpods.max") AIRPODS_MAX(
|
||||
"AirPods Max",
|
||||
R.drawable.devic_headphones_generic
|
||||
@@ -110,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"
|
||||
),
|
||||
|
||||
@@ -19,6 +19,7 @@ abstract class AppleFactoryModule {
|
||||
|
||||
@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 beatsFlex(factory: BeatsFlex.Factory): ApplePodsFactory<out ApplePods>
|
||||
@@ -26,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,89 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import eu.darken.capod.common.R
|
||||
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.DualApplePods.LidState
|
||||
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 AirPodsPro2Usbc(
|
||||
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: LidState? = null
|
||||
) : DualApplePods, HasStateDetectionAirPods {
|
||||
|
||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_PRO2_USBC
|
||||
|
||||
@get:DrawableRes
|
||||
override val iconRes: Int
|
||||
get() = R.drawable.devic_airpods_pro2_both
|
||||
|
||||
@get:DrawableRes
|
||||
override val caseIcon: Int
|
||||
get() = R.drawable.devic_airpods_pro2_case
|
||||
|
||||
@get:DrawableRes
|
||||
override val leftPodIcon: Int
|
||||
get() = R.drawable.devic_airpods_pro2_left
|
||||
|
||||
@get:DrawableRes
|
||||
override val rightPodIcon: Int
|
||||
get() = R.drawable.devic_airpods_pro2_right
|
||||
|
||||
override val batteryCasePercent: Float?
|
||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||
|
||||
override val caseLidState: LidState
|
||||
get() = cachedCaseState ?: super.caseLidState
|
||||
|
||||
override val rssi: Int
|
||||
get() = rssiAverage ?: super<HasStateDetectionAirPods>.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 = AirPodsPro2Usbc(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 = 0x2420.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Pro2", "USBC")
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
@@ -58,4 +58,6 @@
|
||||
<string name="pods_case_unknown_state">حالة غير معروفة</string>
|
||||
<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>
|
||||
|
||||
@@ -58,4 +58,6 @@
|
||||
<string name="pods_case_unknown_state">Невядомы стан</string>
|
||||
<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">"Дазволіць CAPod адлюстроўваць апавяшчэнні аб вашых AirPods: напрыклад, іх бягучы стан пры падключэнні."</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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>
|
||||
|
||||
@@ -58,4 +58,6 @@
|
||||
<string name="pods_case_unknown_state">Status tidak diketahui</string>
|
||||
<string name="last_seen_x">Terakhir terlihat: %s</string>
|
||||
<string name="first_seen_x">Pertama kali terlihat: %s</string>
|
||||
<string name="permission_post_notifications_label">Tampilkan notifikasi</string>
|
||||
<string name="permission_post_notifications_description">"Izinkan CAPod untuk menampilkan notifikasi tentang AirPods anda, contoh. status saat terhubung."</string>
|
||||
</resources>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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_value_not_available_label">T/A</string>
|
||||
<string name="general_error_label">Ralat</string>
|
||||
<string name="general_grant_permission_action">Berikan kebenaran</string>
|
||||
|
||||
@@ -58,4 +58,6 @@
|
||||
<string name="pods_case_unknown_state">Estado desconhecido</string>
|
||||
<string name="last_seen_x">Visto pela última vez: %s</string>
|
||||
<string name="first_seen_x">Visto pela primeira vez: %s</string>
|
||||
<string name="permission_post_notifications_label">Mostrar notificações</string>
|
||||
<string name="permission_post_notifications_description">"Permita que o CAPod mostre notificações sobre seus AirPods, por exemplo. seu status atual enquanto conectado."</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,2 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"></resources>
|
||||
<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_value_not_available_label">N/A</string>
|
||||
<string name="general_error_label">Eroare</string>
|
||||
<string name="general_grant_permission_action">Acordați permisiuni</string>
|
||||
<string name="overview_nomaindevice_label">Niciun dispozitiv principal</string>
|
||||
<string name="overview_nomaindevice_description">Este puțin probabil ca toate dispozitivele detectate să fie ale tale. Porniți și conectați dispozitivul sau ajustați setările.</string>
|
||||
<string name="overview_bluetooth_disabled_label">Bluetooth este dezactivat</string>
|
||||
<string name="overview_bluetooth_disabled_description">Bluetooth este dezactivat, activați-l ;)</string>
|
||||
<string name="permission_bluetooth_connect_label">Conectare Bluetooth</string>
|
||||
<string name="permission_bluetooth_connect_description">Această aplicație necesită permisiunea „Conectare Bluetooth” pentru a interacționa cu dispozitivele asociate și a iniția conexiuni.</string>
|
||||
<string name="permission_bluetooth_scan_label">Scanare Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Permisiunea „Scanare Bluetooth” permite acestei aplicații să descopere și să primească date Bluetooth de la dispozitivele din apropiere, cum ar fi AirPod-urile dvs.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Această aplicație necesită permisiunea „Bluetooth” pentru a se conecta la dispozitive Bluetooth asociate.</string>
|
||||
<string name="permission_access_fine_location_label">Permiteți locație exactă</string>
|
||||
<string name="permission_access_fine_location_description">CAPod folosește permisiunea „locație exactă” pentru a primi date Bluetooth Energie Scăzută (BLE). Căștile dvs. folosesc tehnologia Bluetooth Energie Scăzută (BLE) pentru a-și transmite starea. Această aplicație NU va folosi date Bluetooth pentru a vă determina locația.</string>
|
||||
<string name="permission_background_location_label">Permiteți acces la locație în fundal</string>
|
||||
<string name="permission_background_location_description">CAPod folosește „accesul la locație în fundal” pentru a activa funcții precum „Afișare pop-up” și „Conectare Automată” în timp ce aplicația este închisă. Accesul la locație în fundal permite aplicației să primească date Bluetooth Energie Scăzută (BLE) în timp ce se află în fundal. Această aplicație NU va folosi date Bluetooth pentru a vă determina locația.</string>
|
||||
<string name="permission_ignore_battery_optimizations_label">Dezactivați optimizări ale bateriei</string>
|
||||
<string name="permission_ignore_battery_optimizations_description">Optimizările bateriei împiedică această aplicație să primească în mod fiabil date Bluetooth în timp ce aplicația este în fundal.</string>
|
||||
<string name="permission_required_title">Este necesară următoarea permisiune:</string>
|
||||
<string name="permission_system_alert_window_label">Fereastra de alertă de sistem</string>
|
||||
<string name="permission_system_alert_window_description">Permiteți CAPod să apară peste alte aplicații pentru a face posibilă funcția „Afișați pop-up”.</string>
|
||||
<string name="settings_scanner_mode_lowpower_label">Putere redusă</string>
|
||||
<string name="settings_scanner_mode_balanced_label">Echilibrat</string>
|
||||
<string name="settings_scanner_mode_lowlatency_label">Latență scăzută</string>
|
||||
<string name="settings_monitor_mode_manual_label">Când aplicația este deschisă</string>
|
||||
<string name="settings_monitor_mode_automatic_label">Când dispozitivul este conectat</string>
|
||||
<string name="settings_monitor_mode_always_label">Mereu</string>
|
||||
<string name="settings_reaction_autoconnect_whenseen_label">Când este detectat</string>
|
||||
<string name="settings_reaction_autoconnect_caseopen_label">Carcasa este deschisă</string>
|
||||
<string name="settings_reaction_autoconnect_inear_label">În ureche</string>
|
||||
<string name="pods_dual_left_label">Casca stângă</string>
|
||||
<string name="pods_dual_right_label">Casca dreaptă</string>
|
||||
<string name="pods_case_label">Carcasă</string>
|
||||
<string name="pods_case_status_open_label">Deschisă</string>
|
||||
<string name="pods_case_status_closed_label">Închisă</string>
|
||||
<string name="pods_connection_state_disconnected_label">Nu sunt conectate la un dispozitiv</string>
|
||||
<string name="pods_connection_state_idle_label">Conectate la un dispozitiv, dar inactiv</string>
|
||||
<string name="pods_connection_state_music_label">În modul muzică</string>
|
||||
<string name="pods_connection_state_call_label">În modul apel</string>
|
||||
<string name="pods_connection_state_ringing_label">Sună</string>
|
||||
<string name="pods_connection_state_hanging_up_label">Închidere</string>
|
||||
<string name="pods_connection_state_unknown_label">Starea conexiunii necunoscută</string>
|
||||
<string name="pods_unknown_raw_data_label">Date neprelucrate</string>
|
||||
<string name="pods_unknown_label">Dispozitiv necunoscut</string>
|
||||
<string name="pods_unknown_contact_dev">Acesta este un dispozitiv necunoscut, dar folosește un format de mesaj similar. Să adăugăm suport pentru el, contactează-mă :)</string>
|
||||
<string name="pods_none_label_short">Niciun dispozitiv</string>
|
||||
<string name="pods_charging_label">Se încarcă</string>
|
||||
<string name="pods_inear_label">În ureche</string>
|
||||
<string name="pods_microphone_label">Microfon</string>
|
||||
<string name="pods_yours">Ale tale</string>
|
||||
<string name="headset_being_worn_label">Fiind purtate</string>
|
||||
<string name="pods_case_unknown_state">Stare necunoscută</string>
|
||||
<string name="last_seen_x">Vazute ultima dată: %s</string>
|
||||
<string name="first_seen_x">Prima dată văzute: %s</string>
|
||||
<string name="permission_post_notifications_label">Arată notificări</string>
|
||||
<string name="permission_post_notifications_description">"Permiteți ca CAPod să afișeze notificări despre AirPod-urile dvs., de exemplu, starea lor actuală în timp ce sunt conectate."</string>
|
||||
</resources>
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
<string name="pods_microphone_label">Microphone</string>
|
||||
<string name="pods_yours">Yours</string>
|
||||
<string name="headset_being_worn_label">Being worn</string>
|
||||
<string name="headset_not_being_worn_label">Not being worn</string>
|
||||
<string name="pods_case_unknown_state">Unknown state</string>
|
||||
|
||||
<string name="last_seen_x">Last seen: %s</string>
|
||||
|
||||
@@ -3,80 +3,69 @@ package eu.darken.capod.common.flow
|
||||
import eu.darken.capod.common.collections.mutate
|
||||
import io.kotest.assertions.throwables.shouldThrow
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.types.instanceOf
|
||||
import io.kotest.matchers.types.shouldBeInstanceOf
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.test.*
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import org.junit.jupiter.api.Test
|
||||
import testhelpers.BaseTest
|
||||
import testhelpers.coroutine.runTest2
|
||||
import testhelpers.flow.test
|
||||
import java.io.IOException
|
||||
import java.lang.Thread.sleep
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
class DynamicStateFlowTest : BaseTest() {
|
||||
|
||||
// Without an init value, there isn't a way to keep using the flow
|
||||
@Test
|
||||
fun `exceptions on initialization are rethrown`() {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow<String>(
|
||||
fun `exceptions on initialization are rethrown`() = runTest2(expectedError = IOException::class) {
|
||||
val testScope = this
|
||||
|
||||
val hotData = DynamicStateFlow<String>(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
coroutineContext = Dispatchers.Unconfined,
|
||||
startValueProvider = { throw IOException() }
|
||||
)
|
||||
runBlocking {
|
||||
withTimeoutOrNull(500) {
|
||||
// This blocking scope gets the init exception as the first caller
|
||||
hotData.flow.firstOrNull()
|
||||
} shouldBe null
|
||||
}
|
||||
|
||||
testScope.advanceUntilIdle()
|
||||
|
||||
testScope.uncaughtExceptions.single() shouldBe instanceOf(IOException::class)
|
||||
// This blocking scope gets the init exception as the first caller
|
||||
hotData.flow.firstOrNull()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `subscription doesn't end when no subscriber is collecting, mode Lazily`() {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
fun `subscription doesn't end when no subscriber is collecting, mode Lazily`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val valueProvider = mockk<suspend CoroutineScope.() -> String>()
|
||||
coEvery { valueProvider.invoke(any()) } returns "Test"
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
coroutineContext = Dispatchers.Unconfined,
|
||||
startValueProvider = valueProvider,
|
||||
)
|
||||
|
||||
testScope.apply {
|
||||
runTest2(autoCancel = true) {
|
||||
hotData.flow.first() shouldBe "Test"
|
||||
hotData.flow.first() shouldBe "Test"
|
||||
}
|
||||
coVerify(exactly = 1) { valueProvider.invoke(any()) }
|
||||
}
|
||||
hotData.flow.first() shouldBe "Test"
|
||||
hotData.flow.first() shouldBe "Test"
|
||||
|
||||
coVerify(exactly = 1) { valueProvider.invoke(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `value updates`() {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
fun `value updates`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val valueProvider = mockk<suspend CoroutineScope.() -> Long>()
|
||||
coEvery { valueProvider.invoke(any()) } returns 1
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
startValueProvider = valueProvider,
|
||||
@@ -88,7 +77,6 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
(1..16).forEach { _ ->
|
||||
thread {
|
||||
(1..200).forEach { _ ->
|
||||
sleep(10)
|
||||
hotData.updateAsync(
|
||||
onUpdate = { this + 1L },
|
||||
onError = { throw it }
|
||||
@@ -97,12 +85,16 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
}
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
testCollector.await { list, _ -> list.size == 3201 }
|
||||
testCollector.latestValues shouldBe (1..3201).toList()
|
||||
}
|
||||
advanceUntilIdle()
|
||||
|
||||
testCollector.await { list, _ -> list.size == 3201 }
|
||||
testCollector.latestValues shouldBe (1..3201).toList()
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 1) { valueProvider.invoke(any()) }
|
||||
|
||||
testCollector.cancelAndJoin()
|
||||
}
|
||||
|
||||
data class TestData(
|
||||
@@ -110,14 +102,13 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `check multi threading value updates with more complex data`() {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
val valueProvider =
|
||||
mockk<suspend CoroutineScope.() -> Map<String, eu.darken.capod.common.flow.DynamicStateFlowTest.TestData>>()
|
||||
coEvery { valueProvider.invoke(any()) } returns mapOf("data" to eu.darken.capod.common.flow.DynamicStateFlowTest.TestData())
|
||||
fun `check multi threading value updates with more complex data`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val valueProvider = mockk<suspend CoroutineScope.() -> Map<String, TestData>>()
|
||||
coEvery { valueProvider.invoke(any()) } returns mapOf("data" to TestData())
|
||||
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
startValueProvider = valueProvider,
|
||||
@@ -140,20 +131,23 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
}
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
testCollector.await { list, _ -> list.size == 4001 }
|
||||
testCollector.latestValues.map { it.values.single().number } shouldBe (1L..4001L).toList()
|
||||
}
|
||||
advanceUntilIdle()
|
||||
|
||||
testCollector.await { list, _ -> list.size == 4001 }
|
||||
testCollector.latestValues.map { it.values.single().number } shouldBe (1L..4001L).toList()
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 1) { valueProvider.invoke(any()) }
|
||||
|
||||
testCollector.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `only emit new values if they actually changed updates`() {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
fun `only emit new values if they actually changed updates`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
startValueProvider = { "1" },
|
||||
@@ -167,26 +161,28 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
hotData.updateAsync { "2" }
|
||||
hotData.updateAsync { "1" }
|
||||
|
||||
runBlocking {
|
||||
testCollector.await { list, _ -> list.size == 3 }
|
||||
testCollector.latestValues shouldBe listOf("1", "2", "1")
|
||||
}
|
||||
advanceUntilIdle()
|
||||
|
||||
testCollector.await { list, _ -> list.size == 3 }
|
||||
testCollector.latestValues shouldBe listOf("1", "2", "1")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `multiple subscribers share the flow`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val valueProvider = mockk<suspend CoroutineScope.() -> String>()
|
||||
coEvery { valueProvider.invoke(any()) } returns "Test"
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = this,
|
||||
parentScope = testScope,
|
||||
startValueProvider = valueProvider,
|
||||
)
|
||||
|
||||
val sub1 = hotData.flow.test(tag = "sub1", scope = this)
|
||||
val sub2 = hotData.flow.test(tag = "sub2", scope = this)
|
||||
val sub3 = hotData.flow.test(tag = "sub3", scope = this)
|
||||
val sub1 = hotData.flow.test(tag = "sub1", scope = testScope)
|
||||
val sub2 = hotData.flow.test(tag = "sub2", scope = testScope)
|
||||
val sub3 = hotData.flow.test(tag = "sub3", scope = testScope)
|
||||
|
||||
hotData.updateAsync { "A" }
|
||||
hotData.updateAsync { "B" }
|
||||
@@ -207,17 +203,19 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
|
||||
@Test
|
||||
fun `value is persisted between unsubscribes`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val valueProvider = mockk<suspend CoroutineScope.() -> Long>()
|
||||
coEvery { valueProvider.invoke(any()) } returns 1
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = this,
|
||||
parentScope = testScope,
|
||||
coroutineContext = this.coroutineContext,
|
||||
startValueProvider = valueProvider,
|
||||
)
|
||||
|
||||
val testCollector1 = hotData.flow.test(tag = "collector1", scope = this)
|
||||
val testCollector1 = hotData.flow.test(tag = "collector1", scope = testScope)
|
||||
testCollector1.silent = false
|
||||
|
||||
(1..10).forEach { _ ->
|
||||
@@ -233,7 +231,7 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
|
||||
testCollector1.cancelAndJoin()
|
||||
|
||||
val testCollector2 = hotData.flow.test(tag = "collector2", scope = this)
|
||||
val testCollector2 = hotData.flow.test(tag = "collector2", scope = testScope)
|
||||
testCollector2.silent = false
|
||||
|
||||
advanceUntilIdle()
|
||||
@@ -246,10 +244,10 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blocking update is actually blocking`() = runBlocking {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
fun `blocking update is actually blocking`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
coroutineContext = testScope.coroutineContext,
|
||||
@@ -270,6 +268,8 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
|
||||
hotData.updateBlocking { this - 3 } shouldBe 0
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
testCollector.await { _, i -> i == 3 }
|
||||
testCollector.latestValues shouldBe listOf(2, 3, 0)
|
||||
|
||||
@@ -277,10 +277,10 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blocking update rethrows error`() = runBlocking {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
fun `blocking update rethrows error`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
coroutineContext = testScope.coroutineContext,
|
||||
@@ -300,16 +300,17 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
hotData.flow.first() shouldBe 2
|
||||
|
||||
hotData.updateBlocking { 3 } shouldBe 3
|
||||
hotData.flow.first() shouldBe 3
|
||||
|
||||
testScope.uncaughtExceptions.singleOrNull() shouldBe null
|
||||
advanceUntilIdle()
|
||||
|
||||
hotData.flow.first() shouldBe 3
|
||||
|
||||
testCollector.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `async updates error handler`() = runTest2(expectedError = IOException::class) {
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = this,
|
||||
startValueProvider = { 1 },
|
||||
@@ -321,14 +322,15 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
hotData.updateAsync { throw IOException("Surprise") }
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
testCollector.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `async updates rethrow errors on HotDataFlow scope if no error handler is set`() = runBlocking {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
fun `async updates rethrow errors on HotDataFlow scope if no error handler is set`() = runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
startValueProvider = { 1 },
|
||||
@@ -346,31 +348,29 @@ class DynamicStateFlowTest : BaseTest() {
|
||||
|
||||
testScope.advanceUntilIdle()
|
||||
thrownError!!.shouldBeInstanceOf<IOException>()
|
||||
testScope.uncaughtExceptions.singleOrNull() shouldBe null
|
||||
|
||||
testCollector.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clean up function is called when parent scope is cancelled`() = runTest {
|
||||
val testScope =
|
||||
createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + EmptyCoroutineContext)
|
||||
|
||||
fun `clean up function is called when parent scope is cancelled`() {
|
||||
var onReleaseValue: String? = null
|
||||
|
||||
val hotData = eu.darken.capod.common.flow.DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
coroutineContext = Dispatchers.Unconfined,
|
||||
startValueProvider = { "Test" },
|
||||
onRelease = {
|
||||
onReleaseValue = it
|
||||
}
|
||||
)
|
||||
runTest2(autoCancel = true) {
|
||||
val testScope = this
|
||||
|
||||
hotData.flow.first() shouldBe "Test"
|
||||
val hotData = DynamicStateFlow(
|
||||
loggingTag = "tag",
|
||||
parentScope = testScope,
|
||||
coroutineContext = Dispatchers.Unconfined,
|
||||
startValueProvider = { "Test" },
|
||||
onRelease = {
|
||||
onReleaseValue = it
|
||||
}
|
||||
)
|
||||
|
||||
testScope.cancel()
|
||||
hotData.flow.first() shouldBe "Test"
|
||||
}
|
||||
|
||||
onReleaseValue shouldBe "Test"
|
||||
}
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.HasAppleColor
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AirPodsPro2UsbcTest : BaseAirPodsTest() {
|
||||
|
||||
/**
|
||||
* https://github.com/d4rken-org/capod/issues/164
|
||||
*/
|
||||
@Test
|
||||
fun `AirPods Pro 2 with USB-C - via #164`() = runTest {
|
||||
create<AirPodsPro2Usbc>("07 19 01 24 20 0B 99 8F 11 00 04 BD A7 3B FF 2D 8A 3C AF 9B 1A 7C 74 B7 A9 D1 C3") {
|
||||
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x2420.toUShort()
|
||||
rawStatus shouldBe 0x0B.toUByte()
|
||||
rawPodsBattery shouldBe 0x99.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x11.toUByte()
|
||||
rawDeviceColor shouldBe 0x0.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
isLeftPodMicrophone shouldBe false
|
||||
isRightPodMicrophone shouldBe true
|
||||
|
||||
isLeftPodInEar shouldBe true
|
||||
isRightPodInEar shouldBe true
|
||||
|
||||
batteryLeftPodPercent shouldBe 0.9f
|
||||
batteryRightPodPercent shouldBe 0.9f
|
||||
|
||||
isCaseCharging shouldBe false
|
||||
isRightPodCharging shouldBe false
|
||||
isLeftPodCharging shouldBe false
|
||||
batteryCasePercent shouldBe null
|
||||
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name
|
||||
|
||||
model shouldBe PodDevice.Model.AIRPODS_PRO2_USBC
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `AirPods Pro 2 with USB-C - via #164 - in case`() = runTest {
|
||||
create<AirPodsPro2Usbc>("07 19 01 24 20 53 AA 98 32 00 05 49 0A B8 BF 8E 29 D8 70 12 0D A7 0C CE 77 56 00") {
|
||||
|
||||
isLeftPodMicrophone shouldBe true
|
||||
isRightPodMicrophone shouldBe false
|
||||
|
||||
isLeftPodInEar shouldBe true
|
||||
isRightPodInEar shouldBe false
|
||||
|
||||
batteryLeftPodPercent shouldBe 1f
|
||||
batteryRightPodPercent shouldBe 1f
|
||||
|
||||
isCaseCharging shouldBe false
|
||||
isRightPodCharging shouldBe true
|
||||
isLeftPodCharging shouldBe false
|
||||
batteryCasePercent shouldBe 0.8f
|
||||
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name
|
||||
|
||||
model shouldBe PodDevice.Model.AIRPODS_PRO2_USBC
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package testhelpers.coroutine
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.*
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class CoroutinesTestExtension(
|
||||
private val dispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
|
||||
) : BeforeEachCallback, AfterEachCallback,
|
||||
TestCoroutineScope by createTestCoroutineScope(TestCoroutineDispatcher() + TestCoroutineExceptionHandler() + dispatcher) {
|
||||
|
||||
override fun beforeEach(context: ExtensionContext?) {
|
||||
Dispatchers.setMain(dispatcher)
|
||||
}
|
||||
|
||||
override fun afterEach(context: ExtensionContext?) {
|
||||
cleanupTestCoroutines()
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
package="eu.darken.capod">
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<uses-feature android:name="android.hardware.type.watch" />
|
||||
|
||||
<application
|
||||
@@ -41,4 +42,4 @@
|
||||
tools:node="remove" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/request_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
@@ -44,11 +44,12 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/grant_action"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:text="@string/general_grant_permission_action"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/permission_description" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -38,6 +38,11 @@ android {
|
||||
create("foss") {
|
||||
dimension = "version"
|
||||
signingConfig = signingConfigs["releaseFoss"]
|
||||
// The info block is encrypted and can only be read by google
|
||||
dependenciesInfo {
|
||||
includeInApk = false
|
||||
includeInBundle = false
|
||||
}
|
||||
}
|
||||
create("gplay") {
|
||||
dimension = "version"
|
||||
@@ -125,7 +130,7 @@ android {
|
||||
dependencies {
|
||||
implementation(project(":app-common"))
|
||||
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
|
||||
|
||||
addBaseKotlin()
|
||||
|
||||
@@ -145,6 +150,6 @@ dependencies {
|
||||
|
||||
addTesting()
|
||||
|
||||
"gplayImplementation"("com.android.billingclient:billing:5.1.0")
|
||||
"gplayImplementation"("com.android.billingclient:billing-ktx:5.1.0")
|
||||
"gplayImplementation"("com.android.billingclient:billing:6.0.1")
|
||||
"gplayImplementation"("com.android.billingclient:billing-ktx:6.0.1")
|
||||
}
|
||||
@@ -1,2 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="foss_upgrade_donate_label">Donează</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">Am donat deja</string>
|
||||
<string name="foss_upgrade_no_money_label">Mi-am cheltuit toți banii pe AirPods</string>
|
||||
</resources>
|
||||
|
||||
+16
-6
@@ -1,7 +1,13 @@
|
||||
package eu.darken.capod.common.upgrade.core.client
|
||||
|
||||
import android.app.Activity
|
||||
import com.android.billingclient.api.*
|
||||
import com.android.billingclient.api.AcknowledgePurchaseParams
|
||||
import com.android.billingclient.api.BillingClient
|
||||
import com.android.billingclient.api.BillingFlowParams
|
||||
import com.android.billingclient.api.BillingResult
|
||||
import com.android.billingclient.api.ProductDetails
|
||||
import com.android.billingclient.api.Purchase
|
||||
import com.android.billingclient.api.QueryProductDetailsParams
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.INFO
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
@@ -20,11 +26,15 @@ data class BillingClientConnection(
|
||||
) {
|
||||
private val purchasesLocal = MutableStateFlow<Collection<Purchase>>(emptySet())
|
||||
val purchases: Flow<Collection<Purchase>> = combine(purchasesGlobal, purchasesLocal) { global, local ->
|
||||
val combined = mutableMapOf<String, Purchase>()
|
||||
global.plus(local).toSet().sortedByDescending { it.purchaseTime }.forEach { purchase ->
|
||||
combined[purchase.orderId] = purchase
|
||||
}
|
||||
combined.values
|
||||
val combined = mutableSetOf<Purchase>()
|
||||
|
||||
combined.addAll(local)
|
||||
|
||||
global
|
||||
.let { purchases -> purchases.filter { it.purchaseState == Purchase.PurchaseState.PURCHASED } }
|
||||
.let { combined.addAll(it) }
|
||||
|
||||
combined.sortedByDescending { it.purchaseTime }
|
||||
}
|
||||
.setupCommonEventHandlers(TAG) { "purchases" }
|
||||
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="upgrades_gplay_unavailable_error">Serviciile Google Play nu sunt disponibile.</string>
|
||||
<string name="upgrades_no_purchases_found_check_account">Nu s-au găsit achiziții. Folosești contul corect?</string>
|
||||
</resources>
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.bluetooth_le"
|
||||
android:required="true" />
|
||||
@@ -24,9 +27,9 @@
|
||||
<activity
|
||||
android:name=".main.ui.MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppThemeSplash"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/AppThemeSplash">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -74,7 +77,13 @@
|
||||
android:name=".common.debug.recording.ui.RecorderActivity"
|
||||
android:theme="@style/AppThemeFloating" />
|
||||
|
||||
<service android:name=".common.debug.recording.core.RecorderService" />
|
||||
<service
|
||||
android:name=".common.debug.recording.core.RecorderService"
|
||||
android:foregroundServiceType="specialUse">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="Users can record a debug log to help developers with bugs. The debug log recording is controlled via notifications and hosted in a foreground service." />
|
||||
</service>
|
||||
|
||||
<!-- Worker stuff-->
|
||||
<service
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract class PreferenceFragment2
|
||||
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import androidx.annotation.LayoutRes
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.coroutine.AppScope
|
||||
@@ -41,6 +42,7 @@ import kotlinx.coroutines.withTimeout
|
||||
import java.time.Duration
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WidgetProvider : AppWidgetProvider() {
|
||||
|
||||
@@ -95,6 +97,27 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of cells needed for given size of the widget.
|
||||
*
|
||||
* The value is determined in accordance with official guidelines
|
||||
* for designing widgets, see:
|
||||
* https://developer.android.com/guide/practices/ui_guidelines/widget_design
|
||||
*
|
||||
* Thanks to Jakub S. on Stackoverflow for this solution:
|
||||
* https://stackoverflow.com/a/37522648/10866268
|
||||
*
|
||||
* @param size Widget size in dp.
|
||||
* @return Size in number of cells.
|
||||
*/
|
||||
private fun getCellsForSize(size: Int): Int {
|
||||
var n = 2
|
||||
while (70 * n - 30 < size) {
|
||||
++n
|
||||
}
|
||||
return n - 1
|
||||
}
|
||||
|
||||
private suspend fun updateWidget(
|
||||
context: Context,
|
||||
widgetManager: AppWidgetManager,
|
||||
@@ -107,7 +130,23 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
|
||||
val layout = when {
|
||||
!upgradeRepo.isPro() -> createUpgradeRequiredLayout(context)
|
||||
device is DualPodDevice -> createDualPodLayout(context, device)
|
||||
device is DualPodDevice -> {
|
||||
val minWidth = widgetManager.getAppWidgetOptions(widgetId)
|
||||
.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
|
||||
val columns = getCellsForSize(minWidth)
|
||||
|
||||
/* Enable wide widgets only when we are provided with 5 or
|
||||
* more columns of space.
|
||||
* Although the minimum size is only 2x1, the safeguards are
|
||||
* added if these restrictions will ever be loosened in the future.
|
||||
*/
|
||||
val layout = when (columns) {
|
||||
in 1 .. 4 -> R.layout.widget_pod_dual_compact_layout
|
||||
else -> R.layout.widget_pod_dual_wide_layout
|
||||
}
|
||||
|
||||
createDualPodLayout(context, device, layout)
|
||||
}
|
||||
device is SinglePodDevice -> createSinglePodLayout(context, device)
|
||||
device is PodDevice -> createUnknownPodLayout(context, device)
|
||||
else -> createNoDeviceLayout(context)
|
||||
@@ -169,8 +208,9 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
private fun createDualPodLayout(
|
||||
context: Context,
|
||||
podDevice: DualPodDevice,
|
||||
): RemoteViews = RemoteViews(context.packageName, R.layout.widget_pod_dual_layout).apply {
|
||||
log(TAG, VERBOSE) { "createSinglePodLayout(context=$context, podDevice=$podDevice)" }
|
||||
@LayoutRes layout: Int
|
||||
): RemoteViews = RemoteViews(context.packageName, layout).apply {
|
||||
log(TAG, VERBOSE) { "createSinglePodLayout(context=$context, podDevice=$podDevice), layout=${layout}" }
|
||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
|
||||
@@ -80,8 +80,6 @@ class MonitorWorker @AssistedInject constructor(
|
||||
val start = System.currentTimeMillis()
|
||||
log(TAG, VERBOSE) { "Executing $inputData now (runAttemptCount=$runAttemptCount)" }
|
||||
|
||||
setForeground(monitorNotifications.getForegroundInfo(null))
|
||||
|
||||
doDoWork()
|
||||
|
||||
val duration = System.currentTimeMillis() - start
|
||||
@@ -108,6 +106,8 @@ class MonitorWorker @AssistedInject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
setForeground(monitorNotifications.getForegroundInfo(null))
|
||||
|
||||
val monitorJob = podMonitor.mainDevice
|
||||
.setupCommonEventHandlers(TAG) { "PodMonitor" }
|
||||
.distinctUntilChanged()
|
||||
|
||||
@@ -19,7 +19,16 @@ import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.hasApiLevel
|
||||
import eu.darken.capod.common.notifications.PendingIntentCompat
|
||||
import eu.darken.capod.main.ui.MainActivity
|
||||
import eu.darken.capod.pods.core.DualPodDevice
|
||||
import eu.darken.capod.pods.core.HasCase
|
||||
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.SinglePodDevice
|
||||
import eu.darken.capod.pods.core.getBatteryLevelCase
|
||||
import eu.darken.capod.pods.core.getBatteryLevelHeadset
|
||||
import eu.darken.capod.pods.core.getBatteryLevelLeftPod
|
||||
import eu.darken.capod.pods.core.getBatteryLevelRightPod
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import javax.inject.Inject
|
||||
@@ -71,9 +80,65 @@ class MonitorNotifications @Inject constructor(
|
||||
}
|
||||
|
||||
return builder.apply {
|
||||
|
||||
// Options here should be mutually exclusive, and are prioritized by their order of importance
|
||||
// Some options are omitted here, as they will conflict with other options
|
||||
// TODO: Implement a settings pane to allow user to customize this
|
||||
val stateText = when {
|
||||
// Pods charging state
|
||||
// This goes first as pods should not be worn if it is still charging
|
||||
device is HasChargeDetection && device.isHeadsetBeingCharged -> {
|
||||
context.getString(eu.darken.capod.common.R.string.pods_charging_label)
|
||||
}
|
||||
|
||||
// Pods wear state
|
||||
device is HasEarDetection -> {
|
||||
if (device.isBeingWorn) context.getString(eu.darken.capod.common.R.string.headset_being_worn_label)
|
||||
else context.getString(eu.darken.capod.common.R.string.headset_not_being_worn_label)
|
||||
}
|
||||
|
||||
// Case charge state
|
||||
// This is under pods wear state as we don't want it conflicting with it
|
||||
device is HasCase && device.isCaseCharging -> {
|
||||
context.getString(eu.darken.capod.common.R.string.pods_charging_label)
|
||||
}
|
||||
|
||||
else -> context.getString(eu.darken.capod.common.R.string.pods_case_unknown_state)
|
||||
}
|
||||
|
||||
val batteryText = when (device) {
|
||||
is DualPodDevice -> {
|
||||
val left = device.getBatteryLevelLeftPod(context)
|
||||
val right = device.getBatteryLevelRightPod(context)
|
||||
when {
|
||||
device is HasCase -> {
|
||||
val case = device.getBatteryLevelCase(context)
|
||||
"$left $case $right"
|
||||
}
|
||||
|
||||
else -> "$left $right"
|
||||
}
|
||||
}
|
||||
|
||||
is SinglePodDevice -> {
|
||||
val headset = device.getBatteryLevelHeadset(context)
|
||||
when {
|
||||
device is HasCase -> {
|
||||
val case = device.getBatteryLevelCase(context)
|
||||
"$headset $case"
|
||||
}
|
||||
|
||||
else -> headset
|
||||
}
|
||||
}
|
||||
|
||||
else -> "?"
|
||||
}
|
||||
|
||||
setStyle(NotificationCompat.DecoratedCustomViewStyle())
|
||||
setCustomContentView(notificationViewFactory.createContentView(device))
|
||||
setCustomBigContentView(notificationViewFactory.createContentView(device))
|
||||
setSmallIcon(device.iconRes)
|
||||
setContentTitle("$batteryText ~ $stateText")
|
||||
setSubText(null)
|
||||
log(TAG, VERBOSE) { "updatingNotification(): $device" }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_path"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recording_path"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_size"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recording_size"
|
||||
style="@style/TextAppearance.AppCompat.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_compressed_size"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recording_size_compressed"
|
||||
style="@style/TextAppearance.AppCompat.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="@+id/label_compressed_size"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Primary"
|
||||
style="@style/Widget.Material3.Toolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body1"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body2"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body3"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body4"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/request_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/privacy_policy"
|
||||
style="@style/TextAppearance.MaterialComponents.Tooltip"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/grant_action"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/last_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/first_seen"
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/first_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/reception"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reception_icon"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -432,7 +432,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/status"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/last_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/reception"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reception_icon"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -175,7 +175,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/status"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/last_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/reception"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reception_icon"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/details"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -86,7 +86,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/rawdata_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/rawdata"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/signal"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableEnd="@drawable/ic_baseline_signal_cellular_alt_24"
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_left_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_case_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_right_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/signal"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableEnd="@drawable/ic_baseline_signal_cellular_alt_24"
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/headphones_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Primary"
|
||||
style="@style/Widget.Material3.Toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Primary"
|
||||
style="@style/Widget.Material3.Toolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
+1
@@ -106,6 +106,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
tools:text="AirPods Max" />
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/PodWidget.Container"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_icon"
|
||||
style="@style/PodInfoItemIcon.Notification.Large"
|
||||
android:src="@drawable/devic_airpods_pro2_left"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_left_label"
|
||||
style="@style/PodInfoItemText.Notification"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
tools:text="100%" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_charging"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_power_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_ear"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_hearing_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_case_icon"
|
||||
style="@style/PodInfoItemIcon.Notification.Large"
|
||||
android:src="@drawable/devic_airpods_gen1_case"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_case_label"
|
||||
style="@style/PodInfoItemText.Notification"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
tools:text="100%" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_case_charging"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_power_24" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_icon"
|
||||
style="@style/PodInfoItemIcon.Notification.Large"
|
||||
android:src="@drawable/devic_airpods_pro2_right"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_right_label"
|
||||
style="@style/PodInfoItemText.Notification"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
tools:text="100%" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_charging"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_power_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_ear"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_hearing_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/PodWidget.TextPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="AirPods Max" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -4,15 +4,6 @@
|
||||
style="@style/PodWidget.Container"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/PodWidget.TextPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
tools:text="AirPods Max" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -45,4 +36,14 @@
|
||||
android:src="@drawable/ic_baseline_hearing_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/PodWidget.TextPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
tools:text="AirPods Max" />
|
||||
</LinearLayout>
|
||||
@@ -18,6 +18,8 @@
|
||||
app:destination="@id/troubleShooterFragment" />
|
||||
<action
|
||||
android:id="@+id/action_overviewFragment_to_onboardingFragment"
|
||||
app:popUpTo="@id/overviewFragment"
|
||||
app:popUpToInclusive="true"
|
||||
app:destination="@id/onboardingFragment" />
|
||||
</fragment>
|
||||
|
||||
@@ -36,7 +38,9 @@
|
||||
tools:layout="@layout/onboarding_fragment">
|
||||
<action
|
||||
android:id="@+id/action_onboardingFragment_to_overviewFragment"
|
||||
app:destination="@id/overviewFragment" />
|
||||
app:destination="@id/overviewFragment"
|
||||
app:popUpToInclusive="true"
|
||||
app:popUpTo="@id/onboardingFragment" />
|
||||
</fragment>
|
||||
|
||||
</navigation>
|
||||
@@ -45,7 +45,10 @@
|
||||
<string name="settings_maindevice_model_description">Мадэль вашай прылады. Гэта дапамагае праграме апазнаць вашу прыладу, калі яна не падключана да вашага тэлефона.</string>
|
||||
<string name="settings_onepod_mode_label">Рэжым аднаго навушніка</string>
|
||||
<string name="settings_onepod_mode_description">Нашэнне абодвух навушнікаў не абавязкова, нашэнне аднаго навушніка цалкам дастаткова для запуску рэакцый.</string>
|
||||
<string name="settings_popup_caseopen_label">Паказваць апавяшчэнне пры адкрыцці футляра</string>
|
||||
<string name="settings_popup_caseopen_description">Паказваць апавяшчэнне, калі футляр прылады адчынены (эксперыментальная функцыя).</string>
|
||||
<string name="settings_popup_connected_label">Паказваць апавяшчэнне пры падключэнні</string>
|
||||
<string name="settings_popup_connected_description">Паказваць апавяшчэнне пры першапачатковым падключэнні прылады.</string>
|
||||
<string name="notification_channel_device_status_label">Статус прылады</string>
|
||||
<string name="debug_debuglog_size_label">Памер</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Сціснуты памер</string>
|
||||
@@ -94,7 +97,13 @@
|
||||
<string name="troubleshooter_ble_result_success_body">Трансляцыі даных BLE прымаюцца CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Безвынікова</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">Не ўдалося выправіць непаладку. Не дапамагла ніводная камбінацыя параметраў сумяшчальнасці.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Ваш тэлефон наогул не атрымаў ніякіх даных BLE. Вы можаце паўтарыць гэты тэст у шматлюдным месцы, каб даведацца, ці могуць быць атрыманыя даныя з іншых крыніц (акрамя вашых навушнікаў). Няма атрыманых даных, якія паказваюць на праблему з аперацыйнай сістэмай вашага тэлефона.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Ваш тэлефон атрымаў даныя BLE, але яны паступаюць з прылады, якая не падтрымліваецца. Вашы навушнікі ўключаны? Ці падтрымлівае CAPod вашы навушнікі?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Паспрабаваць яшчэ раз</string>
|
||||
<string name="troubleshoot_action">Выпраўленне непаладак</string>
|
||||
<string name="onboarding_body1">Гэта праграма дадае ў Android падтрымку спецыяльных функцый AirPod.</string>
|
||||
<string name="onboarding_body2">Не ўсе прылады Android цалкам падтрымліваюць дадатковыя функцыі AirPod. Ваша аперацыйная сістэма патрабуе карэктнай рэалізацыі функцыі Bluetooth Low Energy.</string>
|
||||
<string name="onboarding_body3">CAPod не змяшчае рэкламу і не збірае вашы даныя.</string>
|
||||
<string name="onboarding_body4">Вы можаце перайсці на CAPod Pro, каб атрымаць дадатковыя функцыі і такім чынам падтрымаць распрацоўку.</string>
|
||||
<string name="general_continue_action">Працягнуць</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">El vostre telèfon ha rebut dades BLE, però les dades no provenen de cap dispositiu compatible. Teniu els auriculars encesos? El CAPod és compatible amb els vostres auriculars?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Torna-ho a provar</string>
|
||||
<string name="troubleshoot_action">Resolució de problemes</string>
|
||||
<string name="onboarding_body1">Aquesta aplicació afegeix suport per a funcions específiques d\'AirPod a l\'Android.</string>
|
||||
<string name="onboarding_body2">No tots els dispositius Android són compatibles completament amb les funcions addicionals d\'AirPod. El vostre sistema operatiu requereix una implementació de Bluetooth de baixa energia que funcioni correctament.</string>
|
||||
<string name="onboarding_body3">El CAPod no conté anuncis i no recull les vostres dades.</string>
|
||||
<string name="onboarding_body4">Podeu actualitzar a CAPod Pro per obtenir funcions addicionals i donar suport al desenvolupament.</string>
|
||||
<string name="general_continue_action">Continua</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefon přijal data BLE, ale data nepocházejí z žádného podporovaného zařízení. Jsou sluchátka zapnutá? Podporuje CAPod vaše sluchátka?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Zkusit znovu</string>
|
||||
<string name="troubleshoot_action">Vyřešit problém</string>
|
||||
<string name="onboarding_body1">Tato aplikace přidává do Androidu podporu specifických funkcí AirPods.</string>
|
||||
<string name="onboarding_body2">Ne všechna zařízení s Androidem plně podporují speciální funkce AirPods.</string>
|
||||
<string name="onboarding_body3">CAPod neobsahuje žádné reklamy a neshromažďuje vaše údaje.</string>
|
||||
<string name="onboarding_body4">Chcete-li získat speciální funkce a podpořit vývoj, můžete přejít na verzi CAPod Pro.</string>
|
||||
<string name="general_continue_action">Pokračovat</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<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_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>
|
||||
<string name="general_continue_action">Fortfahren</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Το τηλέφωνό σας έλαβε δεδομένα BLE, αλλά τα δεδομένα δεν προέρχονται από καμία υποστηριζόμενη συσκευή. Είναι ενεργοποιημένα τα ακουστικά σας; Το CAPod υποστηρίζει τα ακουστικά σας;</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Δοκιμάστε ξανά</string>
|
||||
<string name="troubleshoot_action">Αντιμετώπιση</string>
|
||||
<string name="onboarding_body1">Αυτή η εφαρμογή προσθέτει υποστήριξη για συγκεκριμένες λειτουργίες του AirPod στο Android.</string>
|
||||
<string name="onboarding_body2">Δεν υποστηρίζουν πλήρως όλες οι συσκευές Android τις επιπλέον δυνατότητες του AirPod. Το λειτουργικό σας σύστημα απαιτεί μια σωστή εφαρμογή Bluetooth-χαμηλής ενέργειας.</string>
|
||||
<string name="onboarding_body3">Το CAPod δεν έχει διαφημίσεις και δε συλλέγει τα δεδομένα σας.</string>
|
||||
<string name="onboarding_body4">Μπορείτε να αναβαθμίσετε στο CAPod Pro για να αποκτήσετε επιπλέον λειτουργίες και να υποστηρίξετε την ανάπτυξη.</string>
|
||||
<string name="general_continue_action">Συνέχεια</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"></resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="onboarding_body1">Esta aplicación agrega soporte para funciones específicas de los AirPods para Android.</string>
|
||||
<string name="onboarding_body2">No todos los dispositivos Android son totalmente compatibles con las funciones adicionales de los AirPods. Tu sistema operativo requiere una implementación de un Bluetooth de baja energía que funcione correctamente.</string>
|
||||
<string name="onboarding_body3">CAPod no contiene anuncios y no recopila tus datos.</string>
|
||||
<string name="onboarding_body4">Puedes actualizar a CAPod Pro para obtener funciones adicionales y apoyar el desarrollo.</string>
|
||||
<string name="general_continue_action">Sigue</string>
|
||||
</resources>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<string name="general_check_action">Verificar</string>
|
||||
<string name="general_close_action">Cerrar</string>
|
||||
<string name="upgrade_capod_label">Actualizar CAPod</string>
|
||||
<string name="upgrade_capod_description">Consigue características adicionales y apoya al desarrollador.</string>
|
||||
<string name="upgrade_capod_description">Consigue las funciones adicionales y apoya al desarrollador.</string>
|
||||
<string name="settings_monitor_mode_label">Modo monitor</string>
|
||||
<string name="settings_monitor_mode_description">Bajo qué circunstancias esta aplicación monitorea los datos Bluetooth.</string>
|
||||
<string name="settings_scanner_mode_label">Modo escáner</string>
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Tu teléfono recibió los datos BLE, pero los datos no proceden de ningún dispositivo compatible. ¿Están encendidos tus auriculares? ¿Es CAPod compatible con tus auriculares?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Vuelve a intentarlo</string>
|
||||
<string name="troubleshoot_action">Reparador de los problemas</string>
|
||||
<string name="onboarding_body1">Esta aplicación agrega soporte para funciones específicas de los AirPods para Android.</string>
|
||||
<string name="onboarding_body2">No todos los dispositivos Android son totalmente compatibles con las funciones adicionales de los AirPods. Tu sistema operativo requiere una implementación en el Bluetooth de bajo consumo que funcione correctamente.</string>
|
||||
<string name="onboarding_body3">CAPod no contiene anuncios y no recopila tus datos.</string>
|
||||
<string name="onboarding_body4">Puedes actualizar a CAPod Pro para obtener funciones adicionales y apoyar el desarrollo.</string>
|
||||
<string name="general_continue_action">Seguir</string>
|
||||
</resources>
|
||||
|
||||
@@ -26,4 +26,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefoni saabusid andmed madalama energiakuluga Bluetoothi kaudu aga andmed ei pärine ühestki ühilduvast seadmest. Kas CAPod ühildub teie kõrvaklapiga?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Proovi uuesti</string>
|
||||
<string name="troubleshoot_action">Lahendamine</string>
|
||||
<string name="onboarding_body1">See rakendus lisab Androidile AirPodi võimalused.</string>
|
||||
<string name="onboarding_body2">Vaid mõned Androidi seadmed toetavad kõiki AirPodi võimalusi. Operatsioonisüsteem vajab õigesti toimivat madalama energiatarbimisega Bluetoothi tuge.</string>
|
||||
<string name="onboarding_body3">CAPodis pole reklaame ja see ei kogu andmeid.</string>
|
||||
<string name="onboarding_body4">Lisavõimaluste saamiseks ja arendamise toetamiseks soetage CAPod Pro.</string>
|
||||
<string name="general_continue_action">Jätka</string>
|
||||
</resources>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<string name="general_done_action">Terminé</string>
|
||||
<string name="general_copy_action">Copier</string>
|
||||
<string name="general_thank_you_label">Merci</string>
|
||||
<string name="general_upgrade_action">Surclasser vers Pro</string>
|
||||
<string name="general_upgrade_action">Passer Pro</string>
|
||||
<string name="general_check_action">Vérifier</string>
|
||||
<string name="general_close_action">Fermer</string>
|
||||
<string name="upgrade_capod_label">Surclasser CAPod</string>
|
||||
@@ -83,7 +83,7 @@
|
||||
<string name="help_translate_label">Traduction</string>
|
||||
<string name="help_translate_description">Aider à traduire cette appli dans votre langue préférée.</string>
|
||||
<string name="translators_thanks_title">Traducteurs</string>
|
||||
<string name="translators_thanks_description">AO</string>
|
||||
<string name="translators_thanks_description">yahoe-001</string>
|
||||
<string name="widget_description">Un widget qui affiche le dernier état connu de l’appareil.</string>
|
||||
<string name="settings_compat_indirectcallback_title">Transmission indirecte des données</string>
|
||||
<string name="settings_compat_indirectcallback_summary">Utiliser une méthode de remplacement pour recevoir les données BÉB du système (diffusion au lieu de rappel).</string>
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Votre téléphone a reçu des données, mais les données ne proviennent pas d’un appareil pris en charge. Votre casque d’écoute est-il en fonction ? CAPod prend-il votre casque d’écoute en charge ?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Réessayer</string>
|
||||
<string name="troubleshoot_action">Dépanner</string>
|
||||
<string name="onboarding_body1">Cette appli ajoute des fonctions propres aux AirPods à Android.</string>
|
||||
<string name="onboarding_body2">Tous les appareils Android ne prennent pas en charge les fonctions supplémentaires des AirPods. Votre système d’exploitation a besoin d’une mise en œuvre fonctionnelle du système à basse énergie Bluetooth.</string>
|
||||
<string name="onboarding_body3">CAPod ne présente aucune publicité et ne recueille pas vos données.</string>
|
||||
<string name="onboarding_body4">Vous pouvez passer à CAPod Pro pour obtenir des fonctions supplémentaires et soutenir le développement.</string>
|
||||
<string name="general_continue_action">Poursuivre</string>
|
||||
</resources>
|
||||
|
||||
@@ -45,7 +45,10 @@
|
||||
<string name="settings_maindevice_model_description">Model perangkat utama anda. Ini membantu aplikasi mengenali perangkat anda saat tidak terhubung ke ponsel anda.</string>
|
||||
<string name="settings_onepod_mode_label">Mode satu pod</string>
|
||||
<string name="settings_onepod_mode_description">Menggunakan kedua pod tidak diperlukan, memakai satu pod sudah cukup untuk memicu reaksi.</string>
|
||||
<string name="settings_popup_caseopen_label">Tampilkan popup kasing</string>
|
||||
<string name="settings_popup_caseopen_description">Tampilkan popup saat kasing perangkat dibuka (eksperimental).</string>
|
||||
<string name="settings_popup_connected_label">Tampilkan popup saat terkoneksi</string>
|
||||
<string name="settings_popup_connected_description">Tampilkan popup ketika perangkat terhubung pertama kalinya.</string>
|
||||
<string name="notification_channel_device_status_label">Status perangkat</string>
|
||||
<string name="debug_debuglog_size_label">Ukuran</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Ukuran terkompresi</string>
|
||||
@@ -94,7 +97,13 @@
|
||||
<string name="troubleshooter_ble_result_success_body">Siaran iklan BLE diterima oleh CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Gagal</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">Pemecahan masalah gagal. Tidak ada kombinasi opsi kompatibilitas yang membantu.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Ponsel Anda tidak menerima data BLE sama sekali. Anda dapat mencoba lagi pengujian ini di area yang ramai untuk melihat apakah sumber data (selain headphone Anda) dapat diterima. Tidak ada data yang diterima menunjukkan masalah dengan sistem operasi ponsel Anda.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telepon anda menerima data BLE, tetapi data tersebut tidak berasal dari perangkat yang didukung. Apakah headphone Anda dihidupkan? Apakah CAPod mendukung headphone Anda?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Coba lagi</string>
|
||||
<string name="troubleshoot_action">Memecahkan masalah</string>
|
||||
<string name="onboarding_body1">Aplikasi ini menambahkan bantuan untuk fitur spesifik AirPod untuk Android.</string>
|
||||
<string name="onboarding_body2">Tidak semua perangkat Android mendukung fitur AirPod ekstra. Sistem Os anda memerlukan implementasi Bluetooth-Low-Energy yang bekerja.</string>
|
||||
<string name="onboarding_body3">CAPod tidak menampilkan iklan dan tidak mengambil data anda.</string>
|
||||
<string name="onboarding_body4">Anda bisa membeli CAPod Pro agar bisa menggunakan fitur ekstra dan mendukung pengembangan aplikasi.</string>
|
||||
<string name="general_continue_action">Lanjutkan</string>
|
||||
</resources>
|
||||
|
||||
@@ -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>
|
||||
@@ -102,4 +101,9 @@ Filippo Lolli</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Il tuo smartphone ha ricevuto i dati BLE, ma i dati non provengono da un dispositivo supportato. Le tue cuffie sono accese/cariche? CAPod supporta le tue cuffie?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Riprova</string>
|
||||
<string name="troubleshoot_action">Risoluzione dei problemi</string>
|
||||
<string name="onboarding_body1">Questa applicazione fornisce supporto per le funzionalità specifiche dell AirPods su Android.</string>
|
||||
<string name="onboarding_body2">Non tutti i dispositivi Android supportano le funzionalità extra delle AirPods. Un prerequisito del tuo sistema operativo è l\'implementazione di Bluetooth-Low-Energy.</string>
|
||||
<string name="onboarding_body3">CAPod non contiene pubblicità e non raccoglie i tuoi dati.</string>
|
||||
<string name="onboarding_body4">Puoi aggiornare alla versione Pro per sbloccare funzioni aggiuntive e supportare lo sviluppo.</string>
|
||||
<string name="general_continue_action">Continua</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefon anda menerima data BLE, tetapi data itu tidak datang daripada mana-mana peranti yang disokong. Adakah fon kepala anda dihidupkan? Adakah CAPod menyokong fon kepala anda?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Cuba semula</string>
|
||||
<string name="troubleshoot_action">Selesaikan masalah</string>
|
||||
<string name="onboarding_body1">Aplikasi ini menambah sokongan untuk ciri khusus AirPod pada Android.</string>
|
||||
<string name="onboarding_body2">Tidak semua peranti Android menyokong sepenuhnya ciri AirPod tambahan. Sistem pengendalian anda memerlukan pelaksanaan Bluetooth-Tenaga-Rendah yang berfungsi dengan betul.</string>
|
||||
<string name="onboarding_body3">CAPod tiada iklan serta tidak mengumpul data anda.</string>
|
||||
<string name="onboarding_body4">Anda boleh menaik taraf kepada CAPod Pro untuk mendapatkan ciri tambahan serta pembangunan sokongan.</string>
|
||||
<string name="general_continue_action">Teruskan</string>
|
||||
</resources>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_primaryInverse</item>
|
||||
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item tools:targetApi="29" name="android:enforceNavigationBarContrast">true</item>
|
||||
<item tools:targetApi="29" name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Je telefoon heeft BLE-gegevens ontvangen, maar de gegevens zijn niet afkomstig van een ondersteund apparaat. Staat je koptelefoon aan? Ondersteunt CAPod je koptelefoon?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Probeer opnieuw</string>
|
||||
<string name="troubleshoot_action">Problemen oplossen</string>
|
||||
<string name="onboarding_body1">Deze app voegt ondersteuning voor AirPod-specifieke functies toe aan Android.</string>
|
||||
<string name="onboarding_body2">Niet alle Android-apparaten ondersteunen de extra AirPod-functies volledig. Je besturingssysteem vereist een correct werkende Bluetooth-Low-Energy implementatie.</string>
|
||||
<string name="onboarding_body3">CAPod heeft geen advertenties en verzamelt je gegevens niet.</string>
|
||||
<string name="onboarding_body4">Je kunt upgraden naar CAPod Pro om extra functies te krijgen en de ontwikkeling te ondersteunen.</string>
|
||||
<string name="general_continue_action">Doorgaan</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefonen din mottok BLE-data, men dataene kommer ikke fra en støttet enhet. Er hodetelefonene dine slått på? Støtter CAPod din type hodetelefoner?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Prøv igjen</string>
|
||||
<string name="troubleshoot_action">Feilsøk</string>
|
||||
<string name="onboarding_body1">Denne appen legger til støtte for AirPod-spesifikke funksjoner til Android.</string>
|
||||
<string name="onboarding_body2">Ikke alle Android-enheter støtter de ekstra AirPod-funksjonene fullt ut. Operativsystemet ditt krever en fungerende Bluetooth-Low-Energy-implementering.</string>
|
||||
<string name="onboarding_body3">CAPod har ingen annonser og samler ikke inn dataene dine.</string>
|
||||
<string name="onboarding_body4">Du kan oppgradere til CAPod Pro for å få ekstra funksjoner og støtte utviklingen.</string>
|
||||
<string name="general_continue_action">Fortsett</string>
|
||||
</resources>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<string name="settings_maindevice_model_description">Model twojego głównego urządzenia. Pomaga aplikacji rozpoznać twoje urządzenie, gdy nie jest połączone z telefonem.</string>
|
||||
<string name="settings_onepod_mode_label">Tryb jednego pod\'a</string>
|
||||
<string name="settings_onepod_mode_description">Noszenie obu pod\'ów nie jest wymagane. Wystarczy jeden, aby aktywować reakcje.</string>
|
||||
<string name="settings_popup_caseopen_label">Wyświetl okienko przybornika</string>
|
||||
<string name="settings_popup_caseopen_label">Wyświetl okienko obudowy</string>
|
||||
<string name="settings_popup_caseopen_description">Wyświetla informację, gdy obudowa urządzenia jest otwarta (eksperymentalnie).</string>
|
||||
<string name="settings_popup_connected_label">Wyświetl okienko połączenia</string>
|
||||
<string name="settings_popup_connected_description">Wyświetla okienko, gdy urządzenie łączy się po raz pierwszy.</string>
|
||||
@@ -89,7 +89,7 @@
|
||||
<string name="settings_compat_indirectcallback_summary">Użyj alternatywnej metody odbierania danych BLE z systemu (transmisja zamiast połączenia zwrotnego).</string>
|
||||
<string name="troubleshooter_title">Rozwiązywanie problemów</string>
|
||||
<string name="troubleshooter_ble_intro_title">Transmisja Bluetooth Low Energy</string>
|
||||
<string name="troubleshooter_ble_intro_body1">AirPods (i podobne słuchawki) transmitują informacje o stanie za pomocą technologii BLE zwanej „reklamami”. Niektóre telefony nie obsługują tej technologii poprawnie. CAPod może spróbować to naprawić, wypróbowując różne opcje zgodności, dopóki dane nie zostaną odebrane. Rozpocznij odtwarzanie muzyki na słuchawkach i umieść je blisko telefonu, a następnie rozpocznij proces.</string>
|
||||
<string name="troubleshooter_ble_intro_body1">AirPods (i podobne słuchawki) transmitują informacje o stanie za pomocą technologii BLE zwanej „reklamami”. Niektóre telefony nie obsługują tej technologii poprawnie. CAPod może spróbować to naprawić, testując różne opcje zgodności, dopóki dane nie zostaną odebrane. Rozpocznij odtwarzanie muzyki na słuchawkach i umieść je blisko telefonu, a następnie rozpocznij proces.</string>
|
||||
<string name="troubleshooter_ble_intro_start_action">Rozpocznij rozwiązywanie problemów</string>
|
||||
<string name="troubleshooter_ble_process_title">Rozwiązywanie problemów w toku</string>
|
||||
<string name="troubleshooter_ble_process_subtile">Każdy etap zajmuje 5–10 sekund</string>
|
||||
@@ -97,8 +97,13 @@
|
||||
<string name="troubleshooter_ble_result_success_body">Audycje reklamowe BLE są odbierane przez CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Niepowodzenie</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">Rozwiązywanie problemów nie powiodło się. Nie pomogła żadna kombinacja opcji kompatybilności.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Twój telefon nie odebrał żadnych danych BLE. Możesz ponowić test w zatłoczonym obszarze, aby sprawdzić, czy źródła danych (inne niż twoje słuchawki) mogą być odbierane. Brak odbioru danych wskazuje na problem z systemem operacyjnym telefonu.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Twój telefon odebrał dane BLE, jednak nie pochodzą one od obsługiwanego urządzenia. Czy twoje słuchawki są włączone? Czy CAPod obsługuje twoje słuchawki?</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Twój telefon nie odebrał żadnych danych BLE. Możesz ponowić test w zatłoczonym obszarze, aby sprawdzić, czy źródła danych (inne niż Twoje słuchawki) mogą być odbierane. Brak odbioru danych wskazuje na problem z systemem operacyjnym telefonu.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Twój telefon odebrał dane BLE, jednak nie pochodzą one z obsługiwanego urządzenia. Czy Twoje słuchawki są włączone? Czy CAPod obsługuje Twoje słuchawki?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Spróbuj ponownie</string>
|
||||
<string name="troubleshoot_action">Rozwiązywanie problemów</string>
|
||||
<string name="onboarding_body1">Ta aplikacja dodaje wsparcie dla funkcji AirPods na Androidzie.</string>
|
||||
<string name="onboarding_body2">Nie wszystkie urządzenia z Androidem w pełni wspierają dodatkowe funkcje AirPods. Twój system operacyjny wymaga dobrze działającej implementacji Bluetooth-Low-Energy.</string>
|
||||
<string name="onboarding_body3">CAPod nie wyświetla reklam i nie zbiera Twoich danych.</string>
|
||||
<string name="onboarding_body4">Możesz ulepszyć do CAPod Pro, by zyskać dodatkowe funkcje i wesprzeć rozwój.</string>
|
||||
<string name="general_continue_action">Kontynuuj</string>
|
||||
</resources>
|
||||
|
||||
@@ -45,7 +45,10 @@
|
||||
<string name="settings_maindevice_model_description">O modelo do seu dispositivo principal. Isso ajuda o aplicativo a reconhecer seu dispositivo quando ele não está conectado ao seu telefone.</string>
|
||||
<string name="settings_onepod_mode_label">Modo de um airpod</string>
|
||||
<string name="settings_onepod_mode_description">Não é necessário usar os dois airpods, usar um único airpod é suficiente para destravar reações.</string>
|
||||
<string name="settings_popup_caseopen_label">Mostrar pop-up da case</string>
|
||||
<string name="settings_popup_caseopen_description">Mostrar um pop-up quando o estojo do dispositivo for aberto (experimental).</string>
|
||||
<string name="settings_popup_connected_label">Mostrar pop-up de conexão</string>
|
||||
<string name="settings_popup_connected_description">Mostrar um pop-up quando o dispositivo se conectar pela primeira vez.</string>
|
||||
<string name="notification_channel_device_status_label">Status do dispositivo</string>
|
||||
<string name="debug_debuglog_size_label">Tamanho</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Tamanho compactado</string>
|
||||
@@ -94,7 +97,13 @@
|
||||
<string name="troubleshooter_ble_result_success_body">As transmissões de anúncios BLE estão sendo recebidas pelo CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Sem sucesso</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">A solução de problemas falhou. Nenhuma combinação de opções de compatibilidade ajudou.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Seu telefone não recebeu nenhum dado BLE. Você pode tentar novamente este teste em uma área lotada para ver se fontes de dados (além dos fones de ouvido) podem ser recebidas. Nenhum dado recebido indica um problema no sistema operacional do seu telefone.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Seu telefone recebeu dados BLE, mas os dados não vêm de nenhum dispositivo compatível. Seus fones de ouvido estão ligados? O CAPod suporta seu fone de ouvido?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Tentar novamente</string>
|
||||
<string name="troubleshoot_action">Solucionar problemas</string>
|
||||
<string name="onboarding_body1">Este aplicativo adiciona suporte para recursos específicos do AirPod ao Android.</string>
|
||||
<string name="onboarding_body2">Nem todos os dispositivos Android oferecem suporte total aos recursos extras do AirPod. Seu sistema operacional requer uma implementação de Bluetooth-Low-Energy funcionando corretamente.</string>
|
||||
<string name="onboarding_body3">CAPod não possui anúncios e não coleta seus dados.</string>
|
||||
<string name="onboarding_body4">Você pode atualizar para o CAPod Pro para obter recursos extras e apoiar o desenvolvimento.</string>
|
||||
<string name="general_continue_action">Continuar</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">O seu telefone recebeu dados BLE, mas os dados não vêm de nenhum dispositivo compatível. Os seus auscultadores estão ligados? O CAPod é compatível com os seus auscultadores?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Tentar de novo</string>
|
||||
<string name="troubleshoot_action">Resolver problemas</string>
|
||||
<string name="onboarding_body1">Esta aplicação adiciona suporte para funcionalidades específicas dos AirPods no Android.</string>
|
||||
<string name="onboarding_body2">Nem todos os dispositivos Android suportam todas as funcionalidades extra dos AirPods. O seu sistema operativo requer uma implementação de Bluetooth-Low-Energy a funcionar corretamente.</string>
|
||||
<string name="onboarding_body3">CAPod não tem anúncios nem coleciona os seus dados.</string>
|
||||
<string name="onboarding_body4">Pode obter o CAPod Pro para ganhar funcionalidades extra e apoiar o desenvolvimento.</string>
|
||||
<string name="general_continue_action">Continuar</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,2 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"></resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="general_share_action">Distribuie</string>
|
||||
<string name="general_done_action">Efectuat</string>
|
||||
<string name="general_copy_action">Copiază</string>
|
||||
<string name="general_thank_you_label">Mulțumesc</string>
|
||||
<string name="general_upgrade_action">Actualizare</string>
|
||||
<string name="general_check_action">Verifică</string>
|
||||
<string name="general_close_action">Închide</string>
|
||||
<string name="upgrade_capod_label">Actualizați CaPod</string>
|
||||
<string name="upgrade_capod_description">Obțineți funcții suplimentare și sprijiniți dezvoltatorul.</string>
|
||||
<string name="settings_monitor_mode_label">Modul monitorizare</string>
|
||||
<string name="settings_monitor_mode_description">În ce circumstanțe această aplicație monitorizează datele Bluetooth.</string>
|
||||
<string name="settings_scanner_mode_label">Modul scanare</string>
|
||||
<string name="settings_scanner_mode_description">Scanerul de date Bluetooth Energie Scăzută (BLE) ar trebui să prioritizeze performanța sau să economisească energia?</string>
|
||||
<string name="settings_autopause_label">Pauză automată</string>
|
||||
<string name="settings_autopause_description">Întrerupeți sunetul când scoateți dispozitivul din ureche.</string>
|
||||
<string name="settings_showall_label">Arată toate dispozitivele</string>
|
||||
<string name="settings_showall_description">Afișați dispozitivele altor persoane care sunt în apropierea dvs.</string>
|
||||
<string name="settings_autopplay_label">Redare automată</string>
|
||||
<string name="settings_autoplay_description">Porniți redarea audio când dispozitivul este purtat.</string>
|
||||
<string name="settings_fake_data_label">Date false</string>
|
||||
<string name="settings_fake_data_description">Afișați date false, ex: simulați dispozitive care nu există.</string>
|
||||
<string name="settings_debug_label">Setări de depanare</string>
|
||||
<string name="settings_debug_description">Setări suplimentare pentru a ajuta la depanarea problemelor cu aplicația.</string>
|
||||
<string name="settings_signal_minimum_label">Calitatea minimă a semnalului</string>
|
||||
<string name="settings_signal_minimum_description">Calitatea minimă a semnalului pe care trebuie să o aibă un dispozitiv trebuie să fie considerată a dvs.</string>
|
||||
<string name="settings_autoconnect_label">Conectare automată</string>
|
||||
<string name="settings_autoconnect_description">Dacă Android nu se conectează automat, îl putem întreba și noi. Aceasta va seta setarea modului monitorizare la „Întotdeauna”.</string>
|
||||
<string name="settings_autoconnect_condition_label">Condiția de conectare automată</string>
|
||||
<string name="settings_autoconnect_condition_description">Când ar trebui să încercăm să ne conectăm la dispozitivul dvs.?</string>
|
||||
<string name="settings_reaction_label">Reacții</string>
|
||||
<string name="settings_reaction_description">Reacționați la evenimente și comportamente.</string>
|
||||
<string name="settings_category_yourdevice_label">Dispozitivul tău</string>
|
||||
<string name="settings_category_compatibility_options_title">Opțiuni de compatibilitate</string>
|
||||
<string name="settings_category_compatibility_options_description">Nu atingeți dacă totul funcționează ;)</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_title">Dezactivați filtrarea hardware-ului</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_summary">Nu delegați filtrarea datelor către sistem, în schimb, obțineți toate datele și filtrați în cadrul aplicației.</string>
|
||||
<string name="settings_compat_offloaded_batching_disabled_title">Dezactivați lotizarea hardware</string>
|
||||
<string name="settings_compat_offloaded_batching_disabled_summary">Nu lăsați sistemul să grupeze datele BLE colectate înainte de a ni le transmite.</string>
|
||||
<string name="settings_maindevice_address_label">Adresa dispozitivului dvs.</string>
|
||||
<string name="settings_maindevice_address_description">Adresa dispozitivului dvs. asociat. Aplicația utilizează aceasta pentru a determina când este conectată la telefonul dvs.</string>
|
||||
<string name="settings_maindevice_address_none">Niciunul</string>
|
||||
<string name="settings_maindevice_model_label">Modelul dispozitivului dvs.</string>
|
||||
<string name="settings_maindevice_model_description">Modelul dispozitivului principal. Acest lucru ajută aplicația să recunoască dispozitivul dvs. atunci când nu este conectat la telefonul dvs.</string>
|
||||
<string name="settings_onepod_mode_label">Modul de utilizare o singură cască</string>
|
||||
<string name="settings_onepod_mode_description">Nu este necesar să purtați ambele caști, o singură cască este suficientă pentru a declanșa reacțiile.</string>
|
||||
<string name="settings_popup_caseopen_label">Afișați pop-upul carcasei</string>
|
||||
<string name="settings_popup_caseopen_description">Afișați un pop-up când este deschisă carcasa dispozitivului (experimental).</string>
|
||||
<string name="settings_popup_connected_label">Afișați pop-upul conexiunii</string>
|
||||
<string name="settings_popup_connected_description">Afișați un pop-up când dispozitivul se conectează pentru prima dată.</string>
|
||||
<string name="notification_channel_device_status_label">Starea dispozitivului</string>
|
||||
<string name="debug_debuglog_size_label">Dimensiune</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Dimensiune comprimată</string>
|
||||
<string name="debug_notification_channel_label">Notificări de depanare</string>
|
||||
<string name="debug_debuglog_file_label">Fișier jurnal înregistrat</string>
|
||||
<string name="debug_debuglog_record_action">Înregistrați jurnalul de depanare</string>
|
||||
<string name="settings_support_installid_label">ID de instalare</string>
|
||||
<string name="settings_support_installid_desc">Rapoartele automate de eroare sunt anonime. Partajați ID-ul de instalare dacă dezvoltatorul trebuie să vă găsească rapoartele de eroare.</string>
|
||||
<string name="settings_support_label">Suport</string>
|
||||
<string name="settings_support_description">Dacă ai nevoie de ajutor.</string>
|
||||
<string name="issue_tracker_label">Detector de probleme</string>
|
||||
<string name="issue_tracker_description">Un instrument public de urmărire a problemelor pentru rapoartele de erori și solicitările de funcții (numai în limba engleză).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Un loc în care să stai și să pui întrebări.</string>
|
||||
<string name="changelog_label">Jurnalul modificărilor</string>
|
||||
<string name="settings_label">Setări</string>
|
||||
<string name="settings_privacy_policy_label">Politica de confidențialitate</string>
|
||||
<string name="settings_privacy_policy_desc">Responsabilitatea gestionării datelor.</string>
|
||||
<string name="settings_licenses_label">Licențe</string>
|
||||
<string name="settings_category_other_label">Altele</string>
|
||||
<string name="settings_general_label">Setări</string>
|
||||
<string name="settings_general_description">Ajustări generale care afectează întreaga aplicație.</string>
|
||||
<string name="settings_acknowledgements_label">Mulțumiri</string>
|
||||
<string name="settings_debug_autoreports_label">Rapoarte automate de erori</string>
|
||||
<string name="settings_debug_autoreports_description">Raportează automat probleme, ex: detalii despre o blocare a aplicației, astfel încât să îmi dau seama cum să o rezolv.</string>
|
||||
<string name="settings_debug_mode_label">Modul de depanare</string>
|
||||
<string name="settings_debug_mode_description">Afișați informații suplimentare pentru a remedia problemele.</string>
|
||||
<string name="settings_blescanner_unfiltered_label">Date BLE nefiltrate</string>
|
||||
<string name="settings_blescanner_unfiltered_description">Eliminați toate filtrele din scanerul BLE pentru a afișa toate datele BLE difuzate. Util pentru a adăuga suport pentru noile tipuri de căști.</string>
|
||||
<string name="settings_compatibility_mode_label">Mod de compatibilitate</string>
|
||||
<string name="settings_compatibility_mode_description">Dezactivați optimizările pentru a îmbunătăți compatibilitatea. Încercați acest lucru dacă nu vedeți nicio dată.</string>
|
||||
<string name="help_translate_label">Traducere</string>
|
||||
<string name="help_translate_description">Ajută la traducerea acestei aplicații în limba ta preferată.</string>
|
||||
<string name="translators_thanks_title">Traducători</string>
|
||||
<string name="translators_thanks_description">Darken</string>
|
||||
<string name="widget_description">Un widget care arată starea ultimului dispozitiv cunoscut.</string>
|
||||
<string name="settings_compat_indirectcallback_title">Livrarea indirectă a datelor</string>
|
||||
<string name="settings_compat_indirectcallback_summary">Utilizați o metodă alternativă pentru a primi date BLE de la sistem (difuzare în loc de apel invers).</string>
|
||||
<string name="troubleshooter_title">Depanator</string>
|
||||
<string name="troubleshooter_ble_intro_title">Transmisii Bluetooth Energie Scăzută (BLE)</string>
|
||||
<string name="troubleshooter_ble_intro_body1">AirPod-urile (și căștile similare) transmit informații despre stare folosind o tehnologie BLE numită „reclame”. Unele telefoane nu implementează corect această tehnologie. CAPod poate încerca să remedieze acest lucru încercând diferite opțiuni de compatibilitate până la primirea datelor. Porniți redarea muzicii pe căști și plasați-le aproape de telefon, apoi începeți procesul.</string>
|
||||
<string name="troubleshooter_ble_intro_start_action">Începeți depanarea</string>
|
||||
<string name="troubleshooter_ble_process_title">Depanare în progres</string>
|
||||
<string name="troubleshooter_ble_process_subtile">Fiecare pas durează 5-10 secunde</string>
|
||||
<string name="troubleshooter_ble_result_success_title">Succes</string>
|
||||
<string name="troubleshooter_ble_result_success_body">Emisiunile de reclame BLE sunt recepționate de CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Eșuat</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">Depanarea a eșuat. Nicio combinație de compatibilitate nu a ajutat.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Telefonul dvs. nu a primit deloc date BLE. Puteți reîncerca acest test într-o zonă aglomerată pentru a vedea dacă sursele de date (altele decât căștile) pot fi recepționate. Nicio dată primită indică o problemă cu sistemul de operare al telefonului dvs.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefonul dvs. a primit date BLE, dar datele nu provin de la niciun dispozitiv acceptat. Căștile tale sunt pornite? CAPod vă acceptă căștile?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Încearcă din nou</string>
|
||||
<string name="troubleshoot_action">Depanare</string>
|
||||
<string name="onboarding_body1">Această aplicație adaugă suport pentru caracteristicile specifice AirPod pentru Android.</string>
|
||||
<string name="onboarding_body2">Nu toate dispozitivele Android acceptă pe deplin funcțiile suplimentare AirPod. Sistemul dvs. de operare necesită o implementare Bluetooth Energie Scăzută (BLE) care funcționează corect.</string>
|
||||
<string name="onboarding_body3">CAPod nu are reclame și nu colectează datele dumneavoastră.</string>
|
||||
<string name="onboarding_body4">Puteți face upgrade la CAPod Pro pentru a obține funcții suplimentare și pentru a sprijini dezvoltarea.</string>
|
||||
<string name="general_continue_action">Continuă</string>
|
||||
</resources>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<string name="settings_category_compatibility_options_title">Настройки совместимости</string>
|
||||
<string name="settings_category_compatibility_options_description">Не трогать, если всё работает :)</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_title">Отключить аппаратную фильтрацию</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_summary">Не делегировать фильтрация данных в систему, вместо этого получайте все данные и фильтр в приложение.</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_summary">Не делегируйте фильтрацию данных системе, вместо этого получайте все данные и фильтр в приложении.</string>
|
||||
<string name="settings_compat_offloaded_batching_disabled_title">Отключить аппаратное пакетирование</string>
|
||||
<string name="settings_compat_offloaded_batching_disabled_summary">Не позволять системной группе собирать данные BLE до их пересылки нам.</string>
|
||||
<string name="settings_maindevice_address_label">Адрес Вашего устройства</string>
|
||||
@@ -102,4 +102,9 @@ AL_Cool_T</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Ваш телефон получил BLE данные, но данные не поступают ни с одного поддерживаемого устройства. Ваши наушники включены? Поддерживает ли CAPod ваши наушники?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Попробуйте еще раз</string>
|
||||
<string name="troubleshoot_action">Устранение неполадок</string>
|
||||
<string name="onboarding_body1">Приложение обеспечивает поддержку специфичных функций AirPod на Android.</string>
|
||||
<string name="onboarding_body2">Не все устройства Android полностью поддерживают дополнительные функции AirPod. Вашей операционной системе требуется корректно работающая версия Bluetooth-Low-Energy.</string>
|
||||
<string name="onboarding_body3">CAPod не содержит рекламы и не собирает Ваши данные.</string>
|
||||
<string name="onboarding_body4">Вы можете обновиться до CAPod Pro для дополнительных функций и поддержки разработки.</string>
|
||||
<string name="general_continue_action">Продолжить</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Váš telefón prijal údaje BLE, ale údaje nepochádzajú zo žiadneho podporovaného zariadenia. Máte zapnuté slúchadlá? Podporuje CAPod vaše slúchadlá?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Skúste znova</string>
|
||||
<string name="troubleshoot_action">Riešiť problém</string>
|
||||
<string name="onboarding_body1">Táto aplikácia pridáva podporu pre špecifické funkcie AirPod do systému Android.</string>
|
||||
<string name="onboarding_body2">Nie všetky zariadenia so systémom Android plne podporujú ďalšie funkcie AirPod. Váš operačný systém vyžaduje správne fungujúcu implementáciu Bluetooth-Low-Energy.</string>
|
||||
<string name="onboarding_body3">CAPod nemá žiadne reklamy a nezhromažďuje vaše údaje.</string>
|
||||
<string name="onboarding_body4">Môžete upgradovať na CAPod Pro, aby ste získali ďalšie funkcie a podporili vývoj.</string>
|
||||
<string name="general_continue_action">Pokračovať</string>
|
||||
</resources>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<string name="changelog_label">Sürüm günlüğü</string>
|
||||
<string name="settings_label">Ayarlar</string>
|
||||
<string name="settings_privacy_policy_label">Gizlilik politikası</string>
|
||||
<string name="settings_privacy_policy_desc">Verileri sorumlu bir şekilde işler.</string>
|
||||
<string name="settings_privacy_policy_desc">Verilerinizi sorumlu bir şekilde işliyoruz.</string>
|
||||
<string name="settings_licenses_label">Lisanslar</string>
|
||||
<string name="settings_category_other_label">Diğer</string>
|
||||
<string name="settings_general_label">Ayarlar</string>
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefonunuz BLE verilerini aldı, ancak veriler desteklenen herhangi bir aygıttan gelmiyor. Kulaklığınız açık mı? CAPod kulaklığınızı destekliyor mu?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Tekrar deneyin</string>
|
||||
<string name="troubleshoot_action">Sorun giderme</string>
|
||||
<string name="onboarding_body1">Bu uygulama Android\'e AirPod\'a özgü özellikler için destek ekler.</string>
|
||||
<string name="onboarding_body2">Tüm Android cihazlar ekstra AirPod özelliklerini tam olarak desteklemez. İşletim sisteminiz doğru çalışan bir Bluetooth-Düşük Enerji uygulaması gerektirir.</string>
|
||||
<string name="onboarding_body3">CAPod\'da reklam yoktur ve verilerinizi toplamaz.</string>
|
||||
<string name="onboarding_body4">Ekstra özellikler kazanmak ve geliştirmeyi desteklemek için CAPod Pro\'ya yükseltebilirsiniz.</string>
|
||||
<string name="general_continue_action">Devam et</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,9 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Ваш смартфон отримав BLE дані, проте вони не від одного з підтримуваних пристроїв. Ваші навушники увімкнено? CAPod підтримує цей тип навушників?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Спробувати знову</string>
|
||||
<string name="troubleshoot_action">Вирішення проблем</string>
|
||||
<string name="onboarding_body1">Цей додаток додає підтримку функцій AirPod в Android.</string>
|
||||
<string name="onboarding_body2">Не всі Android пристрої повністю підтримують додаткові функції AirPod. Ваша операційна система повинна підтримувати коректну реалізацію Bluetooth-Low-Energy.</string>
|
||||
<string name="onboarding_body3">CAPod не містить реклами та не збирає ваші дані.</string>
|
||||
<string name="onboarding_body4">Ви можете оновитись до CAPod Pro, щоб отримати підтримку додаткових функцій та підтримати розробку.</string>
|
||||
<string name="general_continue_action">Продовжити</string>
|
||||
</resources>
|
||||
|
||||
@@ -79,4 +79,9 @@
|
||||
<string name="translators_thanks_title">Dịch thuật</string>
|
||||
<string name="translators_thanks_description">dovanchuc7521</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Điện thoại của bạn hoàn toàn không nhận được bất kỳ dữ liệu BLE nào. Bạn có thể thử lại bài kiểm tra này ở khu vực đông người để xem có thể nhận được các nguồn dữ liệu (không phải tai nghe của bạn) hay không. Không nhận được dữ liệu nào cho thấy có vấn đề với hệ điều hành điện thoại của bạn.</string>
|
||||
<string name="onboarding_body1">Ứng dụng này bổ sung hỗ trợ cho các tính năng cụ thể của AirPod cho Android.</string>
|
||||
<string name="onboarding_body2">Không phải tất cả các thiết bị Android đều hỗ trợ đầy đủ các tính năng bổ sung của AirPod. Hệ điều hành của bạn yêu cầu triển khai Bluetooth-Năng lượng thấp hoạt động chính xác.</string>
|
||||
<string name="onboarding_body3">CAPod không có quảng cáo và không thu thập dữ liệu của bạn.</string>
|
||||
<string name="onboarding_body4">Bạn có thể nâng cấp lên CAPod Pro để có thêm các tính năng và hỗ trợ phát triển.</string>
|
||||
<string name="general_continue_action">Tiếp tục</string>
|
||||
</resources>
|
||||
|
||||
@@ -94,7 +94,16 @@
|
||||
<string name="troubleshooter_ble_process_title">故障排除进行中</string>
|
||||
<string name="troubleshooter_ble_process_subtile">每个步骤需花费 5-10 秒钟</string>
|
||||
<string name="troubleshooter_ble_result_success_title">成功</string>
|
||||
<string name="troubleshooter_ble_result_success_body">CAPod 正在接收 BLE 广告广播</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">失败</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">故障排除失败,兼容性选项的组合没有帮助</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">您的手机未收到任何 BLE 数据。您可以在人多的地方重试此测试,看看能否接收到数据源(耳机除外)。若未收到任何数据则表明您的手机系统存在问题</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">您的手机收到了 BLE 数据,但该数据并非来自任何受支持的设备。您的耳机电源打开了吗?CAPod 支持您的耳机吗?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">重试</string>
|
||||
<string name="troubleshoot_action">故障排除</string>
|
||||
<string name="onboarding_body1">本应用为 Android 增加 AirPod 相关的专用功能。</string>
|
||||
<string name="onboarding_body2">并非所有 Android 设备都充分支持额外的 AirPod 功能。您的操作系统必须正确处理低功耗蓝牙的相关内容。</string>
|
||||
<string name="onboarding_body3">CAPod 不含广告且不会收集您的数据。</string>
|
||||
<string name="onboarding_body4">您可以升级 CAPod Pro 以获得额外功能和支持开发者。</string>
|
||||
<string name="general_continue_action">继续</string>
|
||||
</resources>
|
||||
|
||||
@@ -101,4 +101,5 @@
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">您的手機收到了低功耗藍牙資料,但此資料並非來自任何支援的裝置。您的耳機是否已開機?CAPod 是否支援您的耳機?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">再試一次</string>
|
||||
<string name="troubleshoot_action">疑難排解</string>
|
||||
<string name="general_continue_action">繼續</string>
|
||||
</resources>
|
||||
|
||||
@@ -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,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="MyCardView" parent="Widget.MaterialComponents.CardView">
|
||||
<style name="MyCardView" parent="Widget.Material3.CardView.Outlined">
|
||||
<item name="android:layout_marginTop">8dp</item>
|
||||
<item name="android:layout_marginStart">8dp</item>
|
||||
<item name="android:layout_marginEnd">8dp</item>
|
||||
@@ -24,13 +24,18 @@
|
||||
<item name="tint">?android:attr/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemIcon.Notification.Large" parent="PodInfoItemIcon.Notification">
|
||||
<item name="android:layout_height">40dp</item>
|
||||
<item name="android:layout_width">40dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemText.Notification" parent="TextAppearance.Compat.Notification.Title">
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemIcon" parent="TextAppearance.MaterialComponents.Body2">
|
||||
<style name="PodInfoItemIcon" parent="TextAppearance.Material3.BodyMedium">
|
||||
<item name="android:layout_height">20dp</item>
|
||||
<item name="android:layout_width">20dp</item>
|
||||
<item name="android:tintMode">multiply</item>
|
||||
@@ -43,7 +48,7 @@
|
||||
<item name="android:layout_width">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemText" parent="TextAppearance.MaterialComponents.Body2">
|
||||
<style name="PodInfoItemText" parent="TextAppearance.Material3.BodyMedium">
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
</style>
|
||||
@@ -72,4 +77,4 @@
|
||||
<style name="PodWidget.TextSecondary">
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
<item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_primaryInverse</item>
|
||||
|
||||
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item tools:targetApi="29" name="android:enforceNavigationBarContrast">true</item>
|
||||
<item tools:targetApi="29" name="android:navigationBarColor">@android:color/transparent</item>
|
||||
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://github.com/adolfintel/OpenPods" />
|
||||
</eu.darken.capod.common.preferences.IntentPreference>
|
||||
<eu.darken.capod.common.preferences.IntentPreference
|
||||
android:key="thanks.magicpods"
|
||||
android:summary="Pioneering AirPod support on Windows"
|
||||
android:title="MagicPods project"
|
||||
app:iconSpaceReserved="false">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://github.com/steam3d/MagicPods-Windows" />
|
||||
</eu.darken.capod.common.preferences.IntentPreference>
|
||||
<eu.darken.capod.common.preferences.IntentPreference
|
||||
android:key="thanks.furiousmac"
|
||||
android:summary="Research on the continuity protocol"
|
||||
|
||||
@@ -6,19 +6,19 @@
|
||||
android:key="debug.log.record"
|
||||
android:title="@string/debug_debuglog_record_action" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_bug_report_24"
|
||||
android:key="debug.mode.enabled"
|
||||
android:summary="@string/settings_debug_mode_description"
|
||||
android:title="@string/settings_debug_mode_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_data_array_24"
|
||||
android:key="debug.fakedata.enabled"
|
||||
android:summary="@string/settings_fake_data_description"
|
||||
android:title="@string/settings_fake_data_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_devices_other_24"
|
||||
android:key="debug.blescanner.unfiltered.enabled"
|
||||
android:summary="@string/settings_blescanner_unfiltered_description"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
android:summary="@string/settings_scanner_mode_description"
|
||||
android:title="@string/settings_scanner_mode_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_devices_other_24"
|
||||
android:key="core.showall.enabled"
|
||||
android:summary="@string/settings_showall_description"
|
||||
@@ -49,19 +49,19 @@
|
||||
android:title="@string/settings_category_compatibility_options_title"
|
||||
app:icon="@drawable/ic_chip_24">
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_filter_cog_outline_24"
|
||||
android:key="core.compat.offloaded.filtering.disabled"
|
||||
android:summary="@string/settings_compat_offloaded_filtering_disabled_summary"
|
||||
android:title="@string/settings_compat_offloaded_filtering_disabled_title" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_format_list_group_24"
|
||||
android:key="core.compat.offloaded.batching.disabled"
|
||||
android:summary="@string/settings_compat_offloaded_batching_disabled_summary"
|
||||
android:title="@string/settings_compat_offloaded_batching_disabled_title" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_strategy_24"
|
||||
android:key="core.compat.indirectcallback.enabled"
|
||||
android:summary="@string/settings_compat_indirectcallback_summary"
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_looks_one_24"
|
||||
android:key="reaction.onepod.enabled"
|
||||
android:summary="@string/settings_onepod_mode_description"
|
||||
android:title="@string/settings_onepod_mode_label" />
|
||||
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_play_circle_24"
|
||||
android:key="reaction.autoplay.enabled"
|
||||
android:summary="@string/settings_autoplay_description"
|
||||
android:title="@string/settings_autopplay_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_pause_circle_24"
|
||||
android:key="reaction.autopause.enabled"
|
||||
android:summary="@string/settings_autopause_description"
|
||||
android:title="@string/settings_autopause_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_bluetooth_connected_24"
|
||||
android:key="reaction.autoconnect.enabled"
|
||||
android:summary="@string/settings_autoconnect_description"
|
||||
@@ -32,13 +32,13 @@
|
||||
android:summary="@string/settings_autoconnect_condition_description"
|
||||
android:title="@string/settings_autoconnect_condition_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_message_outline_24"
|
||||
android:key="reaction.popup.caseopen"
|
||||
android:summary="@string/settings_popup_caseopen_description"
|
||||
android:title="@string/settings_popup_caseopen_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_message_24"
|
||||
android:key="reaction.popup.connected"
|
||||
android:summary="@string/settings_popup_connected_description"
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
android:data="https://github.com/d4rken-org/capod/issues" />
|
||||
</eu.darken.capod.common.preferences.IntentPreference>
|
||||
|
||||
<!-- Hide Install-ID and bug reporting settings, but keep for possible use in the future.
|
||||
<PreferenceCategory app:title="@string/settings_category_other_label">
|
||||
<Preference
|
||||
android:icon="@drawable/ic_id_onsurface"
|
||||
android:key="support.installid"
|
||||
android:summary="@string/settings_support_installid_desc"
|
||||
android:title="@string/settings_support_installid_label"
|
||||
app:isPreferenceVisible="false" />
|
||||
android:title="@string/settings_support_installid_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:icon="@drawable/ic_spider_thread_onsurface"
|
||||
android:key="debug.bugreport.automatic.enabled"
|
||||
app:isPreferenceVisible="false"
|
||||
android:summary="@string/settings_debug_autoreports_description"
|
||||
android:title="@string/settings_debug_autoreports_label" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
-->
|
||||
</PreferenceScreen>
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:8.0.2")
|
||||
classpath("com.android.tools.build:gradle:8.1.2")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.core}")
|
||||
classpath("com.google.dagger:hilt-android-gradle-plugin:${Versions.Dagger.core}")
|
||||
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.AndroidX.Navigation.core}")
|
||||
@@ -20,4 +20,4 @@ allprojects {
|
||||
|
||||
tasks.register("clean").configure {
|
||||
delete("build")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
implementation("com.android.tools.build:gradle:8.0.2")
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ fun DependencyHandlerScope.addBaseWorkManager() {
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.addBaseAndroid() {
|
||||
implementation("androidx.core:core-ktx:1.10.0-rc01")
|
||||
implementation("androidx.annotation:annotation:1.4.0")
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.annotation:annotation:1.7.0")
|
||||
implementation("androidx.collection:collection-ktx:1.2.0")
|
||||
implementation("androidx.preference:preference-ktx:1.2.0")
|
||||
}
|
||||
@@ -95,12 +95,12 @@ fun DependencyHandlerScope.addBaseAndroidUi() {
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
|
||||
implementation("androidx.fragment:fragment-ktx:1.4.1")
|
||||
|
||||
implementation("androidx.activity:activity-ktx:1.6.0-rc01")
|
||||
implementation("androidx.fragment:fragment-ktx:1.5.0")
|
||||
implementation("androidx.activity:activity-ktx:1.8.0")
|
||||
implementation("androidx.fragment:fragment-ktx:1.6.1")
|
||||
|
||||
implementation("com.google.android.material:material:1.5.0-rc01")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
|
||||
val lifecycleVers = "2.5.0"
|
||||
val lifecycleVers = "2.6.2"
|
||||
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVers")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycleVers")
|
||||
|
||||
@@ -14,8 +14,8 @@ object ProjectConfig {
|
||||
const val packageName = "eu.darken.capod"
|
||||
|
||||
const val minSdk = 26
|
||||
const val compileSdk = 33
|
||||
const val targetSdk = 33
|
||||
const val compileSdk = 34
|
||||
const val targetSdk = 34
|
||||
|
||||
object Version {
|
||||
val versionProperties = Properties().apply {
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
object Versions {
|
||||
object Gradle {
|
||||
const val buildTools = "7.1.2"
|
||||
}
|
||||
|
||||
object Kotlin {
|
||||
const val core = "1.8.0"
|
||||
const val coroutines = "1.6.2"
|
||||
const val core = "1.9.10"
|
||||
const val coroutines = "1.7.3"
|
||||
}
|
||||
|
||||
object Dokka {
|
||||
@@ -13,7 +9,7 @@ object Versions {
|
||||
}
|
||||
|
||||
object Dagger {
|
||||
const val core = "2.45"
|
||||
const val core = "2.48.1"
|
||||
}
|
||||
|
||||
object Moshi {
|
||||
@@ -24,7 +20,7 @@ object Versions {
|
||||
const val core = ""
|
||||
|
||||
object Navigation {
|
||||
const val core = "2.5.0"
|
||||
const val core = "2.7.3"
|
||||
}
|
||||
|
||||
object Testing {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Bugfixes, performance improvements and maybe new features.
|
||||
¯\_(ツ)_/¯
|
||||
@@ -0,0 +1 @@
|
||||
Support for AirPods Pro 2 with USB-C
|
||||
@@ -0,0 +1,2 @@
|
||||
Bugfixes, performance improvements and maybe new features.
|
||||
¯\_(ツ)_/¯
|
||||
@@ -0,0 +1,2 @@
|
||||
Bugfixes, performance improvements and maybe new features.
|
||||
¯\_(ツ)_/¯
|
||||
@@ -0,0 +1,2 @@
|
||||
Bugfixes, performance improvements and maybe new features.
|
||||
¯\_(ツ)_/¯
|
||||
@@ -0,0 +1,2 @@
|
||||
Bugfixes, performance improvements and maybe new features.
|
||||
¯\_(ツ)_/¯
|
||||
@@ -1,5 +1,2 @@
|
||||
Bugfixes, performance improvements and maybe new features.
|
||||
¯\_(ツ)_/¯
|
||||
|
||||
A detailed changelog is available on GitHub:
|
||||
https://github.com/d4rken-org/capod/releases/latest
|
||||
¯\_(ツ)_/¯
|
||||
@@ -1,4 +1,4 @@
|
||||
O CAPod é um aplicativo complementar para AirPods.
|
||||
CAPod é uma aplicação complementar aos AirPods.
|
||||
|
||||
Recursos:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user